From 63f7134bbcf0706c5fd19912fddc21c732b34881 Mon Sep 17 00:00:00 2001 From: Rene Groeschke Date: Mon, 23 Jun 2025 15:45:54 +0200 Subject: [PATCH] [Build] Make DependenciesInfoPlugin configuration cache compatible (#129791) We can now run projects check tasks and :distribution:generateDependenciesReport with configuration cache enabled (--configuration-cache) --- .../internal/DependenciesInfoPlugin.java | 17 ++- .../gradle/internal/DependenciesInfoTask.java | 117 ++++++++++-------- 2 files changed, 72 insertions(+), 62 deletions(-) diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoPlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoPlugin.java index f687c342e2e5a..669d1b5078dab 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoPlugin.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoPlugin.java @@ -10,7 +10,6 @@ package org.elasticsearch.gradle.internal; import org.elasticsearch.gradle.dependencies.CompileOnlyResolvePlugin; -import org.elasticsearch.gradle.internal.precommit.DependencyLicensesTask; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; @@ -28,14 +27,14 @@ public void apply(final Project project) { var depsInfo = project.getTasks().register("dependenciesInfo", DependenciesInfoTask.class); depsInfo.configure(t -> { - t.setRuntimeConfiguration(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - t.setCompileOnlyConfiguration( - project.getConfigurations().getByName(CompileOnlyResolvePlugin.RESOLVEABLE_COMPILE_ONLY_CONFIGURATION_NAME) - ); - t.getConventionMapping().map("mappings", () -> { - var depLic = project.getTasks().named("dependencyLicenses", DependencyLicensesTask.class); - return depLic.get().getMappings(); - }); + var runtimeConfiguration = project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); + t.getRuntimeArtifacts().set(project.getProviders().provider(() -> runtimeConfiguration.getIncoming().getArtifacts())); + t.getClasspath().from(runtimeConfiguration); + var compileOnlyConfiguration = project.getConfigurations() + .getByName(CompileOnlyResolvePlugin.RESOLVEABLE_COMPILE_ONLY_CONFIGURATION_NAME); + t.getCompileOnlyArtifacts().set(project.getProviders().provider(() -> compileOnlyConfiguration.getIncoming().getArtifacts())); + t.getClasspath().from(compileOnlyConfiguration); + }); Configuration dependenciesInfoFilesConfiguration = project.getConfigurations().create("dependenciesInfoFiles"); dependenciesInfoFilesConfiguration.setCanBeResolved(false); diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoTask.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoTask.java index 3ccae89139a12..180c1308d07be 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoTask.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/DependenciesInfoTask.java @@ -11,19 +11,22 @@ import org.elasticsearch.gradle.internal.precommit.DependencyLicensesTask; import org.elasticsearch.gradle.internal.precommit.LicenseAnalyzer; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.DependencySet; -import org.gradle.api.artifacts.ModuleVersionIdentifier; +import org.gradle.api.artifacts.ArtifactCollection; import org.gradle.api.artifacts.ProjectDependency; +import org.gradle.api.artifacts.component.ModuleComponentIdentifier; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.ProjectLayout; import org.gradle.api.internal.ConventionTask; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; import org.gradle.api.provider.ProviderFactory; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputDirectory; import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; @@ -34,6 +37,7 @@ import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -51,31 +55,58 @@ *
  • license: SPDX license identifier, custom license or UNKNOWN.
  • * */ -public class DependenciesInfoTask extends ConventionTask { +public abstract class DependenciesInfoTask extends ConventionTask { - private final DirectoryProperty licensesDir; + @Inject + public abstract ProviderFactory getProviderFactory(); - @OutputFile - private File outputFile; + /** + * We have to use ArtifactCollection instead of ResolvedArtifactResult here as we're running + * into a an issue in Gradle: https://github.com/gradle/gradle/issues/27582 + */ - private LinkedHashMap mappings; + @Internal + abstract Property getRuntimeArtifacts(); - public Configuration getRuntimeConfiguration() { - return runtimeConfiguration; + @Input + public Provider> getRuntimeModules() { + return mapToModuleComponentIdentifiers(getRuntimeArtifacts().get()); } - public void setRuntimeConfiguration(Configuration runtimeConfiguration) { - this.runtimeConfiguration = runtimeConfiguration; - } + @Internal + abstract Property getCompileOnlyArtifacts(); - public Configuration getCompileOnlyConfiguration() { - return compileOnlyConfiguration; + @Input + public Provider> getCompileOnlyModules() { + return mapToModuleComponentIdentifiers(getCompileOnlyArtifacts().get()); } - public void setCompileOnlyConfiguration(Configuration compileOnlyConfiguration) { - this.compileOnlyConfiguration = compileOnlyConfiguration; + /** + * We need to track file inputs here from the configurations we inspect to ensure we dont miss any + * artifact transforms that might be applied and fail due to missing task dependency to jar + * generating tasks. + * */ + @InputFiles + abstract ConfigurableFileCollection getClasspath(); + + private Provider> mapToModuleComponentIdentifiers(ArtifactCollection artifacts) { + return getProviderFactory().provider( + () -> artifacts.getArtifacts() + .stream() + .map(r -> r.getId()) + .filter(id -> id instanceof ModuleComponentIdentifier) + .map(id -> (ModuleComponentIdentifier) id) + .collect(Collectors.toSet()) + ); } + private final DirectoryProperty licensesDir; + + @OutputFile + private File outputFile; + + private LinkedHashMap mappings; + /** * Directory to read license files */ @@ -102,17 +133,6 @@ public void setOutputFile(File outputFile) { this.outputFile = outputFile; } - /** - * Dependencies to gather information from. - */ - @InputFiles - private Configuration runtimeConfiguration; - /** - * We subtract compile-only dependencies. - */ - @InputFiles - private Configuration compileOnlyConfiguration; - @Inject public DependenciesInfoTask(ProjectLayout projectLayout, ObjectFactory objectFactory, ProviderFactory providerFactory) { this.licensesDir = objectFactory.directoryProperty(); @@ -123,22 +143,18 @@ public DependenciesInfoTask(ProjectLayout projectLayout, ObjectFactory objectFac @TaskAction public void generateDependenciesInfo() throws IOException { - final DependencySet runtimeDependencies = runtimeConfiguration.getAllDependencies(); - // we have to resolve the transitive dependencies and create a group:artifactId:version map - - final Set compileOnlyArtifacts = compileOnlyConfiguration.getResolvedConfiguration() - .getResolvedArtifacts() - .stream() - .map(r -> { - ModuleVersionIdentifier id = r.getModuleVersion().getId(); - return id.getGroup() + ":" + id.getName() + ":" + id.getVersion(); - }) - .collect(Collectors.toSet()); + final Set compileOnlyIds = getCompileOnlyModules().map( + set -> set.stream() + .map(id -> id.getModuleIdentifier().getGroup() + ":" + id.getModuleIdentifier().getName() + ":" + id.getVersion()) + .collect(Collectors.toSet()) + ).get(); final StringBuilder output = new StringBuilder(); - for (final Dependency dep : runtimeDependencies) { + Map mappings = getMappings().get(); + for (final ModuleComponentIdentifier dep : getRuntimeModules().get()) { // we do not need compile-only dependencies here - if (compileOnlyArtifacts.contains(dep.getGroup() + ":" + dep.getName() + ":" + dep.getVersion())) { + String moduleName = dep.getModuleIdentifier().getName(); + if (compileOnlyIds.contains(dep.getGroup() + ":" + moduleName + ":" + dep.getVersion())) { continue; } @@ -147,25 +163,20 @@ public void generateDependenciesInfo() throws IOException { continue; } - final String url = createURL(dep.getGroup(), dep.getName(), dep.getVersion()); - final String dependencyName = DependencyLicensesTask.getDependencyName(getMappings(), dep.getName()); - getLogger().info("mapped dependency " + dep.getGroup() + ":" + dep.getName() + " to " + dependencyName + " for license info"); + final String url = createURL(dep.getGroup(), moduleName, dep.getVersion()); + final String dependencyName = DependencyLicensesTask.getDependencyName(mappings, moduleName); + getLogger().info("mapped dependency " + dep.getGroup() + ":" + moduleName + " to " + dependencyName + " for license info"); final String licenseType = getLicenseType(dep.getGroup(), dependencyName); - output.append(dep.getGroup() + ":" + dep.getName() + "," + dep.getVersion() + "," + url + "," + licenseType + "\n"); + output.append(dep.getGroup() + ":" + moduleName + "," + dep.getVersion() + "," + url + "," + licenseType + "\n"); } Files.write(outputFile.toPath(), output.toString().getBytes("UTF-8"), StandardOpenOption.CREATE); } @Input - public LinkedHashMap getMappings() { - return mappings; - } - - public void setMappings(LinkedHashMap mappings) { - this.mappings = mappings; - } + @Optional + public abstract MapProperty getMappings(); /** * Create an URL on Maven Central