Thursday, January 8, 2015

Gradle Multi-Project structure

I am using a combination of Gradle, Github and Bintray for Krail ... probably a popular combination.

I originally had a single Github repository with a Gradle multi-project setup for a number of libraries.

I had been thinking of breaking out some of the libraries anyway, but Bintray really needs a Github repository per library, so with some regret, I broke up the multi-project into single projects.  The regret was because I thought I needed a directory hierarchy to support a Gradle multi-project.

Now I didn't really want to maintain several build files, all very similar, and just as I expected, a pain to keep up to date.

So I went back to the excellent Gradle documentation looking for inspiration, but it still took a while to work out what I needed to do.

I read the Multi-Project Java build and Multi-Build Projects sections again, but still couldn't find an answer to making the build work across a flat directory structure, with the root project at the same directory level as its subprojects.

Eventually I stumbled on the answers, and they are in the documentation - just that I didn't find them the easy way.  So if you are Gradle, Github and Bintray together, for a multi-project build, this is what you need:

Settings.gradle

In the settings.gradle file, which must be in your root project directory, you define your sub-projects with include statements ... but you are not limited to a hierarchical structure.  You can code any structure you like (coding in a settings file is a bit unusual, too).  Ironically, the first example I found was in the Gradle repository on Github (not in the structure I wanted, but it demonstrates the feature).

My own example looks like this:


include 'krail'include 'krail-jpa'include 'krail-demo'include 'krail-testApp'include 
'krail-testUtil'include 'krail-quartz'include 'krail-bench'include 'q3c-testUtil'


rootProject.children.each {project ->

 String fileBaseName = project.name String projectDirName = '../'+fileBaseName
 project.projectDir = new File(projectDirName)

// for example, makes it krail.gradle project.buildFileName = "${fileBaseName}.gradle"

//make sure it exists assert project.projectDir.isDirectory()
 assert project.buildFile.isFile()
}

All this does is map each of the sub-projects at the same directory level as the root project - it also points to *.gradle files which are named the same as their projects (so krail-jpa.gradle for the krail-jpa project).  This is to avoid having multiple "build.gradle" files in the IDE, which can be confusing.

Now this almost worked, except I couldn't run the sub-projects from their own directories, I had to call grade from the root project directory.

There must be a master

This time I did find the answer in the documentation, but in the Build Lifecycle section, when I was looking for something else!

....if you execute Gradle from within a project with no settings.gradle file, Gradle looks for a settings.gradle file in the following way:
  • It looks in a directory called master which has the same nesting level as the current dir.
  • If not found yet, it searches parent directories.
  • If not found yet, the build is executed as a single project build.
  • If a settings.gradle file is found, Gradle checks if the current project is part of the multiproject hierarchy defined in the found settings.gradle file. If not, the build is executed as a single project build. Otherwise a multiproject build is executed.

For my scenario, all I needed to do was to rename my root project directory as master ... and now I can execute tasks sub-projects from their own directories.

No comments:

Post a Comment