Maven CI Friendly Versions

Starting with Maven 3.5.0-beta-1 you can use the ${revision}, ${sha1} and/or ${changelist} as placeholders for the version in your pom file.

Single Project Setup

This can look like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}</version>
  ...
</project>

This is of course a simple situation where we use only ${revision} for brevity to show the general course.

Based on the above pom you can build your project using:

mvn clean package

But wait there is a problem? Which version will the artifacts have? So you need to define the version for your artifacts. The first possibility is to use the command line like this:

mvn -Drevision=1.0.0-SNAPSHOT clean package

This will become cumbersome over the time. So the other solution for this is to simply use a property inside the pom file which looks like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}</version>
  ...
  <properties>
    <revision>1.0.0-SNAPSHOT</revision>
  </properties>
</project>

So now you can simply call Maven as usual like mvn clean package.

You can of course change the version via the command line like this:

mvn -Drevision=2.0.0-SNAPSHOT clean package

Of course, you can use the .mvn/maven.config file for this.

A note about the used properties. You can only use those named ${revision}, ${sha1} and/or ${changelist} and not other named properties like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}</version>
  ...
  <properties>
    <revision>1.0.0-${buildNumber}-SNAPSHOT</revision>
  </properties>
</project>

The above example will not work as expected. If you like to have more flexibility you can use a combination of the different properties like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}${sha1}${changelist}</version>
  ...
  <properties>
    <revision>1.3.1</revision>
    <changelist>-SNAPSHOT</changelist>
    <sha1/>
  </properties>
</project>

If you like to make a version 2.0.0-SNAPSHOT this can simply being achieved by using this:

mvn -Drevision=2.0.0 clean package

Another usage example can be to make a release which can be done via (version 1.3.1):

mvn -Dchangelist= clean package

Or if you like to make a release with another version:

mvn -Drevision=2.7.8 -Dchangelist= clean package

Please read until the end of this documentation!

Multi-module Setup (Maven 3)

So now let us take a look into a situation where we have a multi-module build. We have a parent pom and one or more children. The parent pom will look like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}</version>
  ...
  <properties>
    <revision>1.0.0-SNAPSHOT</revision>
  </properties>
  <modules>
    <module>child1</module>
    ..
  </modules>
</project>

The child will look like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache.maven.ci</groupId>
    <artifactId>ci-parent</artifactId>
    <version>${revision}</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-child</artifactId>
  ...
</project>

A multi-module build builds the same way as the single project setup. You should define the version either via property in the parent or use the .mvn/maven.config file.

Dependencies

A multi-module build often defines dependencies between modules. The usual way of defining dependencies and their versions has been to use ${project.version} and this has not been changed.

So the correct way to do such things can be seen in the following example:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}</version>
  ...
  <properties>
    <revision>1.0.0-SNAPSHOT</revision>
  </properties>
  <modules>
    <module>child1</module>
    ..
  </modules>
</project>

The child will look like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache.maven.ci</groupId>
    <artifactId>ci-parent</artifactId>
    <version>${revision}</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-child</artifactId>
  ...
  <dependencies>
    <dependency>
      <groupId>org.apache.maven.ci</groupId>
      <artifactId>child2</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
</project>

If you try to use ${revision} instead of ${project.version} your build will fail.

Install / Deploy

To install or deploy artifacts by using the above setup, you have to use the Flatten Maven Plugin. Otherwise, you will install/deploy artifacts in the repository which will not be consumable by Maven. Such a setup will look like this:


<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}</version>
  ...
  <properties>
    <revision>1.0.0-SNAPSHOT</revision>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>flatten-maven-plugin</artifactId>
        <version>1.1.0</version>
        <configuration>
          <updatePomFile>true</updatePomFile>
          <flattenMode>resolveCiFriendliesOnly</flattenMode>
        </configuration>
        <executions>
          <execution>
            <id>flatten</id>
            <phase>process-resources</phase>
            <goals>
              <goal>flatten</goal>
            </goals>
          </execution>
          <execution>
            <id>flatten.clean</id>
            <phase>clean</phase>
            <goals>
              <goal>clean</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <modules>
    <module>child1</module>
    ..
  </modules>
</project>

Multi-Subproject Setup (Maven 4)

When you are using Maven 4 with model version 4.1.0, you don't need to specify the versions of your subproject's parent and your project's own dependencies thanks to automatic version resolution in Maven 4.
In addition, you don't need the Flatten Maven Plugin like you did with Maven 3.