Photo by Negative Space from Pexels

Semantic Versioning in MuleSoft

James Shinevar
Slalom Technology
Published in
4 min readFeb 11, 2021

--

TL;DR

  1. Use Versions-Maven-Plugin from MojoHaus to inject semantic version into pom.xml at build time.
  2. Use gitversion’s official Docker version to determine the semantic version.
  3. Make sure you have the full commit history, or else gitversion won’t work

The whole story

Recently I was asked to help build CI/CD pipelines for a Mulesoft Runtime Fabric (RTF) application. As a primarily .NET and Azure developer, this was a new challenge that allowed me to learn about the Mulesoft platform. Mulesoft is built on top of Java and uses Maven to control its build process. A Mulesoft RTF project requires a version in the configuration for multiple reasons. For starters, Mulesoft RTF requires you to deploy your project to the Anypoint Exchange. The Exchange keeps track of the versions based on the value in the pom.xml configuration. Those versions must be unique and sequential. Furthermore, semantic versioning allows a project to understand what changes are being captured in each software release. As a standard practice, I use semantic versioning to define the Major.Minor.Patch number of the code being released.

Problem 1: How Do I Update the pom.xml as part of the pipeline?

I started trying to research if there was an automatic way to handle versioning for a Maven project. The information I found led me to the Versions-Maven-Plugin from MojoHaus. The Versions-Maven-Plugin provides a Maven plug-in that will update the project version in a pom.xml file via a Maven command. I can then use the command provided by the Maven plug-in within my pipeline. When using this plugin, I do not need to have the pom.xml updated before running my deployment pipeline. Instead, I need the semantic version of the repository at the time of the build. Before I run the mvn clean package deploy command, I run mvn versions:set -DnewVersion=$SEMANTIC_VERSION . This command will inject the semantic version into my pom.xml just before building the project.

Problem 2: How Do I Determine the Semantic Version Automatically?

The next challenge was to find a way to determine the semantic version of the code automatically. To handle this, I like using gitversion. If you are familiar with gitversion, you know that it is fabulous at integrating with .NET projects and updating versions. Mulesoft is not .NET, and it wasn’t clear if this tool would blend well with it. The project also made use of Bitbucket Pipelines for its deployment platform. There was no inherent plug-in for using gitversion inside Bitbucket Pipelines, but it can run Docker commands. Gitversion has an official Docker version that will analyze any particular directory you give it and calculate the semantic version. Using the gitversion, Docker should have solved my problems. I followed the command issued from the documentation, and the pipeline gave me the following error:InvalidOperationException: Could not find a ‘develop’ or ‘master’ branch, neither locally nor remotely.

The error taught me that Bitbucket Pipelines execute a shallow fetch for the git repository. Bitbucket Pipelines will only pull the latest 50 commits. Gitversion uses the full record of the repository to determine the Semantic Version. With Gitversion needing the entire record and Bitbucket pulling only a partial history, this was another issue I needed to solve. I attempted to solve this by telling my pipeline to run the following fetch command before running the gitversion docker command: git fetch --unshallow

The git fetch command seemed to work until it didn’t. Sometimes the pipeline pulled the whole history. If it did have the entire history, and the git fetch --unshallow command was given, git would return an error. This error would cause the pipeline to fail. To prevent the pipeline failure error, I implemented a solution that is a bit hacky. I am open to a cleaner or better solution for this, but I placed an OR statement in the bash command so that it would not error if the complete history already existed: git fetch --unshallow || true

Putting It All Together

Now that I had the full history available for gitversion, I could successfully run the Gitversion docker command. The next issue I needed to solve was getting the gitversion Docker command results to the Maven step. The most straightforward way was to export the gitversion Docker command results to a text file and then add it to the artifact list. Finally, inside the Maven step in my pipeline, I read the text file contents into an environment variable. I then used the Maven command to set the version from the Versions-Maven-Plugin.

When using a CI/CD solution for a Mulesoft RTF application, it is necessary to first publish your application to the Anypoint Exchange. This acts as a store for the various versions of the application. It is necessary to ensure that you provide the Anypoint Exchange with a unique and sequential version. Semantic versioning provides a great solution for this. Once the Exchange has the version of the code, you can then deploy it to your RTF. By using an automated semantic versioning tool, neither myself nor my team needed to spend any time considering version numbers for the project. This just occurred on every commit and every push.

--

--

James Shinevar
Slalom Technology

Geek Dad, Software Engineer, Backyard Grill Master, Best Husband I can be.