Is there a way to express a task dependency of the...
# community-support
m
Is there a way to express a task dependency of the form: "only run if the dependent task is out-to-date"? I.e., I want to run the
composeUp
task for the
avast.gradle.docker-compose
to run first if the
test
task is out-of-date, but it (and the
composeDown
task) should abe skipped if the
test
task is skipped. Context: https://github.com/avast/gradle-docker-compose-plugin/issues/453
Relevant code excerpt from the plugin:
Copy code
@PackageScope
    void isRequiredByCore(Task task, boolean fromConfigure) {
        task.dependsOn upTask
        task.finalizedBy downTask
https://github.com/avast/gradle-docker-compose-plugin/blob/560c9f09bdfd7387511bccf[…]/groovy/com/avast/gradle/dockercompose/TasksConfigurator.groovy
v
Actually, the right thing to use would not be tasks, but an autoclosable shared build service. This is one of its main use-cases.
a
I found a similar issue about dependent tasks not being skipped when their dependent task was run https://github.com/gradle/gradle/issues/34577
I think the purpose of using a task to run
docker compose up
is to make sure it's only run once per build, right? Or would it be acceptable to run it inside a test task's
doFirst {}
action?
I think the best way is to replace the composeUp task with a ValueSource. If you want to be a little risky you could investigate DeploymentHandle. Basically, you tell Gradle 'launch this process and keep it running until the build stops or is cancelled. DeploymentHandle is internal, but KGP uses it so it's unlikely to break soon and might even be made public one day.
v
As I said, the tool at hand for the job is an autocloseable shared build service. When the task is skipped, the shared build service is not triggered. If the task is done, it requests the build service and so the "up" is one and if the service is
AutoCloseable
you do the "down" in the
close
method which will be called between the last task needing the service and the end of the build. So even if multiple tasks need the service it only does its "up" once in the build if needed or not and its "down" once in the build when its appropriate.
The only thing is, that the build service cannot "run a task" so the logic has to be available as normal method, not as task.
m
I'd probably need to preserve the existing task structure to preserve backwards compatibility. E.g., replacing the
composeUp
task with a build service breaks everyone who has a
tasks.named("composeUp")
configuration block.
v
If you are the one providing the compose logic, noone prevents you from providing your logic as task and build service. So legacy users and users who just want to call the up task can use the task, and people updating or starting can use the service to properly up and down around a task only if necessary and not with a wonky
dependsOn
/
finalizedBy
sequence.
👍 1
m
Is there a way to create multiple instances of a shared build service (in the context of a plugin)? Under the old way, for each project where you call
isRequiredBy()
in a
dockerCompose
block, it registers and configures a fresh set of tasks (e.g.,
composeUp
). Which makes sense, as different projects may be using different
docker-compose.yml
files. But here, it sounds like there's a singleton shared build service which is shared across all tasks from all projects.
v
Currently a build service is always scoped to the build execution until maybe https://github.com/gradle/gradle/issues/27756 finally gets considered and implemented. But it is identified by the name you register it under, so you can just use
project.path
within the name of the service to scope it to the project. This also prevents class loader issues when your plugin is applied to individual subprojects without being on a common parent class loader.