Posted by johnsmart
on August 31, 2008 at 9:23 PM PDT
It is an excellent and widely used best practice to tag each of your stable releases in your version control system for future reference. However, this sort of bookkeeping is tedious and error-prone at the best of times. Like many tedious, error-prone tasks, it is one of those things that could do with a bit of automation.
Fortunately, Maven can help. The Maven Release Plugin helps you automate the whole process of upgrading your POM version number and tagging a release version in your version control system. Let's see how it works. Here is an extract from a POM file, showing the version number that uniquely identifies this version:
The SNAPSHOT suffix means that each time I deploy this version, a new snapshot will be deployed into my Maven repository. Anyone who wants to use the latest, bleeding-edge SNAPSHOT version can add a SNAPSHOT dependency in their project. This would usually be myself, or other members of the development team. Snapshots, by definition, tend to be fairly unstable beasts.
As a side-note, the fearless and the reckless can take this a step further by always using the LATEST version, regardless of its actual version number, and regardless of whether it happens to be an official release or just a snapshot:
When the version 1.0.1 is ready, we need to update the POM file, commit the new POM file to version control, tag this version as a release, and then move on to work on version 1.0.2. The Maven Release plugin can automate much of this process. However, before the Maven Release plugin can do its magic, you need to make sure you have everything it needs set up in your POM file.
First of all, you need to be working with a SNAPSHOT release. However, when you are ready to release your new version, you should remove any references to snapshots in your dependencies. This is because a release needs to be stable, and a build using snapshots is, by definition, not always reproducible.
The next thing you need is an block, so that it can find where to create a new release tag and commit the changes. Here is a real-world example:
Next, you need to configure the Release plugin itself. This mainly involves telling Maven where your release tags go, via the "tagBase" configuration element. If you are using the Subversion trunk/tags/branches convention, Maven will automatically put release tags in the "tags" directory. In the following example, we use a slight variation on the normal convention, and place releases in the "tags/releases" directory:
Now you can get down to business, and try out a (semi-)automated release. The first thing you need to do is to make sure all your latest changes have been committed to (in our case) Subversion. If there are any outstanding changes, Maven won't let you do a release. First of all, you need to prepare the release, using the "prepare" goal:
$ mvn release:prepare
This goal will ask you a series of questions to confirm what version number you want to release, what new snapshot version number you want to use, and where you want to place the release tag. If you have set up your POM file correctly, these will have sensible defaults, and you won't have to do much thinking. In fact, you can even disable these questions entierly using the "--batch-mode" command line option.
If you want to know exactly what Maven will do to your POM file and your SCM ahead of time (generally a good idea), you can run the operation in the "dry-run" mode, as shown here:
$ mvn release:prepare -DdryRun=true
This useful trick simulates the SCM operations (by writing them out to the console), and creates two sample pom files that you can consult: pom.xml.tag, which is the pom file that will be committed to Subversion and tagged, and pom.xml.next, which contains the next snapshot version number. Once you are happy with what Maven will do, you can do the real thing:
$ mvn release:clean release:prepare
The "prepare" goal actually does quite a lot. Indeed, it will:
- Make sure that there are no uncommitted changes or SNAPSHOT dependencies (see above)
- Update the SNAPSHOT version number to a release version (e.g. going from "1.0.1-SNAPSHOT" to "1.0.1")
- Update the SCM section of the POM file to point to the release tag rather than the trunk in the Subversion repository
- Run all the application tests to make sure everything still works
- Commit the changes made to the POM file
- Create a new tag in Subversion for this release
- Update the SNAPSHOT version number to a new SNAPSHOT version (e.g. going from "1.0.1" to "1.0.2-SNAPSHOT")
- Commit the changes made to the POM file
Once you're finished, you have your release version tagged in Subversion and you are working on a new SNAPSHOT version.
But wait, a minute, you might say. Didn't we forget to deploy our release somewhere? Well, that is why the goal is called "prepare". We only set everything up in preparation for the release, we haven't actually released anything yet. But dont worry, performing the release is pretty straight-forward, too. Just use "mvn release:perform":
$ mvn release:perform
This will effectively do a "mvn deploy" with the release we have just created. More precisely, it will use the release.properties file generated by the "release:prepare" goal to do the following:
- Check out the release we just tagged
- Build the application (compiling, testing and packaging)
- Deploy the release version to local and remote repositories
Of course, both of these steps are very easy to place on a Hudson server, so that they can be done centrally.
All in all, a very convenient way to automate your release process.
"Best development course I have been on in a very long time...Greatly enjoyed the course...A 'must' course for serious Java developers..." - Read what people are saying about the Java Power Tools Bootcamps.