My project has an :individuals subproject with a custom SourceSet named testData, compiled via the corresponding JavaCompile task named compileTestDataJava. A second subproject, :aggregate, has a Jar task named testDataJar that should include all bytecode files produced by the :individuals:compileTestDataJava task.
plugins { java }
val testData by sourceSets.creating {}
val provide by
configurations.creating {
isCanBeConsumed = true
isCanBeResolved = false
}
artifacts { add(provide.name, tasks.named("compileTestDataJava")) }
aggregate/build.gradle.kts
plugins { java }
val consume by
configurations.creating {
isCanBeConsumed = false
isCanBeResolved = true
}
dependencies { consume(project(mapOf("path" to ":individuals", "configuration" to "provide"))) }
tasks.register<Jar>("testDataJar") {
group = "build"
archiveBaseName.set("testData")
from(consume)
}
Unfortunately, this approach fails when trying to create the :individuals:assemble task:
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':individuals:build'.
> Could not create task ':individuals:assemble'.
> Expected task 'compileTestDataJava' output files to contain exactly one file, however, it contains more than one file.
I changed the artifacts block to use just the single destinationDirectory of the JavaCompile task:
This approach runs without failure, but the generated aggregate.jar archive contains no bytecode files, just a bare-bones META-INF/MANIFEST.MF.
What is the right way for a subproject to create a consumable configuration containing the multiple bytecode files created by a JavaCompile task, and then to consume that configuration in some other subproject?
The complete project is a code analysis tool. The testData classes truly are test data, not test-supporting fixtures. The byte code files produced by compileTestDataJava should not even be added to the class path when running tests. Thus, the java-test-fixtures plugin is not a suitable solution.
If you really want to add the single files, iirc you have to iterate through the files and add each as single artifact or something like that. You could probably look at the java-library plugin that adds the classes secondary variant.
Other than that, you could add the jar as artifact to your configuration and then unpack them on the consumer side if you need them unpacked.
You can also have a look at the java-test-fixtures plugin and add a feature variant like it does it for your use-case.
Other than that, you could add the jar as artifact to your configuration and then unpack them on the consumer side if you need them unpacked.
I like the simplicity of this idea, and I don’t mind putting things into a jar just to copy them out again later. Nice. Thank you for this suggestion!
On the consuming side, I tried using the configuration to create a zipTree in the obvious way:
val consume by
configurations.creating {
isCanBeConsumed = false
isCanBeResolved = true
}
...
tasks.register<Jar>("testDataJar") {
group = "build"
archiveBaseName.set("testData")
from(zipTree(consume)) { include("**/*.class") }
}
Sadly, this approach fails:
Execution failed for task ':aggregate:testDataJar'.
> Cannot fingerprint input file property 'rootSpec$1$1': Cannot convert the provided notation to a File or URI: configuration ':aggregate:consume'.
The following types/formats are supported:
- A String or CharSequence path, for example 'src/main/java' or '/usr/include'.
- A String or CharSequence URI, for example 'file:/usr/include'.
- A File instance.
- A Path instance.
- A Directory instance.
- A RegularFile instance.
- A URI or URL instance.
- A TextResource instance.
Everything works if I explicitly extract the configuration’s single file, and also add the inputs.files dependency explicitly:
However, this feels inelegant. Is there a more concise approach that gets all of its dependencies from from without needing help from an explicit inputs.files?
The elegant way would be an atrifact transform that unpacks that zips, that way you then again get it unpacked from the configuration already and it would also work if you declare multiple such dependencies on one configuration: Transforming dependency artifacts on resolution