Sebastian Schuberth
05/14/2026, 7:17 AMregisterFeature to work as expected with the distribution plugin. The goal is to create a distribution that contains the functional tests of my app. For each module of my app I have
java {
registerFeature("funTest") {
usingSourceSet(sourceSets["funTest"])
}
}
to register functional tests as a feature. Then in the project that creates the distribution, I have
val Project.hasFunTests
// Do not dig into sourceSets to avoid coupling between projects.
get() = projectDir.resolve("src/funTest").isDirectory
dependencies {
rootProject.subprojects.filter { it.hasFunTests }.forEach {
implementation(project(it.path)) {
capabilities {
// Note that this uses kebab-case although "registerFeature()" uses camelCase, see
// <https://github.com/gradle/gradle/issues/31362>.
@Suppress("UnstableApiUsage")
requireFeature("fun-test")
}
}
}
}
Now, when running the installDist task, there are not only *.jar files in the lib directory as expected, but also a bunch of loose files, like *.class files and resources. Although there already are JARs containing these files as well. Am I doing somethign wrong, or might this be a bug with the experimental registerFeature / usingSourceSet?Philip W
05/14/2026, 7:34 AMSebastian Schuberth
05/14/2026, 7:37 AMPhilip W
05/14/2026, 7:37 AMSebastian Schuberth
05/14/2026, 7:39 AMcapabilities? Or implementation? If you could point me at an example that would be awesome!Sebastian Schuberth
05/14/2026, 8:00 AMval funTestConfiguration by configurations.creating {
attributes {
// Request the 'jar' form of the library
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements::class.java, LibraryElements.JAR)
)
// Request the 'runtime' usage to avoid API/Runtime ambiguity
attribute(
Usage.USAGE_ATTRIBUTE,
objects.named(Usage::class.java, Usage.JAVA_RUNTIME)
)
}
}
I'm getting JARs only, but far too few of them, and none of the funTest JARs. Hmm...Sebastian Schuberth
05/14/2026, 8:15 AMconfigurations.runtimeClasspath {
attributes {
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
objects.named(LibraryElements::class.java, LibraryElements.JAR)
)
}
}
has no effect at all.Vampire
05/14/2026, 12:57 PMimplementation does not use anything, it is not resolvable, but a dependency scope.
runtimeClasspath should already request jars, so that config has no effect and also is not necessary.
Also, you should better not reach into the other project even on filesystem to check whether to depend. Maybe better use normal dependency and then an artifact view that requests the other variant so that projects that miss it are simply ignored?Sebastian Schuberth
05/14/2026, 12:59 PMAlso, you should better not reach into the other project even on filesystem to check whether to depend.True, but I'm trying to solve one problem at a time... unless doing the artifact-view-thing would to help me to get JARs only, not classes.
Sebastian Schuberth
05/14/2026, 1:00 PMruntimeClasspath should already request jars, so that config has no effect and also is not necessary.
I though the effect would be that it requests only JARs, and not also classes anymore.Vampire
05/14/2026, 9:48 PMSebastian Schuberth
05/15/2026, 4:52 PMSebastian Schuberth
05/15/2026, 4:55 PMmain source set, not from the funTest source set. So I'm wondering what makes Gradle copy those files if I'm only requesting the fun-test feature...Sebastian Schuberth
05/15/2026, 5:13 PMtest-fixtures feature (as I also have test fixtures), then only JARs get copied by installDist, as expected.Sebastian Schuberth
05/15/2026, 5:41 PMJavaPluginHelper.getJavaComponent(project) stuff in the former.Sebastian Schuberth
05/15/2026, 5:43 PMtest-fixtures feature.Sebastian Schuberth
05/15/2026, 6:04 PMmain source set.Sebastian Schuberth
05/15/2026, 6:05 PM// Associate the "funTest" compilation with the "main" compilation to be able to access "internal" objects from
// functional tests.
kotlin.target.compilations.apply {
getByName("funTest").associateWith(getByName(KotlinCompilation.MAIN_COMPILATION_NAME))
}
in my code could be the culprit...