diff --git a/src/main/java/com/palantir/gradle/versions/VersionsProps.java b/src/main/java/com/palantir/gradle/versions/VersionsProps.java index 269b5248..04ef1868 100644 --- a/src/main/java/com/palantir/gradle/versions/VersionsProps.java +++ b/src/main/java/com/palantir/gradle/versions/VersionsProps.java @@ -37,10 +37,16 @@ public final class VersionsProps { private final FuzzyPatternResolver fuzzyResolver; private final Map patternToPlatform; - private final Path path; - public VersionsProps(Path path) { - this.path = path; + private VersionsProps(FuzzyPatternResolver fuzzyResolver) { + this.fuzzyResolver = fuzzyResolver; + this.patternToPlatform = Sets + .difference(fuzzyResolver.versions().keySet(), fuzzyResolver.exactMatches()) + .stream() + .collect(Collectors.toMap(key -> key, this::constructPlatform)); + } + + public static VersionsProps loadFromFile(Path path) { Properties recommendations = new Properties(); try (BufferedReader reader = Files.newBufferedReader(path)) { recommendations.load(new EolCommentFilteringReader(new ColonFilteringReader(reader))); @@ -53,16 +59,12 @@ public VersionsProps(Path path) { .forEach(name -> builder.putVersions( name.replaceAll("/", ":"), recommendations.getProperty(name).trim())); - fuzzyResolver = builder.build(); - - patternToPlatform = Sets - .difference(fuzzyResolver.versions().keySet(), fuzzyResolver.exactMatches()) - .stream() - .collect(Collectors.toMap(key -> key, this::constructPlatform)); + return new VersionsProps(builder.build()); } - public Path getPath() { - return path; + /** Construct a trivial {@link VersionsProps} that has no version recommendations. */ + static VersionsProps empty() { + return new VersionsProps(FuzzyPatternResolver.builder().build()); } public Stream constructConstraints(DependencyConstraintHandler handler) { diff --git a/src/main/java/com/palantir/gradle/versions/VersionsPropsPlugin.java b/src/main/java/com/palantir/gradle/versions/VersionsPropsPlugin.java index 9e75f248..978ee789 100644 --- a/src/main/java/com/palantir/gradle/versions/VersionsPropsPlugin.java +++ b/src/main/java/com/palantir/gradle/versions/VersionsPropsPlugin.java @@ -21,7 +21,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; -import java.util.Optional; import org.gradle.api.GradleException; import org.gradle.api.NamedDomainObjectProvider; import org.gradle.api.Plugin; @@ -49,51 +48,55 @@ public class VersionsPropsPlugin implements Plugin { @Override public final void apply(Project project) { - checkPreconditions(project); + checkPreconditions(); + if (project.getRootProject().equals(project)) { + applyToRootProject(project); + } - VersionRecommendationsExtension extension = project.getExtensions() - .create(VersionRecommendationsExtension.EXTENSION, VersionRecommendationsExtension.class, project); + VersionRecommendationsExtension extension = + project.getRootProject().getExtensions().getByType(VersionRecommendationsExtension.class); - Optional versionsProps = computeVersionsProps(project.file("versions.props").toPath()); - if (!versionsProps.isPresent()) { - return; - } + VersionsProps versionsProps = loadVersionsProps(project.getRootProject().file("versions.props").toPath()); + + NamedDomainObjectProvider rootConfiguration = + project.getConfigurations().register(ROOT_CONFIGURATION_NAME, conf -> { + conf.setVisible(false); + }); - project.allprojects(subproject -> { - NamedDomainObjectProvider rootConfiguration = - subproject.getConfigurations().register(ROOT_CONFIGURATION_NAME, conf -> { - conf.setVisible(false); - }); - - subproject.getConfigurations().configureEach(conf -> - setupConfiguration(subproject, extension, rootConfiguration, versionsProps.get(), conf)); - - // Note: don't add constraints to this, only call `create` / `platform` on it. - DependencyConstraintHandler constraintHandler = project.getDependencies().getConstraints(); - rootConfiguration.configure(conf -> - addVersionsPropsConstraints(constraintHandler, conf, versionsProps.get())); - - log.info("Configuring rules to assign *-constraints to platforms in {}", subproject); - subproject.getDependencies() - .getComponents() - .all(component -> tryAssignComponentToPlatform(versionsProps.get(), component)); - - // Gradle 5.1 has a bug whereby a platform dependency whose version comes from a separate constraint end - // up as two separate entries in the resulting POM, making it invalid. - // https://github.com/gradle/gradle/issues/8238 - subproject.getPluginManager().withPlugin("publishing", plugin -> { - PublishingExtension publishingExtension = - subproject.getExtensions().getByType(PublishingExtension.class); - publishingExtension.getPublications().withType(MavenPublication.class, publication -> { - log.info("Fixing pom publication for {}: {}", subproject, publication); - publication.getPom().withXml(xmlProvider -> { - GradleWorkarounds.mergeImportsWithVersions(xmlProvider.asElement()); - }); + project.getConfigurations().configureEach(conf -> + setupConfiguration(project, extension, rootConfiguration, versionsProps, conf)); + + // Note: don't add constraints to this, only call `create` / `platform` on it. + DependencyConstraintHandler constraintHandler = project.getDependencies().getConstraints(); + rootConfiguration.configure(conf -> + addVersionsPropsConstraints(constraintHandler, conf, versionsProps)); + + log.info("Configuring rules to assign *-constraints to platforms in {}", project); + project.getDependencies() + .getComponents() + .all(component -> tryAssignComponentToPlatform(versionsProps, component)); + + // Gradle 5.1 has a bug whereby a platform dependency whose version comes from a separate constraint end + // up as two separate entries in the resulting POM, making it invalid. + // https://github.com/gradle/gradle/issues/8238 + project.getPluginManager().withPlugin("publishing", plugin -> { + PublishingExtension publishingExtension = + project.getExtensions().getByType(PublishingExtension.class); + publishingExtension.getPublications().withType(MavenPublication.class, publication -> { + log.info("Fixing pom publication for {}: {}", project, publication); + publication.getPom().withXml(xmlProvider -> { + GradleWorkarounds.mergeImportsWithVersions(xmlProvider.asElement()); }); }); }); } + private static void applyToRootProject(Project project) { + project.getExtensions() + .create(VersionRecommendationsExtension.EXTENSION, VersionRecommendationsExtension.class, project); + project.subprojects(subproject -> subproject.getPluginManager().apply(VersionsPropsPlugin.class)); + } + private static void setupConfiguration( Project subproject, VersionRecommendationsExtension extension, @@ -185,19 +188,15 @@ private static void addVersionsPropsConstraints( constraints.forEach(conf.getDependencyConstraints()::add); } - private static Optional computeVersionsProps(Path versionsPropsFile) { + private static VersionsProps loadVersionsProps(Path versionsPropsFile) { if (!Files.exists(versionsPropsFile)) { - return Optional.empty(); + return VersionsProps.empty(); } log.info("Configuring constraints from properties file {}", versionsPropsFile); - return Optional.of(new VersionsProps(versionsPropsFile)); + return VersionsProps.loadFromFile(versionsPropsFile); } - private static void checkPreconditions(Project project) { - if (!project.getRootProject().equals(project)) { - throw new GradleException("Must be applied only to root project"); - } - + private static void checkPreconditions() { Preconditions.checkState( GradleVersion.current().compareTo(MINIMUM_GRADLE_VERSION) >= 0, "This plugin requires gradle >= %s", diff --git a/src/test/groovy/com/palantir/gradle/versions/VersionsPropsPluginIntegrationSpec.groovy b/src/test/groovy/com/palantir/gradle/versions/VersionsPropsPluginIntegrationSpec.groovy index 3e050ff5..7aa35575 100644 --- a/src/test/groovy/com/palantir/gradle/versions/VersionsPropsPluginIntegrationSpec.groovy +++ b/src/test/groovy/com/palantir/gradle/versions/VersionsPropsPluginIntegrationSpec.groovy @@ -202,7 +202,22 @@ class VersionsPropsPluginIntegrationSpec extends IntegrationSpec { def e = runTasksAndFail() e.output.contains("Not allowed to resolve") } -/** + + def "creates rootConfiguration even if versions props file missing"() { + buildFile << """ + dependencies { + constraints { + rootConfiguration 'org.slf4j:slf4j-api:1.7.25' + } + } + """.stripIndent() + file('versions.props').delete() + + expect: + runTasks() + } + + /** * Recursively converts a node's children to a map of (tag name): (value inside tag). *

* See: https://stackoverflow.com/a/26889997/274699