From caad92a64fe868a1367c36334d93e8265bbc320f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 1 Jul 2024 11:52:37 +0100 Subject: [PATCH] Apply exclusions earlier to avoid deprecation warning Previously, the dependency management plugin used a before resolve action to apply Maven-style exclusions. Gradle performs configuration resolution in two passes and, despite its name, a before resolve action is called after the first pass. With Gradle 8.8 and later, using a before resolve action to configure the exclusions can result in a deprecation warning. The deprecation warning states that support for mutating the dependency attributes of a configuration after it has been resolved has been deprecated. This commit addresses the deprecation warning by configuring the exclusions earlier, in the withDependencies callback. The callback is called before the first pass of the resolution process, thereby avoiding the warning. Configuring the exclusions at this step prevents the exclusions from being configured on a per-dependency basis so they are now configured on the configuration. Without any additional changes, this regresses the fix for gh-21 as the exclusions are now inherited and cause an exclusion in one configuration where it should apply to leak into another configuration where it should not. To overcome this regression, exclusions are only applied to configurations that can be resolved. Typically, these are configurations like compileClasspath, testRuntimeClasspath and so on, that are leaves and are not extended by other configurations, thereby minimizing the risk of any inheritance-related problems. Closes gh-384 --- .../internal/DependencyManagementApplier.java | 8 ++++---- .../internal/ExclusionConfiguringAction.java | 20 ++++++++----------- ...eVersionCompatibilityIntegrationTests.java | 20 ++++++++++++++++--- ...ldDoesNotProduceDeprecationWarnings.gradle | 19 ++++++++++++++++++ 4 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 src/test/resources/io/spring/gradle/dependencymanagement/GVCIT/buildDoesNotProduceDeprecationWarnings.gradle diff --git a/src/main/java/io/spring/gradle/dependencymanagement/internal/DependencyManagementApplier.java b/src/main/java/io/spring/gradle/dependencymanagement/internal/DependencyManagementApplier.java index 55ca397..23cdd83 100644 --- a/src/main/java/io/spring/gradle/dependencymanagement/internal/DependencyManagementApplier.java +++ b/src/main/java/io/spring/gradle/dependencymanagement/internal/DependencyManagementApplier.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.ResolvableDependencies; +import org.gradle.api.artifacts.DependencySet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -75,11 +75,11 @@ public void execute(Configuration configuration) { .getManagedVersionsForConfiguration(configuration)); VersionConfiguringAction versionConfiguringAction = new VersionConfiguringAction(this.project, this.dependencyManagementContainer, configuration); - configuration.getIncoming().beforeResolve(configureMavenExclusions(configuration, versionConfiguringAction)); + configuration.withDependencies(configureMavenExclusions(configuration, versionConfiguringAction)); versionConfiguringAction.applyTo(configuration); } - private Action configureMavenExclusions(Configuration configuration, + private Action configureMavenExclusions(Configuration configuration, VersionConfiguringAction versionConfiguringAction) { return new ExclusionConfiguringAction(this.dependencyManagementSettings, this.dependencyManagementContainer, this.configurationContainer, configuration, this.exclusionResolver, versionConfiguringAction::applyTo); diff --git a/src/main/java/io/spring/gradle/dependencymanagement/internal/ExclusionConfiguringAction.java b/src/main/java/io/spring/gradle/dependencymanagement/internal/ExclusionConfiguringAction.java index 5b9f5ce..d44e310 100644 --- a/src/main/java/io/spring/gradle/dependencymanagement/internal/ExclusionConfiguringAction.java +++ b/src/main/java/io/spring/gradle/dependencymanagement/internal/ExclusionConfiguringAction.java @@ -29,7 +29,6 @@ import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.DependencyConstraintSet; import org.gradle.api.artifacts.DependencySet; -import org.gradle.api.artifacts.ModuleDependency; import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.artifacts.ResolvableDependencies; import org.gradle.api.artifacts.component.ComponentSelector; @@ -48,7 +47,7 @@ * * @author Andy Wilkinson */ -class ExclusionConfiguringAction implements Action { +class ExclusionConfiguringAction implements Action { private static final Logger logger = LoggerFactory.getLogger(ExclusionConfiguringAction.class); @@ -77,21 +76,18 @@ class ExclusionConfiguringAction implements Action { } @Override - public void execute(ResolvableDependencies resolvableDependencies) { - if (this.configuration.isTransitive() && this.dependencyManagementSettings.isApplyMavenExclusions()) { - applyMavenExclusions(resolvableDependencies); + public void execute(DependencySet dependencySet) { + if (this.configuration.isCanBeResolved() && this.configuration.isTransitive() + && this.dependencyManagementSettings.isApplyMavenExclusions()) { + applyMavenExclusions(dependencySet); } } - private void applyMavenExclusions(ResolvableDependencies resolvableDependencies) { + private void applyMavenExclusions(DependencySet dependencySet) { Set excludedDependencies = findExcludedDependencies(); logger.info("Excluding {}", excludedDependencies); - for (org.gradle.api.artifacts.Dependency dependency : resolvableDependencies.getDependencies()) { - if (dependency instanceof ModuleDependency) { - for (DependencyCandidate excludedDependency : excludedDependencies) { - ((ModuleDependency) dependency).exclude(excludedDependency.asMap()); - } - } + for (DependencyCandidate excludedDependency : excludedDependencies) { + this.configuration.exclude(excludedDependency.asMap()); } } diff --git a/src/test/java/io/spring/gradle/dependencymanagement/GradleVersionCompatibilityIntegrationTests.java b/src/test/java/io/spring/gradle/dependencymanagement/GradleVersionCompatibilityIntegrationTests.java index ca1d343..18bc4cb 100644 --- a/src/test/java/io/spring/gradle/dependencymanagement/GradleVersionCompatibilityIntegrationTests.java +++ b/src/test/java/io/spring/gradle/dependencymanagement/GradleVersionCompatibilityIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package io.spring.gradle.dependencymanagement; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -38,7 +40,7 @@ class GradleVersionCompatibilityIntegrationTests { @RegisterExtension private final GradleBuild gradleBuild = new GradleBuild(); - @ParameterizedTest(name = "Gradle {0}") + @ParameterizedTest(name = "{displayName} (Gradle {0})") @MethodSource("gradleVersions") void pluginIsCompatible(String gradleVersion) { BuildResult result = this.gradleBuild.runner() @@ -48,9 +50,21 @@ void pluginIsCompatible(String gradleVersion) { assertThat(result.task(":resolve").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); } + @ParameterizedTest(name = "{displayName} (Gradle {0})") + @MethodSource("gradleVersions") + void buildDoesNotProduceDeprecationWarnings(String gradleVersion) throws IOException { + File projectDir = this.gradleBuild.runner().getProjectDir(); + File javaSource = new File(projectDir, "src/main/java/com/example/Main.java"); + javaSource.getParentFile().mkdirs(); + javaSource.createNewFile(); + BuildResult result = this.gradleBuild.runner().withGradleVersion(gradleVersion).withArguments("build").build(); + assertThat(result.getOutput()).doesNotContainIgnoringCase("deprecated"); + assertThat(result.task(":build").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + static List gradleVersions() { List versions = Arrays.asList("6.8.3", "6.9.4", "7.0.2", "7.1.1", "7.2", "7.3.3", "7.4.2", "7.5.1", - "8.0.2", "8.1.1", "8.2.1", "8.3", "8.4", "8.5", "8.6", "8.7"); + "8.0.2", "8.1.1", "8.2.1", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8"); List result = new ArrayList<>(); for (String version : versions) { result.add(new String[] { version }); diff --git a/src/test/resources/io/spring/gradle/dependencymanagement/GVCIT/buildDoesNotProduceDeprecationWarnings.gradle b/src/test/resources/io/spring/gradle/dependencymanagement/GVCIT/buildDoesNotProduceDeprecationWarnings.gradle new file mode 100644 index 0000000..28de77c --- /dev/null +++ b/src/test/resources/io/spring/gradle/dependencymanagement/GVCIT/buildDoesNotProduceDeprecationWarnings.gradle @@ -0,0 +1,19 @@ +plugins { + id "java" + id "io.spring.dependency-management" +} + +repositories { + mavenCentral() +} + +dependencyManagement { + imports { + mavenBom 'org.springframework.boot:spring-boot-dependencies:2.7.15' + } +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.keycloak:keycloak-admin-client:25.0.1") +}