What would the equivalent of a maven reactor be in gradle?


#1

Is there a way to express the maven reactor pattern in Gradle, including creating a build order graph that matches the dependencies declared for each project?

I’m asking because I am getting the impression that the dependencies declared on binary artifacts in a repository do not equate or are not used when it comes to determine the build order in a multi-project gradle build.

The typical example would be where source code is split up into many components aka. gradle projects and you try to create some kind of workspace into which you populate some or all components in source code form. Any that are not present are picked from the binary repository.

At first impression, Gradle appears to do just this. But then when you investigate the build order you notice that it seems to be following an alphanumeric build order, unless you explicitly give it an order.

But given that we are working in with Maven style dependencies then it does not make sense to have to declare the build order twice, once explicitly via dependencies{} and the other via build ordering.

Are we off the mark by missing some detail here or is this something for the future for Gradle?


(sethgoings) #2

Gradle attacks the build order quite naturally through multi project dependencies on other projects. You probably want to investigate: http://www.gradle.org/docs/current/userguide/multi_project_builds.html

Specifically, you can apply dependencies between projects using:

dependencies {
  compile project('api')
}

assuming that you’ve set up your multiproject build environment correctly.

You also mention some things in your question about connecting the ideas of a binary repository and a source repository and having Gradle automatically figure out which one to use based on your workspace/environment. I would love a feature like that, and I believe the core developers are interested in solving this problem too, but I’m not sure where it lies in their list of priorities.


#3

I think your answer is confirming what we have found but I am not sure, so I have to try to elaborate my question a bit more to make sure we have the same understanding.

I’ve read Chapter 50 until my eyes are bleeding and there isn’t anything there as far as I can see that address our particular set of circumstances, which are:

  • we have a binary Ivy repository * we have a large component hierarchy * we express dependencies between components via the binary repository (and in gradle dependencies sections) * we want to create a workspace into which we inject some or all components in source code form * any component not present in the workspace will be picked, as is, from the Ivy repository

Now, the actual source code handling we have already done. That wasn’t the tricky bit, it was rather easy.

The tricky bit is to make Gradle understand that dependencies expressed in each component (gradle sub-project) should be used when creating the build order. Gradle also needs to understand that if we list component X as a dependency in one of these sub-projects and X is cloned into the workspace then obviously ivy:X and gradle-multi-project:X are the same thing.

Naturally we could do some magic to ensure the output from gradle-multi-project:X ends up in the Ivy repository and thus gets reused, but we can’t tell it to build it at the right time.

What I am therefore saying is that I have no capability or want or need to expressly state a build order in the rootProject of Gradle…in fact, without a lot of plugin magic I would not even be able to express it.

I interpret your reply as an indication that this is a missing bit inside Gradle at this time.

It’s a showstopper for us, so unless we can figure this out (pdq) we will have to give Gradle a miss, which would be a pity since it does so much other stuff right!


#4

We plodded on and were able to resolve it on our own.

For anyone else’s benefit this is the snippet of code we used to ensure the build order:

subprojects {

afterEvaluate {

project.configurations.compile.dependencies.each { dep ->

if(new File(rootDir, dep.name).exists())

consumertask.dependsOn “:${dep.name}:producertask”

}

}

}

In this example producertask could eg. be uploadArchives and consumertask could something that unpacks dependencies in the localised build directory.

We are now just down to one remaining obstacle which is to figure out how to work with transitive dependency lists. But that is another story.

So you can mark this one as solved!