mavenjenkinsmaven-release-pluginmulti-projectmultiple-repositories

maven release plugin and multiple projects in separate git repositories with Jenkins


I’ve found quite a few hints about the maven-release-plugin, multi-module, multi-project, parent POMs, etc. but they all don’t quite fit what I have:

I have several projects (the reduced case is two: project-common and project-impl) that are somewhat separate from each other, and developed in separate git repositories, but usually released together. For this purpose, project-common/pom.xml contains:

<groupId>de.tarent.example</groupId>
<artifactId>project-common</artifactId>
<version>1.5.1.4-SNAPSHOT</version>

… and project-impl/pom.xml contains:

<groupId>de.tarent.example</groupId>
<artifactId>project-impl</artifactId>
<version>1.5.1.4-SNAPSHOT</version>

<dependencies>
    <dependency>
        <groupId>de.tarent.example</groupId>
        <artifactId>project-common</artifactId>
        <version>${project.version}</version>
    </dependency>

There is no parent POM.

The idea here is to generally use the version of project-common for them all, but be able to occasionally do individual releases of only one project; in those cases, the dependency version would, of course, have to be manually changed, but that’s okay.

Now, we’re using Jenkins’ “Perform Maven Release” to create our releases. (Well, we wish to. The projects were until recently not releasable, so our developers built them by hand, complete with temporary files, unused files, local changes, LDAP passwords in XML configs, editor .swp files, etc. – you can see why I was tasked to change this, despite not knowing Java™ or Maven or Jenkins. Or maybe, because of it.)

The release of project-common goes without a hitch, but project-impl fails at the very first phase, checking that there are no SNAPSHOT dependencies. Well duh. (There are none except the project-common one.) Overriding the maven-release-plugin to skip the SNAPSHOT check is impossible. Using a parent POM does not work here either, as these are completely separate repositories and, on occasion, released independently. So, how to do this while retaining the Jenkins and Maven Release comfort?

Continue on to: Answer your own question – share your knowledge, Q&A-style…


Solution

  • Reading logs, I figured out that Jenkins invokes Maven like this:

    mvn -B -f /var/lib/hudson/jobs/project-impl/workspace/pom.xml \
        -DdevelopmentVersion=1.5.1.5-SNAPSHOT -DreleaseVersion=1.5.1.4 \
        -Dtag=1.5.1.4 -Dresume=false release:prepare release:perform \
        -DpreparationGoals=clean install -e
    

    The -D had to be good for something, right? Could I do ${project.version:-${releaseVersion}} like in shell, I asked a coworker (thanks Umer!), who said, not like that, but -D overrides properties.

    That stopped me short for a bit: I could not place the version into the property, because the maven-release-plugin only updates the project <version> element.

    Thankfully, double indirection works. While an ugly hack, and it will break if someone does not use Jenkins to release, or if someone uses -DreleaseVersion locally, two little changes made those projects releasable:

    First, we add a property called releaseVersion which defaults to the (dynamically updated) ${project.version}:

    <properties>
        <releaseVersion>${project.version}</releaseVersion>
    </properties>
    

    Then, we change the dependency to use that instead:

        <dependency>
            <groupId>de.tarent.example</groupId>
            <artifactId>project-common</artifactId>
            <version>${releaseVersion}</version>
        </dependency>
    

    The only other problem I can see with this solution is if some{one,thing} uses the released POM from the Maven repository, as it also contains this indirection (we don’t filter the POMs on release). But it works well, so far.

    And if there is a need for project-impl, one will just change the <version>${releaseVersion}</version> line to <version>1.5.1.4</version> manually, just like before (ceteris paribus).