Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support flatDir repositories #118

Merged
merged 2 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
Loading