I'm having difficulties getting the `registerFeatu...
# community-support
s
I'm having difficulties getting the
registerFeature
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
Copy code
java {
    registerFeature("funTest") {
        usingSourceSet(sourceSets["funTest"])
    }
}
to register functional tests as a feature. Then in the project that creates the distribution, I have
Copy code
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
?
p
You have to specify the attributes if you don't want to use the local classes variant that implementation is using by default. Or better, create a new resolvable configuration.
s
Hmm, where would I need to make those changes? In the place I register the feature, or in the place where I request the feature?
p
In your distribution project
s
Ok, and where would I specify those attributes, somewhere inside
capabilities
? Or
implementation
? If you could point me at an example that would be awesome!
With something like
Copy code
val 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...
On the other hand, something like
Copy code
configurations.runtimeClasspath {
    attributes {
        attribute(
            LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
            objects.named(LibraryElements::class.java, LibraryElements.JAR)
        )
    }
}
has no effect at all.
v
implementation
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?
s
Also, 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.
>
runtimeClasspath
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.
v
You just configured what is already configured, so it is a no-op. Why you get classes I'd have to try out, but I'm on vacation without computer available.
s
Enjoy your vacation ☺️
The interesting thing is, that the resources being copied stem fro the
main
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...
Also, when (just for the fun of it) requesting the
test-fixtures
feature (as I also have test fixtures), then only JARs get copied by
installDist
, as expected.
I'm now comparing how the test-fixtures plugin creates its feature vs. how `usingSourceSet() create the feature. The only apparent difference I can see is the additional
JavaPluginHelper.getJavaComponent(project)
stuff in the former.
Ha, I wonder whether I'm basically running into https://github.com/gradle/gradle/issues/10872, but for my own feature instead of the
test-fixtures
feature.
Then again, that bug is different in that it duplicated classes from the feature. But I'm seeing duplicate classes from the
main
source set.
I wonder whether
Copy code
// 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...