torsdag 17. mars 2011

Rethinking automated release management with Gradle and Git.

In the process of migrating several projects to Gradle, I had to find a replacement for the less than optimal Maven Release Plugin. At the moment there is no release plugin in gradle, so I used the opportunity to create one that fitted my needs.

The current Maven release does something like this:

  1. Do a full checkout from svn.
  2. Build the current SNAPSHOT version. 
  3. Update all pom.xml files to the release version. 
  4. Commit and tag.
  5. Update all pom.xml files to the next SNAPSHOT version. 
  6. Checkout the tag.
  7. Build from the tag and upload ALL x number of projects to Nexus.
In a large multi project building twice, checkout twice, pom.xml modifications and uploads takes too much time.
What I really want is something much simpler and as fast as a normal build. 

Deciding what a release really means

A release is just the project at a specific Git commit.
To give the release(commit) a name/version a tag is used. i.e. master-REL-1 for the fist release from master branch.
Artifacts produced by a build should use the tag name as version. The version is not stored in the build script itself, instead it is derived from information from git and the current project state.

Version resolution in a release build
  •  The artifacts in the build will have their version resolved by a git query for the latest release tag + 1.
  •  Create a git tag named from the resolved version.
  •  Finally artifacts are uploaded to nexus. And the tag is pushed.

Version resolution in a normal gradle build
  • If the HEAD of your current branch has a release tag, the tag name will be used. 
  • If your branch is not on a release tag or if the branch contains local modifications, the version is resolved to {branchName}-SNAPSHOT

In my case, having a version number in the snapshots doesn't make any sense.

What to upload to Nexus ?

I believe that Nexus should only contain artifacts you consider publicly available to use in any other project.
In my case this reduces the number of artifacts uploaded from 90 to less than 30.

The point of this blog entry is not to push the use of my plugin, but to illustrate the flexibility gradle gives you to customize and optimize your build. Migrating to gradle has been fun, and here is a list of the most important gains:   

  • Simple customization of the release process.
  • Number of build script configuration lines reduced by a factor of 10.
  • True incremental build support.
  • True multi project support.
  • Project version is only declared once (No parent pom version reference in every sub-project).

Some inspiration for making the migration: (Steve Ebersole documented why he wanted to move hibernate to gradle.)

4 kommentarer:

  1. Nice work, Stian! I have some projects that are now Gradle-based and others that will be migrating from Maven. I've been thinking about, but done zero work, on how to best use Git with Gradle to accomplish the same thing. I'll check out your plugin!

  2. Great work! I really agree with the idea that minimizing the number of artifacts to upload is the best decision in a release process.

  3. I have long struggled with mavens release process in an agile project with Continuous integration. Your approach exactly implements my conclusions for improvement.