DevOps Zone is brought to you in partnership with:

By day I'm a build and release engineer in London, but by night I'm a normal person! If anyone ever asks me what I do, I usually generarlise and say "I'm in I.T." and then check to see if they've already stopped listening. When I'm not working or blogging I can be found playing rugby or cycling around the countryside on my bike, in an attempt to keep fit and fool myself into thinking I'm still young. James is a DZone MVB and is not an employee of DZone and has posted 53 posts at DZone. You can read more from them at their website. View Full User Profile

Maven Release Plugin and Continuous Delivery

07.07.2011
| 11870 views |
  • submit to reddit

I was setting up a Continuous Delivery system using Maven as the build tool, Perforce as the SCM and Go (ThoughtWorks’ CI system). All was going perfectly well until I got to the point when I no longer wanted to make snapshot builds…

The idea behind my Continuous Delivery system was this:

  • Every check-in runs a load of unit tests
  • If they pass it runs a load of acceptance tests
  • If they pass we run more tests – Integration, scenario and performance tests
  • If they all pass we run a bunch of static analysis and produce pretty reports and eventually deploy the candidate to a “Release Candidate” repository where QA and other like-minded people can look at it, prod it, and eventually give it a seal of approval.


As you can see, there’s no room for the notion of “snapshot” and “release” builds being separate here. Every build is a potential release build. So, a few days ago I went right ahead and used the maven release plugin, and that was the last time I remember smiling, having fun, getting a full night’s sleep, and my brain not hurting.

The problem is this: the maven release plugin doesn’t really work for continuous delivery. And what’s more, it REALLY doesn’t work with Go and Perforce. I’ll start with the Go/Perforce issues: I got loads of errors thanks to the way Go runs as the system user, and creates its own clientspecs. The results of this debacle are detailed here and here.

I managed to finally get around the clientspec/P4/Go problems with some help from my colleague Toby Catlin who bears the scars of similar skirmishes with Go and Perforce from days gone by. The “fix” was to create a perforce config file and an “uber” client spec. The perforce config file specified the uber clientspec and it lived in the root of the project directory. It was hardly a satisfactory workaround, as it meant that every project would need to have this file, and the uber clientspec would need to be updated every time a new build job was created. But never mind that, it was just a relief to see the builds going green for a change.

And that’s when it happened… the release build completed. The maven release plugin increased the version number in the pom and checked it in. And then Go detected the change in the pom and checked it out again and started building again. This then updated the version number and checked it in, which in turn got detected and kicked off another build CAN YOU SEE THE GLARINGLY OBVIOUS PROBLEM HERE????

It’s obvious really. I’ve always made my maven release builds a manual process in the past and that was exactly why, I’d just forgotten all about it. So, I’ve decided not to use the maven release plugin at all. Every build now just creates a “release” build because I’ve removed all instances of the word SNAPSHOT from the poms. If they pass all their tests and look good enough, they’re automatically promoted to the release candidate repository. And everyone’s happy. Also, I’ve added a property to the builds which pulls in a variable from the Go system, and if that’s not present the “deploy to release candidate repository” step fails – this is to stop developers from manually creating releases – all release builds must come from the CI system.

References
Published at DZone with permission of James Betteley, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Adam Leggett replied on Thu, 2011/07/07 - 9:55am

Never tried maven release plugin with perforce or go, so unable to feel your pain on this. Usually, I only ever create release CI jobs using Maven that
  • Require someone to log in to the CI Server (usually Hudson/Jenkins) and run the build, typically parameterised with something (like a JIRA id for example) or
  • Only run it as a scheduled job. It will likely build forever if you are polling for SCM changes...
For a belt an braces approach I'll typically use something like the locks-and-latches plugin to prevent my 'commit' jobs running in parallel once Maven SCM has performed the requisite bumping and commiting of new pom versions. These commit builds publish SNAPSHOT versions of course (usually to Artifactory along with successful releases).

Fabrizio Giudici replied on Thu, 2011/07/07 - 10:58am

"The problem is this: the maven release plugin doesn’t really work for continuous delivery."

Well, yes. It's right, but this is quite obvious, as the fact that you can't use a hammer as a screwdriver ;-) The maven-release-plugin is strictly related to the concept of working with snapshots and extracting a release every in a while (maybe even many times in the day, but always starting with a snapshot).

If you don't have the concept of "snapshot" you should just not use maven-release-plugin. BTW, what would do for you? :)

Loren Kratzke replied on Thu, 2011/07/07 - 1:47pm

To each his own, but I don't get the benefit of continuous "delivery" and especially don't see any advantage in every build being a possible release. It seems that you are really going against the grain of what Maven is all about in order to make your other tools and your extreme process happy. But if it works for you then cool.

FYI: The simplest and most effective setup I know is Maven/Nexus/Hudson with SVN on the drum kit. This stuff is all free and works well. I have no idea why anybody would choose to pay money for anything else. Since it is free, I encourage you to dust off that old box in the server room and create a test setup. You will not be disappointed.

Mladen Girazovski replied on Fri, 2011/07/08 - 9:53am

As you can see, there’s no room for the notion of “snapshot” and “release” builds being separate here. 

 I don't see your point, of course a snapshot is different from a release.

RC Candidates are always releases in Maven btw.

The problem is this: the maven release plugin doesn’t really work for continuous delivery.

 Again, i don't see our point. A fabrizio already stated, you've abandoned the snapshot/release conecpt of Maven (this distinction an important part of the maven dependency mechanism btw., messing with it without understanding it will cause nasty surprises sooner or later, especially in complex multimodule projects) which has consequences, this is not dirctly releated to the release plugin itself  but rather an effect of the way yoo used it.

The thing that you could have problems with is that the maven release plugin is based on the idea to "create a release before releasing it", projects like Eclipse do it the other way around, a "snapshot" gets released (no distinction) and is eventually "promoted" afterwards.

James Betteley replied on Mon, 2011/07/11 - 11:19am in response to: Mladen Girazovski

What I'm trying to achieve is a system where a release build is made every time a check in is made. The "only" thing that the builds must do in order to be considered "release candidates" is pass all the tests (unit, acceptance, performance etc and so on). This can take a long time, but that's not a problem since the builds are broken down into manageable feedback loops.

 Because I want every build to potentially be a release buil, I cannot class commit builds as snapshot builds. Likewise, I cannot use the maven release plugin, because it will check in the pom at the end and therefore start another build - creating a continually building loop :-(

I have settled on not using the release plugin, which is a pity because I liked some of the features. Anyway, my solution is to neither use the release plugin nor use the word SNAPSHOT in my builds: http://jamesbetteley.wordpress.com/2011/07/07/what-is-in-a-name-usually-a-version-number-actually/

Thanks!

Loren Kratzke replied on Tue, 2011/07/19 - 6:44pm in response to: James Betteley

Again, I am unclear what benefit "continuous delivery" offers, in fact I would like to debate it sometime. It is with great restraint that I don't tear into it like a pitbull in a barrel of porkchops right now because clearly you are outside of the 99% that do things another way. You must have a good reason. I just don't know what it could be.

I wonder if you actually keep 77,000 builds around and then decide to release build number 76,287 because it passed all tests and has good performance, or if you just use The Force to determine that "yup, this next build is the one!". My WTF meter is totally pegged out of curiosity right now.

Oliver Schmitz replied on Wed, 2011/12/07 - 12:24pm

James, it would be interesting to know, if and how you solved that issue, because we are currently working on the same topic.

We use teamcity instead of go, which allows to define rules, that prevent the triggers to fire due to the commits done by the maven release plugin, thus only real user commits will trigger a build. We currently use that with the release polugin on our so called Testing branch, where we fix issues, before the release goes live. That is, we are currently on a weekly release cycle and fix criticle bugs in a branch before we push to production. Here we have a around 5 to 10 commits in a week, where updating all the poms (multimodule project with around 120 modules) is not a problem

 Another thing that we just implemented is to remember a last know good build. That is a build that managed to sucessfully run through a chains similar to the one described by you (unit, deployment, integration, smoketests). Here we use the tagging functionality of teamcity, that allows to tag the version which was processed after all buildsteps are done successfully with a tag (actually a branch) on our subversion server. After that, we trigger a release:prepare release:perform run to check releasability and prepare a release canditate. This will happen on the branch previously created without changing the trunk. To prepare the branch we run a small shell script, that fixes the scm info in the pom files.As long as we still need a release version (instead of using the svn revision nr) we determine the next release version not from the pom version, but from a subversion tag. like RELEASE-108.0.0. Automatically created branches will than follow the scheme RELEASE-108.0.<svn revision>. To find the 108, we do a svn list and search for the lates RELEASE-<###>-0.0 Tag. In the trunk all poms have the version TRUNK-SNAPSHOT. This is a little bit ugly, as it disables the release functionality of maven, but it works fine for us.

What we do to promote a release is, we create a new marker tag for the next target release version,  ship the last known good released version, and rename the branch we finally took to show the Release number. 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.