Maven Git Versioning Extension
This extension can virtually set project version and properties, based on current Git status
- Get rid ofβ¦
- Maven Release Plugin; see Maven Release Plugin: The Final Nail in the Coffin
- editing
pom.xml
- managing project versions within files and Git tags
- git merge conflicts
Requirements
β οΈ minimal required java version is11
β οΈ minimal required maven version is3.6.3
Usage
Add Extension to Maven Project
create or update ${rootProjectDir}/.mvn/extensions.xml
file
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
<extension>
<groupId>me.qoomon</groupId>
<artifactId>maven-git-versioning-extension</artifactId>
<version>9.6.5</version>
</extension>
</extensions>
Configure Extension
Create ${rootProjectDir}/.mvn/maven-git-versioning-extension.xml
.
You can configure the version and properties adjustments for specific branches and tags.
Example: maven-git-versioning-extension.xml
<configuration xmlns="https://github.com/qoomon/maven-git-versioning-extension"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/qoomon/maven-git-versioning-extension https://qoomon.github.io/maven-git-versioning-extension/configuration-9.4.0.xsd">
<refs>
<ref type="branch">
<pattern>.+</pattern>
<version>${ref}-SNAPSHOT</version>
<properties>
<foo>${ref}</foo>
</properties>
</ref>
<ref type="tag">
<pattern><![CDATA[v(?<version>.*)]]></pattern>
<version>${ref.version}</version>
</ref>
</refs>
<!-- optional fallback configuration in case of no matching ref configuration-->
<rev>
<version>${commit}</version>
</rev>
</configuration>
Configuration Elements
-
<disable>
global disable(true
)/enable(false
) extension, default isfalse
.- Can be overridden by command option, see Parameters & Environment Variables.
-
<projectVersionPattern>
An arbitrary regex to match project version, matching groups can be used as Format Placeholders (has to be a full match pattern) -
<describeTagPattern>
An arbitrary regex to match tag names for git describe command- has to be a full match pattern e.g.
v(.+)
, default is.*
- has to be a full match pattern e.g.
-
<describeTagFirstParent>
Enable(true
) or disable(false
) following only the first parent in a merge commit- default is
true
- default is
-
<updatePom>
Enable(true
)/disable(false
) version and properties update in original pom file, default isfalse
- Can be overridden by command option, see Parameters & Environment Variables.
-
<refs considerTagsOnBranches="BOOLEAN">
List of ref configurations, ordered by priority. First matching configuration will be used.-
considerTagsOnBranches
By default, tags pointing at current commit will be ignored if HEAD is attached to a branch. -
If this option is
true
tags will always be taken into account. -
<ref type="TYPE">
specific ref patch definition.-
required
type
Ref type indicates which kind of ref will be matched againstpattern
, can bebranch
ortag
-
<pattern>
An arbitrary regex to match ref names- has to be a full match pattern e.g.
main
orfeature/.+
- has to be a full match pattern e.g.
-
<describeTagPattern>
An arbitrary regex to match tag names for git describe command- has to be a full match pattern e.g.
v.+
) - will override global
<describeTagPattern>
value
- has to be a full match pattern e.g.
-
<describeTagFirstParent>
Enable(true
) or disable(false
) following only the first parent in a merge commit- default is
true
- default is
-
<version>
The new version format, see Format Placeholders -
<properties>
<name>value</name>
A property definition to update the value of a property.<name>
The property namevalue
The new value format of the property, see Format Placeholders
-
<userProperties>
<name>value</name>
A property definition to add a user property to the maven session, active during the build. UserProperties with the same name of a property in the pom or this configuration file will take precedence as that is how maven handles user properties.<name>
The property namevalue
The new value format of the property, see Format Placeholders
<userProperties> <test.property>${ref}</test.property> </userProperties>
-
<updatePom>
Enable(true
) or disable(false
) version and properties update in original pom file- will override global
<updatePom>
value
- will override global
-
-
-
<rev>
Rev configuration will be used if no ref configuration is matching current git situation.- same as
<ref>
configuration, excepttype
attribute and<pattern>
element.
- same as
-
<relatedProjects>
Add external projects as related project to update their versions as well.<relatedProjects> <project> <groupId>me.qoomon</groupId> <artifactId>base</artifactId> </project> </relatedProjects>
Format Placeholders
β¦.slug
placeholders means all /
characters will be replaced by -
.
version
will be slugified automatically, so no need to use ${β¦.slug}
placeholders in <version>
format.
βΉ define placeholder default value (placeholder is not defined) like this ${name:-DEFAULT_VALUE}
e.g ${env.BUILD_NUMBER:-0}
or ${env.BUILD_NUMBER:-local}
${name:+OVERWRITE_VALUE}
e.g ${dirty:-SNAPSHOT}
resolves to -SNAPSHOT
instead of -DIRTY
Placeholders
-
${env.VARIABLE}
Value of environment variableVARIABLE
-
${property.name}
Value of commandline property-Dname=value
-
${version}
<version>
set inpom.xml
e.g. '1.2.3-SNAPSHOT'${version.core}
the core version component of${version}
e.g. '1.2.3'${version.major}
the major version component of${version}
e.g. '1'${version.major.next}
the${version.major}
increased by 1 e.g. '2'
${version.minor}
the minor version component of${version}
e.g. '2'${version.minor.next}
the${version.minor}
increased by 1 e.g. '3'
${version.patch}
the patch version component of${version}
e.g. '3'${version.patch.next}
the${version.patch}
increased by 1 e.g. '4'
${version.label}
the version label of${version}
e.g. 'SNAPSHOT'${version.label.prefixed}
like${version.label}
with label separator e.g. '-SNAPSHOT'
-
Project Version Pattern Groups
- Content of regex groups in
<projectVersionPattern>
can be addressed like this: ${version.GROUP_NAME}
${version.GROUP_INDEX}
- Named Group Example
<configuration> <projectVersionPattern><![CDATA[^.+-(?<environment>.+)-SNAPSHOT$]]></projectVersionPattern> <refs> <ref type="branch"> <version>${version.environment}-SNAPSHOT</version> </ref> </refs> </configuration>
- Content of regex groups in
-
${ref}
${ref.slug}
ref name (branch or tag name or commit hash) -
Ref Pattern Groups
- Content of regex groups in
<ref><pattern>
can be addressed like this: ${ref.GROUP_NAME}
${ref.GROUP_NAME.slug}
${ref.GROUP_INDEX}
${ref.GROUP_INDEX.slug}
- Named Group Example
<ref type="branch"> <pattern><![CDATA[feature/(?<feature>.+)]]></pattern> <version>${ref.feature}-SNAPSHOT</version> </ref>
- Content of regex groups in
-
${commit}
commit hash '0fc20459a8eceb2c4abb9bf0af45a6e8af17b94b' -
${commit.short}
commit hash (7 characters) e.g. '0fc2045' -
${commit.timestamp}
commit timestamp (epoch seconds) e.g. '1560694278' -
${commit.timestamp.year}
commit year e.g. '2021' -
${commit.timestamp.year.2digit}
2-digit commit year.g. '21' -
${commit.timestamp.month}
commit month of year e.g. '12' -
${commit.timestamp.day}
commit day of month e.g. '23' -
${commit.timestamp.hour}
commit hour of day (24h)e.g. '13' -
${commit.timestamp.minute}
commit minute of hour e.g. '59' -
${commit.timestamp.second}
commit second of minute e.g. '30' -
${commit.timestamp.datetime}
commit timestamp formatted asyyyyMMdd.HHmmss
e.g. '20190616.161442' -
${build.timestamp}
maven-build-timestamp (epoch seconds) e.g. '1560694278' -
${build.timestamp.year}
maven-build-timestamp year e.g. '2021' -
${build.timestamp.year.2digit}
2-digit maven-build-timestamp year.g. '21' -
${build.timestamp.month}
maven-build-timestamp month of year e.g. '12' -
${build.timestamp.day}
maven-build-timestamp day of month e.g. '23' -
${build.timestamp.hour}
maven-build-timestamp hour of day (24h)e.g. '13' -
${build.timestamp.minute}
maven-build-timestamp minute of hour e.g. '59' -
${build.timestamp.second}
maven-build-timestamp second of minute e.g. '30' -
${build.timestamp.datetime}
maven-build-timestamp formatted asyyyyMMdd.HHmmss
e.g. '20190616.161442' -
${describe}
Will resolve togit describe
output -
${describe.distance}
The distance count to last matching tag -
${describe.tag}
The matching tag ofgit describe
${describe.tag.version}
the tag version determined by regex(?<version>(?<core>(?<major>\d+)(?:\.(?<minor>\d+)(?:\.(?<patch>\d+))?)?)(?:-(?<label>.*))?)
${describe.tag.version.core}
the core version component of${describe.tag.version}
e.g. '1.2.3'${describe.tag.version.major}
the major version component of${describe.tag.version}
e.g. '1'${describe.tag.version.major.next}
the${describe.tag.version.major}
increased by 1 e.g. '2'
${describe.tag.version.minor}
the minor version component of${describe.tag.version}
e.g. '2'${describe.tag.version.minor.next}
the${describe.tag.version.minor}
increased by 1 e.g. '3'
${describe.tag.version.patch}
the patch version component of${describe.tag.version}
e.g. '3'${describe.tag.version.patch.next}
the${describe.tag.version.patch}
increased by 1 e.g. '4'${describe.tag.version.patch.plus.describe.distance}
the${describe.tag.version.patch}
increased by${describe.distance}
e.g. '2'${describe.tag.version.patch.next.plus.describe.distance}
the${describe.tag.version.patch.next}
increased by${describe.distance}
e.g. '3'
${describe.tag.version.label}
the label version component of${describe.tag.version}
e.g. 'SNAPSHOT'${describe.tag.version.label.next}
the${describe.tag.version.label}
converted to an integer and increased by 1 e.g. '6'${describe.tag.version.label.plus.describe.distance}
the${describe.tag.version.label}
increased by${describe.distance}
e.g. '2'${describe.tag.version.label.next.plus.describe.distance}
the${describe.tag.version.label.next}
increased by${describe.distance}
e.g. '3'
-
Describe Tag Pattern Groups
- Content of regex groups in
<describeTagPattern>
can be addressed like this: ${describe.tag.GROUP_NAME}
${describe.tag.GROUP_NAME.slug}
${describe.tag.GROUP_INDEX}
${describe.tag.GROUP_INDEX.slug}
- Named Group Example
<ref type="branch"> <pattern>main</pattern> <describeTagPattern><![CDATA[v(?<name>.*)]]></describeTagPattern> <version>${describe.tag.name}-SNAPSHOT</version> </ref>
- Content of regex groups in
-
${dirty}
If repository has untracked files or uncommitted changes this placeholder will resolve to-DIRTY
, otherwise it will resolve to an empty string.βΉ May lead to performance issue on very large projects (10,000+ files)
-
${dirty.snapshot}
Like${dirty}
, but will resolve to-SNAPSHOT
-
${value}
Original value of matching property (Only available within property format)
Parameters & Environment Variables
-
Disable Extension
- Environment Variables
export VERSIONING_DISABLE=true
- Command Line Parameters
mvn β¦ -Dversioning.disable
-
Provide branch or tag name
- Environment Variables
export VERSIONING_GIT_REF=$PROVIDED_REF
e.g.refs/heads/main
,refs/tags/v1.0.0
orrefs/pull/1000/head
export VERSIONING_GIT_BRANCH=$PROVIDED_BRANCH_NAME
e.g.main
orrefs/heads/main
export VERSIONING_GIT_TAG=$PROVIDED_TAG_NAME
e.g.v1.0.0
orrefs/tags/v1.0.0
- Command Line Parameters
mvn β¦ -Dgit.ref=$PROVIDED_REF
mvn β¦ -Dgit.branch=$PROVIDED_BRANCH_NAME
mvn β¦ -Dgit.tag=$PROVIDED_TAG_NAME
βΉ Especially useful for CI builds see Miscellaneous Hints -
Update
pom.xml
- Environment Variables
export VERSIONING_UPDATE_POM=true
- Command Line Parameters
mvn β¦ -Dversioning.updatePom
Provided Project Properties
git.worktree
absolute path of git worktree directory
IDE Setup
IntelliJ - Multi Modules Projects
For a flawless experience you need to disable this extension during project import, otherwise you'll get errors for modules depending on another module.
To disable this extension during import add following Maven Importer VM options (Preferences > Build, Execution, Deployment > Build Tools > Maven > Importing > VM options for importer
) -Dversioning.disable=true
Related Issues
CI/CD Setup
Most CI/CD systems do checkouts in a detached HEAD state so no branch information is available, however they provide environment variables with this information. You can provide those, by using Parameters & Environment Variables.
Native Support
- GitHub Actions: if
$GITHUB_ACTIONS == true
,GITHUB_REF
is considered - GitLab CI: if
$GITLAB_CI == true
,CI_COMMIT_BRANCH
,CI_COMMIT_TAG
andCI_MERGE_REQUEST_SOURCE_BRANCH_NAME
are considered - Circle CI: if
$CIRCLECI == true
,CIRCLE_BRANCH
andCIRCLE_TAG
are considered - Jenkins: if
JENKINS_HOME
is set,BRANCH_NAME
andTAG_NAME
are considered
Manual Setup
Set following environment variables before running your mvn
command
export VERSIONING_GIT_REF=$PROVIDED_REF;
$PROVIDED_REF
value examples: refs/heads/main
, refs/tags/v1.0.0
or refs/pull/1000/head
or
export VERSIONING_GIT_BRANCH=$PROVIDED_BRANCH;
export VERSIONING_GIT_TAG=$PROVIDED_TAG;
$PROVIDED_BRANCH
value examples: main
, refs/heads/main
or refs/pull/1000/head
$PROVIDED_TAG
value examples: v1.0.0
or refs/tags/v1.0.0
Miscellaneous Hints
Commandline To Print Project Version
mvn help:evaluate -Dexpression=project.version -q -DforceStdout
Reproducible builds
The maven reproducible builds feature can be easily supported with this extension e.g.
<ref type="branch">
<pattern>.+</pattern>
<properties>
<project.build.outputTimestamp>${commit.timestamp}</project.build.outputTimestamp>
</properties>
</ref>
Build & Release
gpg --import private.key
gpg --list-keys
./mvnw verify
# Publishes this plugin to local Maven
./mvnw install
# Run integration tests after install,
# integration tests will run with LATEST version of extension installed
./mvnw failsafe:integration-test
# Publishes this plugin to OSS Nexus.
GPG_TTY=$(tty) ./mvnw clean deploy -P release -Dgpg.keyname=???
Debug
mvn help:evaluate -Dexpression=project.version -Dorg.slf4j.simpleLogger.log.me.qoomon.maven.gitversioning=debug