Question: How do you handle feature branches for maven multi project builds?
Jenkins builds and deploys these branches to keep build overhead on develop
We use a similar technique as Peter Kahn, modifying the version of the branch before building. We have three steps in our "Pre Steps":
echo VERSION=$(echo ${GIT_BRANCH} | sed 's_^.*\/__') > env.properties
env.properties
versions:set -DgenerateBackupPoms=false -DnewVersion=${VERSION}-SNAPSHOT
I am quite sure that this can be done with two or even one and only step as well, bit the principe behind it will be the same.
The reason why we don't change the version in the pom.xml files in the branch directly is indeed merging. With SVN this was possible (merging with --accept-mine-conflict
. With GIT this does not exist anymore, so we stopped changing versions and created this pre-build steps.
How about the following approach:
scmBranch
property (that is, the current git branch)master
, develop
, etc.) and populate (or not) a new Maven property, say branch.classifier
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:
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)For Maven ge 3.5.0 try this https://maven.apache.org/maven-ci-friendly.html This is the recommended Maven solution. The only problem (but unusual) can be the numeric versions resolution of the maven dependencies. But this only apears, if you use different SNAPSHOT dependencies of the the module, which is a bad idea anyway.
This does not work Results in warnings throughout the build and GC error when run from top parent.
Ideally, we want to use version as to differentiate feature branch from mainline because it is the normal maven way and classifier manipulation can result in all kinds of issues.
Since maven can use environment variables for properties and we already initialize build environment with a script (we also have git hook scripts that can set environment variables from branch names) we can use env to control the version.
<groupID>my.project</groupId>
<artifactID>database</artifactId>
<version>1.2.0${env.BRANCHMODIFIER}-SNAPSHOT</version>
If on develop our scripts set BRANCHMODIFIER to ""
If on feature/JIRA-30495 our scripts set BRANCHMODIFIER to ".30495"
How does this work in eclipse or Intellij? No clue as of yet.