Tasks that consume configuration artifact module coordinates and configuration cache

Hello. I’m working on modernizing a fairly large gradle build in Apache Lucene. I can’t figure out how to properly convert one of the tasks to be compatible with configuration cache. Here is the problem:

The task (a forbidden-api checker) currently computes the set of resolved dependency coordinates (group:name) from a given configuration. These are then used to look for forbidden API rules for the given dependency. The code looks roughly like this:

def dynamicSignatures = { configuration ->
  def deps = configuration.resolvedConfiguration.resolvedArtifacts
    .collect { a -> a.moduleVersion.id }
    .collect { id -> "${id.group}-${id.name}" }
    .sort()

  deps.each { dep ->
    def signaturesFile = file("${forbiddenApiRulesDir}/${dep}.txt")
    if (signaturesFile.exists()) {
      signaturesFiles += files(signaturesFile)
    }
  }
}

I’ve been reading the documentation at [1] and this seems relevant:

“In the same vein, if you reference some ResolvedArtifactResult instances, you should instead use ArtifactCollection.getResolvedArtifacts() that returns a Provider<Set<ResolvedArtifactResult>> that can be mapped as an input to your task.”

I’ve declared such a provider in many ways but no matter how I do it, I get an error:

  • Task :foo of type org.gradle.api.DefaultTask: cannot serialize object of type ‘org.gradle.api.internal.artifacts.result.DefaultResolvedArtifactResult’, a subtype of ‘org.gradle.api.artifacts.result.ArtifactResult’, as these are not supported with the configuration cache.

Here is the code I tried:

  var task =
      project
          .getTasks()
          .register(
              "foo",
              t -> {
                Provider<Set<ResolvedArtifactResult>> prov =
                    project
                        .getConfigurations()
                        .named("testCompileClasspath")
                        .flatMap(
                            conf -> {
                              Provider<Set<ResolvedArtifactResult>> resolvedArtifacts =
                                  conf.getIncoming()
                                      .getArtifacts()
                                      .getResolvedArtifacts();
                              return resolvedArtifacts;
                            });

                t.doFirst(
                    (tt) -> {
                      System.out.println(prov.get());
                    });
              });

Could somebody enlighten me and maybe provide a guiding example of how to declare a task that, for a given resolvable configuration, consumes the set of dependencies and transforms them into module-id pairs? Thank you.

[1] Configuration cache

The resolved artifacts would only be the artifacts and iirc you cannot get the coordinates from it.
So making your code work - while possible - is probably not what you want as you do not want to handle the artifacts but the coordinates.
What you want is the part right before your quote, the Provider<ResolvedComponentResult> where you then can get the coordinates from.
So this should be the example you are after: gradle/platforms/software/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/DependencyManagementResultsAsInputsIntegrationTest.groovy at master · gradle/gradle · GitHub

Thank you. This points me in the right direction.

1 Like