Maven release plugin

Properly versioning and releasing code can be fiddly if it’s done properly. If you’re not cutting corners, the process involves several steps. If these steps are performed manually the process is error prone and time consuming. I’ve often found it’s easier just to cut a few corners. Why change the version in the Maven pom when you could perform all releases against a single SNAPSHOT version? Why tag the release build when you could probably work out the release version from a Subversion log? Why put release artifacts in a release repo when you can rebuild from a historic version?

I’m not going to argue that you shouldn’t cut corners when creating a release build (all the same, just don’t!). I will argue that the process need not be fiddly. So long as a Maven project is correctly set up, the whole thing can be done with a single command. Wire that single command up to Hudson, Jenkins, CruiseControl or whatever and you can create properly versioned release builds in a single click or (if you’re so inclined) as a scheduled task.

At the heart of this is the powerful – though slightly inflexible – maven release plugin.

Maven Release Plugin

The Maven Release Plugin will perform the following actions necessary to create a versioned release (some steps omitted – check Maven documentation for full details):

  1. Update the version number of your project (and subprojects) in the pom file(s) to a full release number (remove SNAPSHOT suffix)
  2. Run project test suite
  3. Commit updated POM(s) to SCM
  4. Create a release tag in SCM
  5. Update the version number of your project (and subprojects) in the pom files(s) to next SNAPSHOT number
  6. Commit updated POM(s) to SCM
  7. Checkout release tag from SCM
  8. Build and deploy released code

Obviously, if you’re doing this sort of process manually it will take a while. The above steps are done by Maven using two goals – release:prepare and release:perform. These goals can be run interactively allowing the build user full control over new version numbers, SCM tags and so on. They can also be run together non-interactively which is more suited to integration with a CI tool.

Setting up the project

As you may expect from Maven’s Convention over Configuration ethos, your project and release procedure must be set up The Maven Way or not at all. The project must be set up with the following in order for the plugin to work effectively:

Version Number

The project version number must follow Maven conventions. Development should be done in a SNAPSHOT version and releases will have the minor version incremented by default. The version of all sub-modules should be the same as the version of the parent pom and all sub-modules should be released together.

My parent pom contains the following config:

This version will be changed to 1.2 on release and then 1.3-SNAPSHOT immediately following release.

SCM – Software Configuration Management

The project should use a compatible SCM and the <scm> element should be defined in the pom. Maven supports a number of SCMs. I use Subversion and I’ve configured my pom as follows:

Tests

The release plugin will run unit tests by default. Any test fails will prevent the release.

Dependencies

Software should not be released with SNAPSHOT dependencies so the release will fail if any SNAPSHOT dependencies exist in the pom.

Distribution Management

The release plugin will attempt to deploy the built artifacts so the <dependencyManagement> element must exist in the pom. This should point to a repository manager if you have one. I just want my artifacts deployed to a local file system so I’ve defined my distribution management as follows:

Executing the plugin

It’s easiest to run the two main goals of the plugin interactively from the command line.

Dry run

This will make all necessary changes to the poms but not actually check in anything to SCM or deploy artifacts. This is useful to check that the plugin does what you think it does.

Prepare release

Leaving out the dryRun property will perform all preparation steps for your release. This includes updating the pom to a new version number, creating a tag in SCM, updating the pom to the next SNAPSHOT and checking in all pom changes to SCM. The plugin will prompt you for the version numbers and SCM tag name to use but it will offer sensible defaults.

The username and password here is for the SCM system. They could be defined in the server section of your settings.xml rather than on the command line. This would allow password encryption if you’re into that sort of thing.

The release:prepare goal will check in two changes to the trunk. It will update the pom with the release version number and then update again with the next development SNAPSHOT version number:

Subversion log showing version number changes

It will also create a new tag corresponding to the release:

Subversion repo browser showing release tag

Perform release

This will actually build the release prepared in the previous step. A fresh copy of source code will be checked out from the newly created SCM tag, built and deployed to the location defined in <distributionManagement>

Batch mode – non-interactive

It may be more useful to execute the plugin non-interactively. For example if it’s to be run from a CI tool such as Jenkins. The -B or –batch-mode switch will do this. All values usually picked up interactively will be picked up from command line or from a release.properties file. If none are found, the default values will be used.

I’ve assumed here that the SCM username and password is picked up from settings.xml rather than command line.

References

20 Comments

  • fjd
    October 4, 2012 - 6:47 am | Permalink

    This is a nice concise description of how to make it work, but i would like to to have a global place to place the distributionManagement without having to rifle through all my pom’s to place the same information again and again. Is there a way to use the maven release plugin without the distributionManagement element in the pom’s can i put it in the settings.xml ?

    • October 4, 2012 - 7:06 pm | Permalink

      The settings.xml doesn’t include a distrubutionManagement section and that probably makes sense. The settings.xml contains settings for all Maven projects you’re working on whereas the distributionManagement setting is specific to each project. If you’re working on two different projects that belong in different repos, a per-user distributionManagement section would not work.

      If you have multiple (related) projects that all belong in the same repo, you probably want to define a ‘super’ (corporate) pom that contains all common settings such as artifact, plugin and distribution repos. All your other poms could inherit from that using the parent element. http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Project_Inheritance

  • fjd
    October 5, 2012 - 4:42 am | Permalink

    Thanks we have thought about that but some of our projects are still in svn and newer projects are in github.

    thanks for the suggestion.
    fjd

  • Michael
    October 26, 2012 - 11:33 am | Permalink

    Perhaps “Properly versioning and releasing code can be fiddly if it’s done properly.” should read: “Properly versioning and releasing code can be fiddly if it’s not done properly.”…just a thought. Good blog, btw.

    • October 31, 2012 - 7:35 pm | Permalink

      Michael: What I meant by doing it ‘properly’ was making sure that you do all the steps that you’re ‘supposed’ to: updating POMs with new version numbers, creating SCM tags and so on. If you’re doing this ‘properly’ but by hand, it sure is fiddly. Then again, if you’re doing all this by hand, you’re right, that’s not really doing it properly at all.

  • Pingback: Migrating from SVN to Git « Don't Panic!

  • Despot
    July 15, 2013 - 9:33 am | Permalink

    “…and releases will have the minor version incremented by default.”
    Releases will have the fix version incremented by default.
    Maven-release-plugin doesn’t support automatic minor version increment.

  • July 16, 2013 - 8:16 pm | Permalink

    Despot, thanks for clarifying that. In fact, the maven-release-plugin will increment the last digit of the version number if you run it non-interactively. In my case, I use only a major and minor version number (version 1.0 – 1 is the major version number, 0 is the minor). So 1.0 increments to 1.1.

    If I used a major, minor and incremental version number (say 1.0.3) then you’re absolutely right – it would not increment the minor number by default. It would increment the incremental number: 1.0.3 would increment to 1.0.4.

  • Rajeev
    July 2, 2014 - 6:49 pm | Permalink

    Hi Stevie,

    Informative post. I have a query. I am trying to do maven release using eclipse with the help of maven plugins. While doing so, when I execute prepare goal I don’t get a prompt for release version, release tag or snapshot values. If I run the same goal in command prompt I do see the prompts for above and I could enter necessary values.

    I am using eclipse kepler. Any help in this regard would be great. 🙂

    Thanks,
    Rajeev

  • July 9, 2014 - 11:19 pm | Permalink

    Hi Rajeev
    Thanks for your question but I’m afraid I can’t help you with that one. I’ve always used the release plugin from command line or via the rather nice M2 release plugin for Jenkins.

  • Arun Narayan
    December 11, 2014 - 11:03 pm | Permalink

    Hi Stevie,

    I am working on automating the release and using the following command:
    mvn -DreleaseVersion=1.0 -DdevelopmentVersion=1.1-SNAPSHOT -Dtag=TEST release:clean release:prepare release:perform -f /Users/arunnarayan/Documents/workspace/project/pom-dev.xml

    However the build fails at the end each time with the exception “Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy (default-deploy) on project brmigrator: Deployment failed: repository element was not specified in the POM inside distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter -> [Help 1]”

    I have the repository element specified inside the distributionManagement attribute of pom.xml. Not sure why it is failing again and again. However when I use mvn deploy and point it to the pom.xml from the checkout folder under target it works.
    Please let me know if there is a workaround for this.

    Also is there a way I can have maven checkout the project from tags and deploy it to a unix server from my mac using terminal etc?

    Thanks,
    Arun

  • frankie robbins
    May 7, 2015 - 7:56 pm | Permalink

    We are currently using the plugin and it works. Since the execution of the plugin against our codebase takes about 15 mins, what prevents other developers from committing while the plugin is executing? Setting the useEditMode=true does not seem to prevent commits to Subversion against the project being built by the plugin.

    Thanks in advance,
    Frankie

  • Shankar KC
    June 28, 2016 - 6:33 am | Permalink

    Can you please upload the sample multi-module project somewhere we can refer to?

  • Sanjoy
    May 3, 2017 - 11:41 am | Permalink

    I am getting following errors
    Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.4.2:prepare (default-cli) on project siximex:
    Unable to tag SCM
    fatal: tag ‘siximex-0.0.2’ already exists

    The git-tag command failed.
    Command output:
    fatal: tag ‘siximex-0.0.2’ already exi

    This is comming repeated time. Even though before executing the POM file I havedeleted the tag from my bitbucket repo, using SourceTree.
    ——————-

    Following is part of the POM file I am tryoing to execute

    4.0.0
    com.abcd
    abcd
    pom
    0.0.2-SNAPSHOT
    ABCDE

    core
    ui.apps
    ui.content
    it.tests
    it.launcher

    org.apache.maven.plugins
    maven-release-plugin
    2.4.2

    false
    true
    [maven-scm] :
    clean install
    install
    release

    org.apache.maven.plugins
    maven-source-plugin
    2.4
    true

    ….
    …..

    • May 3, 2017 - 8:15 pm | Permalink

      Hi Sanjoy, I’ve had similar problems myself in the past. I found it especially tricky to resolve as the new version number is held in a number of places – in your local Git repo, in the remote Origin repo and in Maven’s release.backup files. If these get out of sync, you’ll have trouble.

      I’d suggest remove the tag from your local repo using SourceTree as you suggest. Then also delete it from the remote BitBucket repo via the BitBucket UI. Finally run
      mvn release:clean
      to clean up the release.backup files. Hopefully that should fix it for you.

  • Sanjoy
    May 4, 2017 - 2:00 pm | Permalink

    Thanks Stuart Leitch
    It worked.
    In Source Tree one need to remove existing tag and refresh remote server also.Check in Bitbucket UI if the tag is removed.
    During release use release:clean as 1st command and the follow by release:prepare and release:perform.

  • Sanjoy
    May 4, 2017 - 6:43 pm | Permalink

    After Build of artifacts done I want to put the package in artifactory

    I have following command line for build. Does release:perform uploads the package in artifactory? I have provided artifactory URL in settings.xml

    mvn -f siximex/pom.xml release:prepare release:perform -X -s ‘current Repository’/settings.xml -Darguments=”-Dmaven.javadoc.skip=true” -Dusername=”myuser name” -Dpassword=”mypasword”

    Anyone who already did such please share the knowledge

  • Bhagya
    May 30, 2018 - 7:21 pm | Permalink

    Could you please suggest ways to update the dependent jar SNAPSHOTS versions to be updated to their respective releases as maven release is failing because of the SNAPSHOT dependency.

    I tried mvn versions:use-releases -Dincludes=

    But this updates my main pom version instead of the dependency section.

    • May 31, 2018 - 10:08 pm | Permalink

      mvn versions:use-releases works for me so long as the releases now exist (no need for -Dincludes= though). So if you depend on 1.2.3-SNAPSHOT, mvn versions:use-releases will upgrade to 1.2.3 only if it has now been released.

      If this doesn’t work for you, an alternative is to lock your snapshots (mvn versions:lock-snapshots) and then run tell the release prepare step to allow snapshots:

      mvn release:prepare -DignoreSnapshots

  • Leave a Reply

    Your email address will not be published. Required fields are marked *