Question: How do you handle feature branches for maven multi project builds?
Jenkins builds and deploys these branches to keep build overhead on developers to a minimum but develop and feature branches cannot build the same maven version or we risk mismatch between artifacts and source.
We have a script to change parent version in child poms and version in root pom. While this segregates the branches in maven space, it results in extra work when merging.
I think nexus pro staging feature might help us avoid this requirement and make each feature branch use a specific repo which we easily drop after branch deletion/merge.
Again: how to handle the problem of multiple branches and maven?
How about the following approach:
buildnumber-maven-plugin
to fetch information from git and populate specific Maven properties (we are interested specifically in the scmBranch
property (that is, the current git branch)build-helper-maven-plugin
to check whether we are in a feature branch or not (via a regex, excluding well-known branches like master
, develop
, etc.) and populate (or not) a new Maven property, say branch.classifier
maven-jar-plugin
to set a classifier on the generated artifacts, based on what the previous step set, that is, using the new branch.classifier
property: if empty, no classifier will be applied (default behavior, applied to the develop
branch, for example); otherwise a classifier named after the current branch will be dynamically applied.Here is a minimal example:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<id>regex-property</id>
<goals>
<goal>regex-property</goal>
</goals>
<configuration>
<name>branch.classifier</name>
<value>${scmBranch}</value>
<regex>(^develop)|(^master)|(^release.*)</regex>
<replacement></replacement>
<failIfNoMatch>false</failIfNoMatch>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<classifier>${branch.classifier}</classifier>
</configuration>
</plugin>
</plugins>
</build>
The snippet below is basically populating the scmBranch
property dynamically, then setting the branch.classifier
to its value only if different than develop
, master
or release*
, then setting it as a classifier.
Main advantages of this approach:
classifier
attribute of an artifact:
The classifier allows to distinguish artifacts that were built from the same POM but differ in their content.
Examples
Hence, you would have the following artifacts generated:
develop
: e.g. project-1.0.0-SNAPSHOT.jar
(empty classifier, hence not applied, as handled by the regex)featureA
: e.g. project-1.0.0-SNAPSHOT-featureA.jar
hotfix-JIRA123
: e.g. project-1.0.0-hotfix-JIRA123.jar
release-sprint42
: that's up to you, I added this case to not apply the branch name, simply because in these cases I prefer to esplicitely set a special classifier, RC<number>
, for release candidates, but that's a matter of conventions/taste/habits, you can apply the same approach on this branch as well, as long as no clashes will be created on Nexus. Also note: when using JIRA/Stash/Git integration, the release branch name is normally something like release/v0.1.0
, where the /
character may cause issues in some OS (still something fixeable via further regex replacing though, if really required).master
: hey, no one should work on master
:) the case is there just as a double check, but that's actually not requiredWarnings on this approach:
<artifactId>.pom
files containing branch classifier can get into conflicts with the mainline build (i.e. overriding it)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With