Subproject depends on configuration from other subproject, but subproject build order doesn't respect that


(davidmichaelkarr) #1

I asked this as an addendum to another question, but I figured I should post this separately, as it’s really a different issue.

I have a multiproject build with three subprojects. Two of them build WARs, and the third builds a Docker image using the two WARs. The third project (called “ordersImage”) depends on the created WAR files in this way:
dependencies { runtime project(path: ":ordersService", configuration: "war") runtime project(path: ":ordersGUI", configuration: "war") runtime "oracle:ojdbc6:11.2.0.3" }

This looks fine, and if I MANUALLY build the “ordersService” and “ordersGUI” projects, and then build “ordersImage”, it works fine.

However, if I first clean everything and build from the top level, Gradle builds the “ordersGUI” project, then the “ordersImage” project. It might aftwards build the “ordersService” project, but the “ordersImage” build fails because it can’t find the “ordersService.war” artifact.

The problem is, it’s building the projects in the wrong order. It needs to build “ordersGUI” and “ordersService” first (no order dependency between them), and then “ordersImage”.

I would have thought that by having “ordersImage” depend on the “war” configuration in both “ordersService” and “ordersGUI”, then Gradle would know to build those two before building “ordersImage”. Am I misunderstanding how Gradle determines subproject build order?


(Chris Doré) #2

What do the ordersService and/or the ordersGUI build files look like? Or perhaps a link to your other question if it already contains that information?


(davidmichaelkarr) #3

The other conversation is on How to depend on WAR file built by project, not the jar file? , but Mark V is still replying on that thread with my essential change of subject, so perhaps I’ll get it resolved there.

However, that thread doesn’t really talk about the structure of the two WAR build files, as they’re pretty simple, but both of them now have the following so I can depend on the “war” configuration from another project:
`configurations {
war {}
}

artifacts {
war tasks.war
}`


(Stefan Oehme) #4

Please keep in mind that Gradle runs a task graph, not a project graph. Whatever task requires those dependencies needs to declare them as an input, otherwise they won’t be built. I can’t tell from the example above what you are trying to do. Could you maybe create a small reproducible example on GitHub?


(davidmichaelkarr) #5

I’ve managed to resolve this, or at least gotten something that works the way I expect. The other thread also has the conclusion to this, but basically I have a “copyDependencies” task in the “ordersImage” project that depends on the two WAR files being built, so I changed the “copyDependencies” task header to this:

task copyDependencies(dependsOn: [":ordersService:build", ":ordersGUI:build"]) << {

I believe the implication is that it depends on the “war” task, but that feels to me like unnecessary coupling into the build structure of those projects, so I prefer to depend on the overall build of the project instead of a specific task.


(Stefan Oehme) #6

This is not the way to do it. It creates too much coupling and does way too much.

You need to declare the configuration as an input to the task.

task doStuffWithRuntimeDeps() {
 inputs.files configurations.runtime
 doLast {
  //do stuff
 }
}

How to copy dependencies so Gradle can possibly report "UP TO DATE"?
(davidmichaelkarr) #7

Ah, good. This is what Mark referred to in a related thread as “the configuration containing that artifact should be an input to that task.”, and I didn’t quite understand that.

This is a bit cleaner.