Multi-project build design question


(barrybecker4) #1

I have a question about the optimal design for a gradle java project that involves several dependent projects. Currently I have multi-project gradle build in a single repository. The structure of it is something like the following. There are actually more modules, but this is enough to describe the problem.

core - common code puzzles - different puzzle applications simulations - different simulation applications webdeployment - packages puzzles and simulation jars together with html and jnlp files and deploys them to my website.

The dependency structure looks like a diamond. Puzzles and simulations depend on core, while webdeployment depends on puzzles and simulation. This design works fine for the primary use case of

(1) Treating them like 4 closely related projects and checking out everything from a single repository. Changes in one project are immediately available in the others (as handled by gradle subproject dependencies).

There are two other use cases I want to consider, however, and I don’t think this approach is well suited to it.

(2) Someone just wants to work on puzzles (or simulations) and nothing else. They would like to checkout just the puzzles (or puzzles and core) sub-projects and work on them without having to check out all other projects.

(3) Someone else would like to depend on my core jar, but they do not want to add their project to this existing set because they do not care about puzzles or simulations.

These two use cases make me think that I may want to separate these 4 sub-projects into separate top-level projects and put them in separate repositories. I want to do this without making the original mode of working (where I checkout everything) more cumbersome. So far, I don’t know how to do that.

If everything is a separate project, the following is how I think it will work. Please suggest improvements to this proposal. I wish there was a Gradle example for something like this.

Make core, puzzles, simulations, webdeployment separately versioned gradle projects checked into separate repositories. When core, puzzles, or simulations, is built, versioned jars will be uploaded into a central repository. Below is how this design will support each of my 3 use cases. (2) and (3) are now well supported, but (1) becomes awkward. I’m wondering if there is a better alternative.

(1) This case gets significantly more cumbersome. Instead of just getting everything from a single repository and changing any part of the source and building without needing to modify any build file, the process will be like this:

a) create a maven central account so jars can be uploaded to it. Only need to do this once.

b) check out all modules that need to be modified. Potentially from 4 different repositories.

c) modify source in one or more separate projects.

d) update version number of upstream modules and in dependency sections of gradle files of dependent projects.

e) build projects in specific dependency order (core, puzzles, simulations, …). Each module uploads jars to a central repository and downloads dependencies from the same place.

(2) Checkout puzzles (or simulations) only from revision control. When it builds, it will automatically pull the appropriate versioned core jar from a central repository. If it requires a change to core, then core needs to be checked out separately, changed and a new version uploaded. Puzzles build.gradle file then needs to be updated to require the new version of the core jar.

It would be nice if core and puzzles could be checked out into the same folder such that when puzzles builds, it could look first to see if the core project exists and use that as a dependency. If its not there, then retrieve the versioned jar from the central repository. The problem with this is that I don’t think its possible to have a compile project(’:core’) dependency specified if that dependency is not guaranteed to be there.

(3) This case is easy with the separate project design. The third party simply adds compile ‘bb4:core:1.x’ to build.gradle and the dependent core jar is automatically retrieved at build time.

What is the best gradle design so that all 3 use cases will still be convenient? This must be a fairly typical situation. thanks, Barry


(Peter Niederwieser) #2

There is no silver bullet. Going with separate source control repositories and builds means more effort. If the projects have the same release cycle, I recommend to have them share the same repository/build.

To share artifacts between builds at development time, you’d declare a local Maven or Ivy repository. You can use ‘-SNAPSHOT’ (Maven) or ‘.latest’ (Ivy) version numbers to avoid the need to increase the version number.

There are plans to support ad-hoc aggegration of builds, but I can’t say when this will be implemented.