When I run `./gradlew check` on a root project of ...
# community-support
s
When I run
./gradlew check
on a root project of a multi-project build, it will run the
check
task of all projects. How do I create a Gradle task that runs this? Is something like this correct (Kotlin syntax) or are there pitfalls? Should I use a provider in
dependsOn
?
Copy code
tasks.register("myCheck") {
    dependsOn(allprojects.mapNotNull { it.tasks.findByPath("check") })
}
m
you don't have to create such a task, that's standard behavior
if you run
./gradlew foo
, it will execute the
foo
task on all projects which define it
if you run
./gradlew :foo
it will only execute it on the root project
s
I know, that's what I said in my first sentence. But as a second step I will need to filter the projects whose tasks are run.
m
so just declare a task called
myCheck
in all projects
reaching out to other project's tasks is not recommended behavior and will fail at some point
s
What will the accepted solution be at some point when I want to check only certain projects?
e.g. only projects that have a certain plugin NOT applied?
m
Copy code
val myCheck = tasks.register("myCheck") {

}
pluginManager.withPlugin("should-disable-checks") { myCheck.configure { enabled = false }
s
okay I guess I'll do this once the non-recommended way stops working
m
you should really avoid the non-recommended way. It's not reliable and will forcefully configure tasks
do it the right way from day 1
s
yes but doesn't
./gradlew check
also forcefully configure tasks? it has to figure out which projects have the task and which don't, after all.
v
Even though such cross-project model access still works, as Cédric said it is highly recommended you don't use it. It will disturb some more sophisticated Gradle features and optimizations. And it also will only work if those projects were configured already and thus got that task added already. If you know that the task you want to depend on exists in all projects that you want to depend on, you can do for example
Copy code
tasks.register("myCheck") {
    allprojects.filterNot { it.path == ":notInThisProject" }.forEach { dependsOn("${it.path}:check") }
}
or
Copy code
tasks.register("myCheck") {
    dependsOn(":inThis:check")
    dependsOn(":andAlsoThis:check")
}
as the project path is already known at that time and by using the string-y dependsOn, it is evaluated late and without cross-project model access.
s
I have subprojects that use a particular tool. Running tests with this tool is slow so I want to create a separate task to run a subset of checks, only of those projects that don’t use the tool. I don’t want to maintain a list of such projects (because I’m in the process of adding new subprojects) but rather recognize them by them not having a certain tool-specific plugin applied. It seems to work based on my experiments (I did throw in a
provider
to make it a bit lazier, just to be sure), and my understanding is that using
allprojects
, especially in a provider, is not doing any more work or causing any more initialization/evaluation/configuration compared to
./gradlew check
. Am I wrong? Which optimizations would it disturb, compared to
./gradlew check
?
v
Accessing the model of another project, no matter whether you change something or read something is always a bad idea and should be avoided. Just registering the task in the projects where you want to have them like Cédric suggested is probably a better idea if you want to control it from the projects. Doing something not if some plugin is not applied is not really a supported use-case as you can never really know when all plugins that are going to be applied will be applied, except when configuration phase is over, but then you cannot change configuration anymore, so reacting to the plugin being applied and disabling the task would also be a good idea. Alternatively, you could also just invent some project property so that you can do
./gradlew check -P onlyFastTests=true
and then accordingly enable / disable tasks as necessary. Disabling
check
for example would be pointless, as
check
is a lifecycle task that anyway in almost all cases does not have own actions anyway and disabling a task does not disable its dependency tasks, so you probably instead need to disable
test
or whatever you want to not run.
s
Thanks, this makes sense.
👌 1