I have a complicated build which requires one task graph which downloads an artifact, unzips it, explodes a war inside of the zip distro, then executes an arbitrary JavaExec task to create one artifact:
Unfortunately, the task graph optimizes, and the order of execution is wrong… :projecta:download :projecta:unzip :projecta:explode :projecta:noconsole <— undesirable :projectb:stage
:projectb:noconsole
How can I set up a build which allows me have the noconsole tasks in both projecta and projectb, but the one in projectb relies on inserting projectb:noconsole BEFORE projecta:noconsole executes?
I can’t quite follow your question. Which exact order do you want to see, and which task are you executing in this case? Right now you have declared that :projectb:noconsole depends on :projecta:noconsole, so the former cannot possibly be executed before the latter.
Hi Peter, sorry for the lack of clarity in the original question. There is a typo, the last line should have read “… inserting :projectb:stage BEFORE :projecta:noconsole …”
Due to the order of elements in the dependsOn list, the order of execution I expected was:
:projecta:download
:projecta:unzip
:projecta:explode
:projectb:stage
:projecta:noconsole
:projectb:noconsole
The code that is generating the task Graph pulls all of the projecta elements up before projectb, even though :projectb:stage does not rely on :projecta:noconsole.
My original thought was to just manually call :projecta:noconsole as the last action of :projectb:noconsole, but I was unable to find anything in the API or DSL that suggested such a thing was possible (or wise). That’s why I tried to get inside of the dependsOn hierarchy.
I’m also open to hearing an alternate approach to the problem. I’ve been staring at this too long and may have lost perspective on the right way to solve the problem.
To get the desired behavior, you could weave in :projectb:stage conditionally in the case :projectb:noconsole is to be executed. The earliest you can tell reliably is gradle.taskGraph.whenReady {}, but unfortunately you can’t add further task dependencies at this point.
In some cases it’s good enough to check gradle.startParameter.taskNames to find out whether a task is going to be executed, but for that you’d have to at least give “:projectb:noconsole” a unique task name (say “:projectb:noconsoleb”). Then you could do:
if (gradle.startParameter.taskNames.contains("noconsoleb")) {
project(":projecta").noconsole.dependsOn(stage)
stage.dependsOn(project(":projecta").explode)
}
However this will only work for the case where :projectb:noconsoleb is executed directly. I expect Gradle to offer a more complete solution in the future.
The other options is to rethink the bigger picture. Why do you need this behavior? Is there a different way to model it?
Thanks, Peter. I was not aware of stage.dependsOn(). I’ll try it out later and see if that can accomplish what I need. In terms of modeling it a different way, there very well could be a better way, but I haven’t thought of it yet.