Showing posts with label release. Show all posts
Showing posts with label release. Show all posts

Friday, May 14, 2010

How to create a release without the maven2 release plugin

One of the most referenced articles I have written is "How to create a release using the maven release plugin". But what if you can't get the maven release plugin to work with your project? Perhaps like our team, you've got a legacy maven2 multi-module project that's been nigh impossible to use with the release plugin. Our project has a mix of WAR modules combined with some Flex modules. I believe our last issue was some googlecode flex mojo wasn't working with the release plugin. Consequently, for the past year or so, we've been manually creating our releases. This actually hasn't been that much of a pain since we really only do it once a sprint at the end. Combined with my favorite perl script it doesn't really take that long. However, it does have the disadvantage of requiring some knowledge of what and now to do it. Ideally, it would be a job in Hudson, anyone on the team could run as many times as they like.

In an effort to try and automate as much as possible, I decided to try and automate releasing our legacy multi-module project using bash. This has several benefits: create a release faster, done consistently each time, turn-key solution anyone on the team can run that doesn't require stale documentation on how to do it.

It took my several hours to essentially duplicate the maven release plugin process. Thanks to our new intern Scott Rogers and linux master Ron Alleva, I was eventually able to get it finished. It's my first "official" bash script so pardon the mess. If you've never attempted to automate your release project, first consider reading my article on How to effectively use SNAPSHOT.

Here is the script available as a gist on github: project-release.sh. Here is what it does:

  1. Copies the current working branch (i.e. trunk) into another branch. It uses the pom.xml value to get the current working branch.
  2. Updates all the pom.xml version sections of the current working branch
  3. Commits the pom.xml changes
  4. Checks out the release branch
  5. Updates all the pom.xml version sections of the release branch (basically stripping off -SNAPSHOT)
  6. Commits the pom.xml changes
To run this script all you have to do is run: project-release.sh 2 false. The first parameter (2) is the increment position that the current working branch needs to be next. For example, if trunk was on 1.2.0-SNAPSHOT and the position passed in was 2, then trunk gets updated to 1.3.0-SNAPSHOT. If the position was 3 then trunk would be updated to 1.2.1-SNAPSHOT. The second parameter is used when testing. It's like the dryRun option in the maven release plugin. When set to true, nothing gets copied or committed.

A few notes about the script:
  • The base branch URL is hardcoded but could easily be passed in as another parameter or placed and read from some external file.
  • It uses the cmd xpath to extract out the pom version, project name, and scm url. I'm on ubuntu 9.10 and according to synaptic I have libxml-xpath-perl version 1.13-6 installed.
  • It doesn't run any maven commands like mvn deploy. Other jobs in CI can accomplish that or you can easily add them into the script.
  • To run from Hudson:
    • Create a New Job
    • In the Build section Add a Execute Shell Step
    • Update the Command text with: $WORKSPACE/trunk/project-release.sh 2 false
Overall, I'm pretty happy with the outcome. And as we start to perform more releases among multiple projects I think it's going to really come in handy. I think ideally you should try and release your project using the maven release plugin, but if that isn't possible then don't give up. Just clone.

Wednesday, October 22, 2008

More tips on using the maven2 release plugin

This blog's most frequently visited post was the one I did over a year ago titled "How to create a release using the maven2 release plugin". Automating this portion of our frequent release process without a doubt has saved my team hundreds of hours over the past year. For that reason I would like to provide some new tips I discovered yesterday when I needed to change the subversion comment used by the release plugin when committing any changes.

For teams not using the maven-release-plugin yet, this handy plugin helps automate the complete process when releasing your software. It helps save time by doing the following and more:

  • First it will build your project running any tests you specify
  • If successful, it will then commit your project into a tag
  • Update the tag pom versions from say 1.0.0-SNAPSHOT to 1.0.0
  • Change the tag pom SCM URL to correctly point to the tag instead of HEAD
  • Most importantly, it will build the release (1.0.0) and upload the artifacts to your companies maven2 repository (archiva now in our case; was artifactory).
  • Finally, it will increment the pom versions in HEAD to be the next release (1.0.1-SNAPSHOT).

Tip #1 - Change Commmit Comment
By default the maven-release-plugin uses a comment like, [maven-release-plugin] prepare release project-1.0.0, when doing any type of commit such as creating a tag/branch or incrementing the pom versions. Which works wonderful until your team implements a Subversion pre-commit hook requiring all commits to start with certain keywords (Story: ZZZ, Jira: ZZ-N). Luckily the maven-release-plugin has an option to override the comment.

There are two simple ways to provide the plugin with the comment. The first sets the system property, scmCommentPrefix, to the predefined prefix. The second, provides the prefix comment in the pom.

mvn release:clean release:prepare -DscmCommentPrefix=Jira: AC-100 [maven-release-plugin]

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<scmCommentPrefix>Jira: AC-100 [maven-release-plugin]</scmCommentPrefix>
</configuration>
</plugin>
<plugins>

Tip #2 - Configuration Options via -D
Disappointed that I didn't catch this earlier, especially since I have been using -DpreparationGoals for awhile now, but all of the optional parameters for the prepare goal can be defined with -D rather than in the POM (as above). So if you wanted to change the default tagBase to use /branches instead of the default /tags do the following. However, I would still put this static value in the pom.
mvn release:clean release:prepare -DtagBase=http://project.svn.org/svn/project/branches
Tip #3 - Allow SNAPSHOT dependencies
This new feature is going to be huge for legacy projects who weren't raised with the release plugin. As mentioned in my previous post, previous versions of the release plugin didn't allow you to have SNAPSHOT dependencies; rightfully so too since that wouldn't be a very good practice to have a release depend on a changing dependency. However, I think this feature prevented many projects from using the release plugin because their snapshot depenencies were too many to change and it was just easier to continue doing same old.

Even though I have not used this feature, it would seem now one could release a project using this plugin and still have SNAPSHOT dependencies. However, after creating the release it would still be a good idea to go back in the release and change any SNAPSHOT dependencies to releases.

I believe this is a new feature so you might also want to upgrade to the latest version.

Friday, September 14, 2007

How to create a release using the maven2 release plugin

If you haven't figured out how to simplify creating a release for your maven2 projects then you need to look into the maven-release-plugin. This powerful plugin helps shorten the time it takes when creating a release and we have used it extensively on our open source projects: RSS BC, SIP BC, UDDI BC, and the XMPP BC.

Kicking It Old School
Back when we were using maven1 we actually used a sed script to update the versions in the project.xml and project.properties files. Boy those where the days; how I don't miss them. However, I was still impressed with it so here you go. Create a script named swap:
#!/bin/sh
cp $1 $1.backup
sed -e s/"$2"/"#3"/g $1 > temp
cat temp $1

Browse to your project and run:
find -name 'project.properties' -exec ~/swap {} 1.1.0-SNAPSHOT 1.1.0 \;
find -name 'project.xml' -exec ~/swap {} 1.1.0-SNAPSHOT 1.1.0 \;

It was effective and did the job (in fact it's easier to use a perl script), but you still had to create the tag/branch and commit. Also with maven2 POMs you have other values that have to be updated like the <scm> information.

How to use the maven-release-plugin
First, you need to clean up your POMs. Here are three basic guidelines that will make your life easier when managing them:

  1. Avoid declaring groupIds and versions where it is not required. For example in child POMs, if the groupId and version are the same as the parent, you don't have to define your own groupId or version. By default it inherits from the parent.
  2. If you do have to declare versions, use the section of your parent POM. This helps define your downstream dependencies and prevents the child POMs from having to declare the versions that are shared among the project.
  3. Use properties to define other common versions.
For a real example, view the RSS BCs parent pom, and subsequent child poms: extensions, jar, and zip. Notice the use of properties and dependencyManagement in the super pom. Also note how the child POMs don't have to declare versions for inner project dependencies that are defined in the parent POM under dependencyManagement.

Now that you have your POMs cleaned up it's time to use the maven-release-plugin. It doesn't actually require these changes, but I am anal so sorry.

Step1
Make sure your parent POM has the <scm> section describing the projects source control location.

Step2
Get a clean copy of your project. The maven-release-plugin will not run if you have locally modified files; including IDE files or the target folder.

Step3
Run mvn release:prepare -DdryRun=true
This will walk you through a dry run and you can view the temporary POMs it creates to verify you did everything correctly.

Step4
Run mvn release:clean release:prepare -Dusername=johndoe -Dpassword=passwd
This will actually commit a tag with non-snapshot versions of your project and also increment all your versions to the next release. So for example, if your current version is 0.9.1-SNAPSHOT, it will commit a tag with 0.9.1 version, and update the trunk POMs with 0.9.2-SNAPSHOT. Of course when using the prepare goal you are prompted for the release numbers and next release numbers.

Step5
Run mvn release:perform
The perform goal basically runs deploy and site-deploy. This step is optional and I typically don't run it.

Gotcha
One gotcha is if your project has a SNAPSHOT dependency on an artifact outside your project, the release plugin doesn't handle that (or at least I haven't figured it out). The prompts seem to ask questions about what version they need to be, but never actually does anything with the information. Hopefully this will be fixed in future versions. In the mean time, use properties, and when running mvn release:prepare use the -D option to specify the version and then manually update the tag and trunk pom to reflect the real version. So something like mvn release:prepare -DdryRun=true -Dcommon.jbi.runtime.version=0.9.2.

Windows Users
The other issue you might have is if you are using Windows. Since I am using Linux the svn commands are already installed and I use them frequently. And since the release plugin uses the svn commands to do its work, you will need to install the svn client commands in order to it in DOS. To do that go here, go down to the Windows section, and click Win32 packages built against Apache 2.2. In there download and install the svn-1.4.6-setup.exe. After installing it, open up a new DOS window and run svn help.

For further tips and tricks read the Gestalt Developers Guidelines for creating a release using the maven-release-plugin.

Related Articles