Groovy => Kotlin - taskProvider dependsOn type problem

Hi,

at the moment I do have a groovy task which does fetch a task list from the subprojects via a provider:


tasks.register("dependencyCheckDelegate") {
	dependsOn(
		provider {
			// can't use named here because there is no new API equivalent for the findByName call
			// see https://docs.gradle.org/current/userguide/task_configuration_avoidance.html
                        subprojects.tasks.collect({ task -> task.findByName("checkDependencies") }).findAll { it }
		},
}

I am trying to convert that to Kotlin but the type check already fails at the “subproject.tasks” because of a type mismatch.

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val TaskContainer. tasks: TaskProvider<TaskReportTask> defined in org. gradle. kotlin.dsl

Did groovy something nice here for me or … what is more likely … I do miss the obvious thing here while trying to write that in Kotlin, anyone an idea? Thanks.

The “goal” of that one is, that I have a global task, which depends on possible existing ones on the submodules, which may or may not exist - hence “findByName” because “named” would fail here.

Replying to myself:

tasks.register("dependencyCheckDelegate") {
    dependsOn(
        provider {
            // can't use named here because there is no new API equivalent for the findByName call
            // see https://docs.gradle.org/current/userguide/task_configuration_avoidance.html
            val theTasks = mutableListOf<Any?>()
            subprojects.forEach {
                val task = it.tasks.findByName("checkDependencies")
                if (task != null) {
                    theTasks += task
                }
            }
            theTasks
        },
    )
}

does work - although I am not sure if it is the best solution here.

Neither the Groovy nor the Kotlin version is the “best” solution, or actually a viable solution, but something you should never ever ever even think about trying to do.

Reaching into the model of other projects is a very bad idea.

Why do you need such a task anyway?
If you do ./gradlew checkDependencies it does exactly what you want already, running a task with that name in all projects that happen to have a task with that name. No synthetic bad-practice delegate task is needed for that.

That was my first idea too, but I do have a task in a compiled script plugin which depends on that “dependencyCheckDelegate” which is a collection of that subtasks which other plugins are going to register.

How would I tell that dependsOn(…) that it should call “checkDependencies” on all the subprojects - if I do, it just tells me that checkDependencies is unknown.

tasks.register("preReleaseCheck") {
    dependsOn(tasks.named("dependencyCheckDelegate"))
    doLast { .... }
}

You cannot do that programmatically.
You would need to ensure that all involved projects have a task with that name and then depend on the task in all those projects, or make the project publish an artifact (and if it is a dummy artifact) that is configured to be built by that task and then depend on that configuration in all projects. In the latter case you could for example also use an artifact view which should ignore if not all projects have such an outgoing configuration, …
How to properly do it highly depends on the exact and gory details.
But reaching into another project’s model, be it for cross-configuration or for getting information from it, is highly discouraged, immediately creates project coupling, and thus works bluntly against some more sophisticated Gradle features and optimizations. And latest when isolated projects become stable and you want to benefit from the performance boost, it is not possible anymore.

1 Like

I had an idea you would tell me that, but your last point is convincing, so I am going to delegate that to the process and not to the build system itself. Thanks.

1 Like