# Automated Releasing with Maven One of the proofs that the software industry is still immature is how much effort is still duplicated. I've now worked the same job in three very different industries, and while there has been plenty of business-specific stuff, there are some things I've found myself writing again each time: a type-safe [Hibernate](http://www.hibernate.org) query language, a responsive AJAX layer for [Wicket](http://wicket.apache.org), and a release system for [Maven](http://maven.apache.org). I've witnessed more hate for Maven than any other piece of software; in my view this couldn't be more wrong. Simply put, Maven is an *opinionated* build system; it forces your project to bend to meet its expectations, not the other way around. Many users respond by trying to fight Maven, and come out with either hundreds of lines of fragile XML that will break the first time they add another plugin, or give up and go back to ant. I'm not sure I've actually programmed in anything that qualifies as a "bondage and discipline language", but Maven seems to meet the spec. It's wonderful. This program is on a mission to eliminate "snowflake" builds (like [snowflake servers](http://server.dzone.com/articles/martin-fowler-snowflake) - I wish I could find the parody article claiming that devops was destroying years of craftmanship in hand-building servers). And within the Java world it's basically succeeded, meaning I or any vaguely competent Java developer can pick up a new project and *not have to think about* how it's built. Like with code formatting standards, the value is not that Maven's standards are particularly good - more important is that we have a standard and all our projects follow it. With this in mind, the obviously correct way to create stable builds of a project is with Maven's "release" plugin. I feel this is something of a misnomer; in maven, the only way to depend on a specific revision of a module is to make a release of that module. So you should release anything you want to depend on, or any version that other people might want to depend on; if you're following an agile approach I'd say each "story" should be a release. My experience with automated releasing parallels my discovery of git, and realising that I could commit not just every few hours, but every few minutes. At my first job (MX Telecom, now OpenMarket) the version numbers were in the thousands. Releasing at MX was synonymous with deployment; we didn't do full-on continuous deployment to the same extent as e.g. Etsy, but we did deploy several times a day - again, one release corresponded to one agile story, i.e. one customer-facing feature. The release process was a low-tech, but highly effective custom python script. (This was a hallmark of many things at MX - our programming language, database, RPC mechanism and deployment infrastructure were all hopelessly out of date by the standards of the HN crowd, but we used them effectively, kept everything simple, and the results were both technically impressive and highly profitable). Perhaps ironically, despite being "bigger" deployment at last.fm was a far more manual process - I think I only deployed once or twice in my three months there. We were expected to do progressive, "canary" deploys, and there was a much stronger culture of real-time monitoring on our production systems. (That said, MX's monitoring was more than adequate; we achieved a level of reliability far greater than I've seen anywhere else, losing perhaps two messages in close to as many years). In my current job the approach has been slightly different, partly because the product isn't live yet. There are two schools of thought on what this means, both driven by the need to avoid slowing down development with deployment concerns; either releasing isn't important yet, or it's more necessary than ever to be able to release cheaply with minimal manual intervention. By now you'll have guessed that I fall into the latter camp; tempting as it was to produce a similar python script, the allure of something more "standard" was strong. So we now have a sequence of [Jenkins](http://jenkins-ci.org) builds that perform releases on request and nightly; this includes deployment to an automated testing system, but not to live servers. It's not perfect - if nothing else, I would prefer to be following MX's policy of "every change to trunk requires a release" (so that trunk is always guaranteed to be a build that has passed acceptance testing and been deployed to live. That approach is possibly unworkable in an environment where vertically segregated developers work on the same trunk - but that's a whole 'nother post). But it's a start; we've already had situations where we wanted to "go back to that old build that was working" and couldn't. So while it's been a few weeks' work (much of it waiting for a clean trunk, which again could be a post in its own right), I would hope we'll be reaping the rewards soon enough. For anyone else having to implement the same thing, a few protips from my experience (that I'd originally intended to be the content of this post): + Branch ("mvn release:branch") before trying to release. "mvn release:rollback" attempts to "undo" a failed release, but I've not found it to be reliable enough to depend on, and it's harder to automate. With branches, you can simply unconditionally delete the release branch after the attempt (whether successful or not), and there's no possible way for anything in the release process to affect your trunk + In Jenkins you can do this by having two builds - one pointing at trunk that does the branch (with a fixed name), and one pointing at the branch that does the release. I feel slightly uncomfortable about this setup, but it's worked well so far. + Rather than trying to run all your deployment integration tests before doing a release, accept that some releases will be "bad" and design your pipeline to handle this (it's good to have a way to associate a "good or bad" flag with a given release - we've used SVN metadata on the release tag). Remember, a release is nothing more than a set of code that you want to be able to refer to reliably. Make sure that development is allowed to freely control the maven version - don't use it as the "product" version. + If you're trying to do anything even vaguely complicated with overlapping tests in Jenkins, use the [Locks and Latches plugin](http://wiki.hudson-ci.org/display/HUDSON/Locks+and+Latches+plugin) - it seems much more reliable than Jenkins' internal "Block build if an upstream/downstream project is building" options. + There are no nice ways to pass the version number from the maven build to Jenkins. Passing it through a chain of test builds is even harder. If you find a good way to do this, tell the world! [Home](/) <div id="disqus_thread"></div> comments powered by Disqus