Simplified application versioning with maven

java

Version management in maven (especially in multi-module projects) was not pleasant and required multiple build steps, some magic commands and maybe bash script here and there. With version 3.5.0 new cool feature has been added to maven. From this version you can easily customize your build number from build tools using simple properties like ${revision} ${sha1} and ${changelist}.

TL;DR

You can define and/or pass following properties ${revision} ${sha1} and ${changelist} and safely use them in version tag of your project.

Prerequisites

Before you even start thinking about versioning you should consider using Semantic Versioning as a base for your releases. If you are not, it should be your conscious decision.

The problem

With previous maven versions, it’s always been painful to manage project version especially if you had multiple modules in your project. In the past, my way to go solution was maven version plugin with its versions:set goal which allowed to bump project version. It is working but results in changes in many files and it always requires googling or checking bash history in order to find the spell required to bump project version.

When working with maven and managing project version my first go to idea was to basically have somewhere in your project bash script that removed -SNAPSHOT from the project version and then bumped the last number by 1 and added -SNAPSHOT suffix again. Preferably using maven versions plugin. This resulted in the quite complex build script and complicated release process which I’m not even going to explain now since it’s outdated :)

The second idea was to allow a user to fill in version during build/deployment process (current date or build number by default for example) and just set it using version plugin. This one is even more complicated as it requires human interaction which leaves space for error…

The solution shipped with new maven

New properties have been added to maven (${revision} ${sha1} and ${changelist}) and you can use them in version tag of your project. You can set it in project properties (properties tag), pass it from the command line or even store them in external file .mvn/maven.config. With this, your project version is set in a single place (in many multi-module projects all modules are released as single version). It can be even decoupled from your pom file…

Samples

Let’s start with parent pom:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.pchudzik.blog.example</groupId>
  <artifactId>maven-revision</artifactId>
  <version>${revision}</version>

  <modules>
    <module>project1</module>
    <module>project2</module>
  </modules>

  <name>maven-revision</name>
  <packaging>pom</packaging>

  <properties>
    <revision>1.0.0-SNAPSHOT</revision>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

</project>

And two submodules. Project 1:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>maven-revision</artifactId>
        <groupId>com.pchudzik.blog.example</groupId>
        <version>${revision}</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>project1</artifactId>

    <name>project1</name>
</project>

And Project 2:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>maven-revision</artifactId>
        <groupId>com.pchudzik.blog.example</groupId>
        <version>${revision}</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>project2</artifactId>

    <name>project2</name>

    <dependencies>
        <dependency>
            <groupId>com.pchudzik.blog.example</groupId>
            <artifactId>project1</artifactId>
            <version>${revision}</version>
        </dependency>
    </dependencies>
</project>

So after a clean package (or install or deploy) project version will be set to 1.0.0-SNAPSHOT as it is defined in parent pom’s properties. We can easily customize it using mvn clean package -Drevision=2.0.0. That’s pretty handy when used with CI tools. If you want to decouple project version from all you have to do is remove revision from properties and define it in mvn/maven.config in the following way: -Drevision=1.5.0-SNAPSHOT (the file) and that’s all. Now you can update the project version without changing a single thing in your pom file.

As always source code for examples can be found on my GitHub, and a version with decoupled maven version is on a separate branch. You should also checkout official maven announcement for the change.

See Also

If you've enjoyed or found this post useful you might also like:

29 May 2019 #mvn