Maven Release Non-supported SCM Structures

8 02 2010

As I’ve mentioned in previous blogs (Maven Release Woes with Flat Project Structures and Maven Release with Flat Structures Revisited), the support for custom SCM structures is spotty in the release plugin. It is highly desirable to leverage the release plugin as it provides a lot of functionality we do not want to have to duplicate. By using profiles and activations, we can still leverage the release plugin with only marginal manual intervention.

First let’s review what functionality the release plugin provides:

  1. Check that there are no uncommitted changes in the sources
  2. Check that there are no SNAPSHOT dependencies
  3. Change the version in the poms from x-SNAPSHOT to a new version (you will be prompted for the versions to use)
  4. Transform the SCM information in the POM to include the final destination of the tag
  5. Run the project tests against the modified POMs to confirm everything is in working order
  6. Commit the modified POMs
  7. Tag the code in the SCM with a version name (this will be prompted for)
  8. Bump the version in the POMs to a new value y-SNAPSHOT (these values will also be prompted for)
  9. Commit the modified POMs
  10. Checkout from an SCM URL with optional tag
  11. Run the predefined Maven goals to release the project (by default, deploy site-deploy)

That’s a lot of functionality we don’t want to reproduce manually. Provided your aggregator and modules are setup in the “flat structure” I’ve used for demonstration purposes in the previous two blogs, you’re in luck.

We’re in a bit of catch-22 here when the aggregator is also used for inheritence. Our modules need the aggregator/parent to be deployed before they can be released. However, our aggregator/parent identifies all the modules to be released which ultimately fail because the release plugin doesn’t support our SCM structures! I recommend placing the modules declaration into a profile that can be activated by your CI server or developers when necessary. This will allow the user to release each module of the multi-module build individually. This will require the releaser to know the order of release to perform this correctly.

        <profiles>
                <profile>
                        <id>modules</id>
                        <activation>
                                <property><name>BUILD_NUMBER</name></property>
                        </activation>
                        <modules>
                                <module>../release-module1</module>
                                <module>../release-module2</module>
                        </modules>
                </profile>
        </profiles>

Here I use a property for activation named BUILD_NUMBER as this is a property Hudson supplies to all Maven builds.

There are some minor things that must be done manually to get all this to work, but this solution is better than the alternative (nothing). Once the modules declaration is located inside a non-activated profile, here are the steps to perform a release for your mutli-module build.

  1. Release aggregator/parent project.
  2. Open all modules of the multi-module build and change the parent version from *-SNAPSHOT to the released version and check in those poms. (easy with an IDE or sed/awk).
  3. Release each module individually, in the order the reactor would perform a release.
  4. Open all modules of the multi-module build and change the parent version from the released version to the new -SNAPSHOT version.

There is also a small byproduct of the release process that might be a bug with the release plugin, I’m not sure. If you’ve structured your projects like mine, the module of a multi-module build do not specify versions allowing the inheritance mechanism to supply that metadata. Once released, the release plugin will update your POM with a version element, something that was not present before. You’ll need to also manually remove these.

For example, before release:

  <parent>
    <artifactId>release-parent</artifactId>
    <groupId>com.captechventures</groupId>
    <version>0.0.12</version>
    <relativePath>../release-parent/pom.xml</relativePath>
  </parent>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.captechventures</groupId>
  <artifactId>release-module2</artifactId>

After release:

  <parent>
    <artifactId>release-parent</artifactId>
    <groupId>com.captechventures</groupId>
    <version>0.0.12</version>
    <relativePath>../release-parent/pom.xml</relativePath>
  </parent>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.captechventures</groupId>
  <artifactId>release-module2</artifactId>
  <version>0.0.13-SNAPSHOT</version>

I’m sure a small global replace, similar to the one we used to change the parent pom version, would work to remove this unnecessary entry.

Reference
Sample Project