Skip to content

Commit

Permalink
Support flatDir repositories (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
RobiNino authored Jul 10, 2024
1 parent 8d25f55 commit 1551a67
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 41 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ exeport BITESTS_ARTIFACTORY_VIRTUAL_REPO='some-virtual-repo'

- The above command run both unit and integration tests.

### Debugging the tests/plugin with the following command:
### Debugging the plugin with the following command:

```
./gradlew aP -Dorg.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class TestConsts {
public static final Path GRADLE_EXAMPLE_PUBLISH = PROJECTS_ROOT.resolve("gradle-example-publish");
public static final Path GRADLE_KTS_EXAMPLE_PUBLISH = PROJECTS_ROOT.resolve("gradle-kts-example-publish");
public static final Path GRADLE_EXAMPLE_CI_SERVER = PROJECTS_ROOT.resolve("gradle-example-ci-server");
public static final Path GRADLE_EXAMPLE_CI_SERVER_FLAT = PROJECTS_ROOT.resolve("gradle-example-ci-server-flat");
public static final Path GRADLE_EXAMPLE_CI_SERVER_ARCHIVES = PROJECTS_ROOT.resolve("gradle-example-ci-server-archives");
public static final Path GRADLE_EXAMPLE_VERSION_CATALOG_PRODUCER = PROJECTS_ROOT.resolve("gradle-example-version-catalog").resolve("producer");
public static final Path GRADLE_EXAMPLE_VERSION_CATALOG_CONSUMER = PROJECTS_ROOT.resolve("gradle-example-version-catalog").resolve("consumer");
Expand Down Expand Up @@ -125,4 +126,10 @@ public class TestConsts {
"org/example/gradle/publishing/gradle_tests_space/1.0.0/gradle_tests_space-1.0.0.module",
"org/example/gradle/publishing/gradle_tests_space/1.0.0/gradle_tests_space-1.0.0.pom"
};

public static final String[] EXPECTED_FLAT_DIR_DEPENDENCIES_IDS = {
":tests-local-project-dependency:",
"junit:junit:4.12",
"org.hamcrest:hamcrest-core:1.3"
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,12 @@ public void versionCatalogTest(String gradleVersion) throws IOException {
(buildResult, deployableArtifacts) -> ValidationUtils.checkVersionCatalogResults(artifactoryManager, buildResult, virtualRepo)
);
}

@Test(dataProvider = "gradleVersions")
public void ciServerFlatDirTest(String gradleVersion) throws IOException {
runPublishCITest(gradleVersion, TestConsts.GRADLE_EXAMPLE_CI_SERVER_FLAT, false,
(deployableArtifacts) -> Utils.generateBuildInfoProperties(this, "", false, false, ""),
(buildResult, deployableArtifacts) -> ValidationUtils.checkBuildResultsFlatDir(buildResult, TestConsts.BUILD_INFO_JSON.toFile())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@
import java.util.Set;

import static org.apache.commons.lang3.StringUtils.*;
import static org.gradle.testkit.runner.TaskOutcome.FAILED;
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
import static org.jfrog.build.extractor.BuildInfoExtractorUtils.jsonStringToBuildInfo;
import static org.jfrog.build.extractor.clientConfiguration.deploy.DeployableArtifactsUtils.loadDeployableArtifactsFromFile;
import static org.jfrog.gradle.plugin.artifactory.Constant.*;
import static org.jfrog.gradle.plugin.artifactory.TestConsts.ARTIFACTS_GROUP_ID;
import static org.jfrog.gradle.plugin.artifactory.TestConsts.EXPECTED_VERSION_CATALOG_CONSUMER_ARTIFACTS;
import static org.jfrog.gradle.plugin.artifactory.TestConsts.*;
import static org.testng.Assert.*;
import static org.testng.Assert.assertTrue;

public class ValidationUtils {
public interface BuildResultValidation {
Expand Down Expand Up @@ -329,4 +327,24 @@ public static void checkBomBuild(BuildResult buildResult, File buildInfoJson, in
.anyMatch(artifactName -> artifactName.equals("gradle_tests_space-1.0-SNAPSHOT.pom")));
}

/**
* Check the results of CI server with flatDir test.
* Aim of the test is to verify flatDir repositories are still respected when applying the Artifactory plugin which shouldn't override them.
*
* @param buildResult - The build results
* @param buildInfoJson - Path to the unpublished build info json.
* @throws IOException In case of any IO error.
*/
public static void checkBuildResultsFlatDir(BuildResult buildResult, File buildInfoJson) throws IOException {
// Assert all tasks ended with success outcome
buildResult.getTasks().forEach(buildTask -> assertNotEquals(buildTask.getOutcome(), FAILED));

// Assert build info contains both the remote and the local dependencies.
assertTrue(buildInfoJson.exists());
BuildInfo buildInfo = jsonStringToBuildInfo(CommonUtils.readByCharset(buildInfoJson, StandardCharsets.UTF_8));
assertEquals(buildInfo.getModules().size(), 1);
assertEquals(buildInfo.getModules().get(0).getDependencies().size(), 3);
String[] dependenciesIds = buildInfo.getModules().get(0).getDependencies().stream().map(Dependency::getId).toArray(String[]::new);
assertEqualsNoOrder(dependenciesIds, EXPECTED_FLAT_DIR_DEPENDENCIES_IDS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
plugins {
id 'java'
}

repositories {
maven {
url "should-override-me"
credentials {
password "should-override-me"
}
}
flatDir {
dirs './tests-local-project-dependency/build/libs'
}
}

dependencies {
implementation ':tests-local-project-dependency:'
implementation 'junit:junit:4.12'
}

// Source compatibility
sourceCompatibility = '1.8'

// Target compatibility
targetCompatibility = '1.8'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.gradle;

import org.gradle.Child;
import org.junit.Assert;

public class Consumer {
public static void main() {
Assert.assertTrue(Child.isChild());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apply plugin: 'java'

jar {
archiveFileName.set('tests-local-project-dependency.jar')
destinationDirectory.set(file("$buildDir/libs"))
}

sourceCompatibility = '1.8'
targetCompatibility = '1.8'
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.gradle;

public class Child {
public static boolean isChild() {
return true;
}}
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,25 @@
import org.apache.commons.lang3.StringUtils;
import org.gradle.api.Plugin;
import org.gradle.api.initialization.Settings;
import org.gradle.api.initialization.resolve.RepositoriesMode;
import org.gradle.api.logging.Logging;
import org.jfrog.build.api.util.Log;
import org.jfrog.build.extractor.BuildInfoExtractorUtils;
import org.jfrog.build.extractor.clientConfiguration.ArtifactoryClientConfiguration;
import org.jfrog.gradle.plugin.artifactory.utils.GradleClientLogger;

import java.util.Properties;
import org.jfrog.gradle.plugin.artifactory.utils.PluginUtils;

@SuppressWarnings("unused")
public class ArtifactoryPluginSettings implements Plugin<Settings> {
private static final Log log = new GradleClientLogger(Logging.getLogger(ArtifactoryPluginSettings.class));

@Override
public void apply(Settings settings) {
ArtifactoryClientConfiguration.ResolverHandler resolver = getResolverHandler();
ArtifactoryClientConfiguration.ResolverHandler resolver = PluginUtils.getResolverHandler(log);
if (resolver == null || StringUtils.isAnyBlank(resolver.getContextUrl(), resolver.getRepoKey())) {
// If there's no configured Artifactory URL or repository, there's no need to include the resolution repository
return;
}
String contextUrl = StringUtils.appendIfMissing(resolver.getContextUrl(), "/");
settings.getDependencyResolutionManagement().getRepositoriesMode().set(RepositoriesMode.PREFER_SETTINGS);
settings.getDependencyResolutionManagement().getRepositories().maven(mavenArtifactRepository -> {
mavenArtifactRepository.setName("artifactoryResolutionRepository");
mavenArtifactRepository.setUrl(contextUrl + resolver.getRepoKey());

// Set credentials if provided
String username = resolver.getUsername();
String password = resolver.getPassword();
if (StringUtils.isNoneBlank(username, password)) {
mavenArtifactRepository.credentials((credentials) -> {
credentials.setUsername(username);
credentials.setPassword(password);
});
}
});
}

/**
* Extract the resolver information from the build-info.properties file generated by the JFrog CLI or by the
* Jenkins Artifactory plugin.
*
* @return resolver handler.
*/
private ArtifactoryClientConfiguration.ResolverHandler getResolverHandler() {
Properties allProps = BuildInfoExtractorUtils.mergePropertiesWithSystemAndPropertyFile(new Properties(), log);
ArtifactoryClientConfiguration configuration = new ArtifactoryClientConfiguration(log);
configuration.fillFromProperties(allProps);
return configuration.resolver;
// Add the Artifactory resolution repository.
settings.getDependencyResolutionManagement().getRepositories().maven(mavenArtifactRepository -> PluginUtils.addArtifactoryResolutionRepositoryAction(mavenArtifactRepository, contextUrl, resolver));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
import org.gradle.StartParameter;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
import org.gradle.api.invocation.Gradle;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.publish.PublishingExtension;
import org.jfrog.build.api.util.Log;
import org.jfrog.build.extractor.clientConfiguration.ArtifactoryClientConfiguration;
import org.jfrog.gradle.plugin.artifactory.Constant;
import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention;
import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask;
import org.jfrog.gradle.plugin.artifactory.utils.ExtensionsUtils;
import org.jfrog.gradle.plugin.artifactory.utils.ProjectUtils;
import org.jfrog.gradle.plugin.artifactory.utils.PublicationUtils;
import org.jfrog.gradle.plugin.artifactory.utils.*;

import java.util.Collections;
import java.util.Set;
Expand All @@ -31,6 +32,7 @@
*/
public class ProjectsEvaluatedBuildListener {
private static final Logger log = Logging.getLogger(ProjectsEvaluatedBuildListener.class);
private static final Log clientLog = new GradleClientLogger(log);
private final Set<Task> detailsCollectingTasks = Collections.newSetFromMap(new ConcurrentHashMap<>());

/**
Expand Down Expand Up @@ -92,6 +94,28 @@ public void afterEvaluate(Project project) {
evaluate(collectDeployDetailsTask);
}
});
addResolverIfConfigured(project);
}

/**
* Adds an Artifactory resolution repository to the project's repository configuration if configured.
* Overrides other remote repositories by removing all existing Maven and Ivy remote repositories from the project.
*
* @param project The Gradle project to which the Artifactory resolution repository is to be added.
*/
private void addResolverIfConfigured(Project project) {
ArtifactoryClientConfiguration.ResolverHandler resolver = PluginUtils.getResolverHandler(clientLog);
if (resolver == null || StringUtils.isAnyBlank(resolver.getContextUrl(), resolver.getRepoKey())) {
// If there's no configured Artifactory URL or repository, there's no need to include the resolution repository
return;
}
String contextUrl = StringUtils.appendIfMissing(resolver.getContextUrl(), "/");

// Remove all remote repositories in order to override with the Artifactory resolution repository.
project.getRepositories().removeIf(repo -> repo instanceof MavenArtifactRepository || repo instanceof IvyArtifactRepository);

// Add the Artifactory resolution repository.
project.getRepositories().maven(mavenArtifactRepository -> PluginUtils.addArtifactoryResolutionRepositoryAction(mavenArtifactRepository, contextUrl, resolver));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

import org.apache.commons.lang3.StringUtils;
import org.gradle.api.GradleException;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
import org.gradle.api.invocation.Gradle;
import org.jfrog.build.api.builder.ModuleType;
import org.jfrog.build.api.util.Log;
import org.jfrog.build.client.Version;
import org.jfrog.build.extractor.BuildInfoExtractorUtils;
import org.jfrog.build.extractor.clientConfiguration.ArtifactoryClientConfiguration;
import org.jfrog.gradle.plugin.artifactory.Constant;

import java.util.Arrays;
import java.util.Properties;

public class PluginUtils {

Expand Down Expand Up @@ -40,4 +45,41 @@ public static ModuleType getModuleType(String moduleType) {
throw new GradleException("moduleType can only be one of " + Arrays.toString(ModuleType.values()), illegalArgumentException);
}
}

/**
* Adds an Artifactory resolution repository to a given MavenArtifactRepository.
* This method configures the repository's name and URL based on the provided context URL and resolver information.
* If credentials (username and password) are provided in the resolver, they are set for the repository.
*
* @param mavenArtifactRepository The MavenArtifactRepository to configure.
* @param contextUrl The base URL for the Artifactory instance.
* @param resolver The resolver handler containing the repository key and optional credentials.
*/
public static void addArtifactoryResolutionRepositoryAction(MavenArtifactRepository mavenArtifactRepository, String contextUrl, ArtifactoryClientConfiguration.ResolverHandler resolver) {
mavenArtifactRepository.setName("artifactoryResolutionRepository");
mavenArtifactRepository.setUrl(contextUrl + resolver.getRepoKey());

// Set credentials if provided
String username = resolver.getUsername();
String password = resolver.getPassword();
if (StringUtils.isNoneBlank(username, password)) {
mavenArtifactRepository.credentials((credentials) -> {
credentials.setUsername(username);
credentials.setPassword(password);
});
}
}

/**
* Extract the resolver information from the build-info.properties file generated by the JFrog CLI or by the
* Jenkins Artifactory plugin.
*
* @return resolver handler.
*/
public static ArtifactoryClientConfiguration.ResolverHandler getResolverHandler(Log log) {
Properties allProps = BuildInfoExtractorUtils.mergePropertiesWithSystemAndPropertyFile(new Properties(), log);
ArtifactoryClientConfiguration configuration = new ArtifactoryClientConfiguration(log);
configuration.fillFromProperties(allProps);
return configuration.resolver;
}
}

0 comments on commit 1551a67

Please sign in to comment.