Alex Semin
09/14/2026, 3:36 PMPhilip W
09/14/2026, 4:33 PMBen Liblit
09/14/2026, 11:34 PMPhilip W
09/15/2026, 5:27 AMDavid Gรถransson
09/15/2026, 6:32 AMBrice Dutheil
09/15/2026, 12:21 PMJendrik Johannes
09/16/2026, 6:22 AMysb33r
09/16/2026, 10:08 AM--isolated-projects as an argument of GradleRunner, but you also need to test with Gradle 9.7+ which is another parameter required. In reality one also needs to write a multi-project test scenario which once again is more work.
There is a lot of scaffolding involved. Using GradleTest 5.1.2 (or later) will simplify the scaffolding, but still requires a multi-project test scenario written by the plugin author.ysb33r
09/16/2026, 10:09 AMTim Yates
09/16/2026, 1:16 PMrootProject.getLayout().getProjectDirectory().file("gradle/config/checkstyle/checkstyle.xml")
if we turn on Isolated Projects?Thomas Broyer
09/16/2026, 1:19 PMrootProject.getIsolated().getProjectDirectory().file("โฆ") (or project.getIsolated().getRootProject().โฆ)Jendrik Johannes
09/16/2026, 1:20 PMlayout.settingsDirectory instead since 8.13Tim Yates
09/16/2026, 1:20 PMysb33r
09/16/2026, 1:38 PM${rootDir}/my/path in the Groovy DSL ?
(If that is no longer available it sure would make apply from: a pain to use).ysb33r
09/16/2026, 5:32 PMsettings.gradle. This has an implication for plugin authors.
By example ProjectEvaluationListener : If someone used this in their Project plugin, they now have to move that functionality into a Settings plugin. They then have to tell their users to also apply the new Settings plugin.
If another plugin author, uses the above plugin as a dependency of their plugin, they now either have to create a Settings plugin which also applies the above Settings plugin. They then have to tell their users to apply the new Settings plugin, OR they have to tell them to use the upstream Settings plugin.
This leads to both some confusion for users, and to resistance from plugin authors.Philip W
09/16/2026, 6:47 PMTim Yates
09/17/2026, 1:01 PMJendrik Johannes
09/17/2026, 1:07 PMlistOfAllSubprojectsPaths.forEach { p -> dependencies(testImplementation(project(p))) }
(the in this example testRuntimeClasspath would depends on "join" subprojects)Jendrik Johannes
09/17/2026, 1:14 PMisolated.rootProject.subProjectPaths (this does not exist right now)Jendrik Johannes
09/17/2026, 1:14 PMgradle.lifecycle.beforeProject .
In early Gradle days you would do that via ext . But a better modeling is to:
1. Create an extension (Can be just and interface with a list of strings)
2. Instantiate that in settings
3. register it in all projects via gradle.lifecycle.beforeProject
That's isolated project compatible because you do the common part in settings which always runs before the parallel project configuration.Tim Yates
09/17/2026, 1:21 PMgradle.projectsEvaluated {
val currentProject = project
currentProject.rootProject.subprojects.forEach { otherProject ->
if (otherProject != currentProject) {
val targetConfigs = listOf("api", "implementation", "runtimeOnly")
targetConfigs.forEach { configName ->
otherProject.configurations.findByName(configName)
?.dependencies
?.withType(ExternalModuleDependency::class.java)
?.forEach { extDep ->
currentProject.dependencies.add("testRuntimeOnly", extDep.copy())
}
}
}
}
}
So at test time, the XML module breaks because the runtime external dependencies of the GCS module are present on the testRuntime classpath...Tim Yates
09/17/2026, 1:25 PMJendrik Johannes
09/17/2026, 1:29 PM("api", "implementation", "runtimeOnly") โ form the runtime classpath. So something like this should be similar
listOfAllSubprojectsPaths.forEach { p -> currentProject.dependencies.add("testRuntimeOnly", project(p)) }
The testRuntimeOnly(project(p)) gives you all the runtime dependencies of that project.
Plus that project itself (the Jar) which is the difference you probably do not want.Jendrik Johannes
09/17/2026, 1:32 PM// in all projects:
configurations.consumable("runtimeElementsTransitive") {
extendsFrom(configurations.runtimeElements) // dependencies are inherited, artifact not (I think)
attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named("java-runtime-depenedencies"))
}Tim Yates
09/17/2026, 1:34 PMlistOfAllSubprojectsPaths.forEach can be done in a settings plugin?Jendrik Johannes
09/17/2026, 1:35 PMlistOfAllSubprojectsPaths.forEach { p -> currentProject.dependencies{
testRuntimeOnly(project(p)) {
attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named("java-runtime-depenedencies"))
}
}
I haven't tested this, and there is maybe an easier/more compact way. But the solution would be to do it through dependency resolution somehow.Tim Yates
09/17/2026, 1:47 PMJendrik Johannes
09/17/2026, 1:54 PMlistOfAllSubprojectsPaths.forEach can be done in a settings plugin?
Yes something like this (just tried out in Kotlin code):
interface AllProjectsExtension {
val allProjectPaths: ListProperty<String>
}
let { // this is here because there is weird behavior that top-level variables can't be cached in config cache in Kotlin DSL
val projectPaths = rootProject.children.map { it.path }
gradle.lifecycle.beforeProject {
extensions.create("allProjectPaths", AllProjectsExtension::class).allProjectPaths.addAll(projectPaths)
}
}
Then there is an allProjectPaths extension in all projects to get the paths of all subprojects.Tim Yates
09/21/2026, 7:32 AMinclude), then when applied the plugin finds all non-project runtime dependencies for each project in the list and applied it to the target project's testRuntime classpath ๐
Thanks again for all the help ๐ysb33r
09/21/2026, 7:35 AM