Gradle plug-in to generate version information from the SCM branch.
Use cases
Given a simple release workflow:
We get the version information from the branch in two flavours:
the full version, which is normalised branch name, followed by the short commit hash
the display version, which can be used to display the version to an end user, and is computed differently on a feature/* or master branch than on a release/* branch.
The computed project's display version on the feature/* and master branches is the base version (the normalised branch name without the prefix) and the abbreviated commit hash (or build version). For release/* branches, the version is computed according the latest tag on the branch, allowing for automatic patch number.
To achieve such a configuration, just configure the versioning plug-in the following way and follow strict conventions for your branch names:
allprojects {
version = versioning.info.full
}
// Using versioning.info.display for generating property files for example
For example, to set the project's full version using the SCM:
version = versioning.info.full
For a multi module project, you will probably do:
allprojects {
version = versioning.info.full
}
Versioning info
Once the versioning plug-in has been applied, a versioning extension is available for the project.
Getting the read-only ìnfo provides access to the following information, computed from the SCM information:
Property
Description
Git: master
Git: feature/great
Git: release/2.0
scm
SCM source
git
git
git
branch
Branch name
master
feature/great
release/2.0
branchType
Type of branch
master
feature
release
branchId
Branch as an identifier
master
feature-great
release-2.0
commit
Full commit hash
09ef6297deb065f14704f9987301ee6620493f70
09ef6297deb065f14704f9987301ee6620493f70
09ef6297deb065f14704f9987301ee6620493f70
build
Short commit/revision indicator, suitable for a build number
09ef629
09ef629
09ef629
full
Branch ID and build
master-09ef629
feature-great-09ef629
release-2.0-09ef629
base
Base version for the display version
``
great
2.0
gradle
Project's version
display
Display version
master
great
2.0.0, 2.0.1, ...
tag (1)
Current tag
(2)
(2)
(2)
lastTag (1)
Last tag
(4)
(4)
(4)
dirty
Current state of the working copy
(3)
(3)
(3)
versionNumber
Version number containing major, minor, patch, qualifier and versionCode
versionNumber.major
Major version
0
0
2
versionNumber.minor
Minor version
0
0
0
versionNumber.patch
Patch version
0
0
0, 1, 2, ...
versionNumber.qualifier
Version qualifier (alpha, beta, engineer, ...)
''
''
''
versionNumber.versionCode
Version code
0
0
20000, 20001, 20002, ...
(1) not supported for Subversion
(2) will be the name of the current tag if any, or null if no tag is associated to the current HEAD.
(3) depends on the state of the working copy the plug-in is applied to. true if the working copy contains uncommitted
files.
(4) Name of the last tag on the branch. It can be on the current HEAD but not
necessarily - it will be null if no previous tag can be found. The last tags are
matched against the lastTagPattern regular expression defined in the configuration. It
defaults to (\d+)$, meaning that we just expect a sequence a digits at the end
of the tag name.
Display version
The display version is equal to the base property is available or to the branch identifier.
For branches to type release, an additional computation occurs:
if no tag is available on the branch which has the base as a prefix, the display version is the base version, suffixed with .0
if a tag is available on the branch which has the base as a prefix, the display version is this tag, where the last digit is incremented by 1
By using the display version when tagging a release, the display version will be automatically incremented, patch after patch, using the release base at a prefix.
Version number
Version number is a container of several numbers computed from display by default . It is hosting major, minor, patch,
qualifier and versionCode.
In a tag like 1.2.3, then major is 1, minor is 2 and patch is 3
Qualifier are taken from tags formatted like 1.2-beta.0 where qualifier is -beta here
Version code is a integer computed from major, minor and patch version.
1.2.3 will give 10203
21.5.16 will give 210516
2.0-alpha.0 will give 20000
Tasks
The versioning plug-in provides two tasks.
versionDisplay
Displays the version information in the standard output. For example:
Creates a file which contains the version information. By default, the file is created at build/version.properties and contains the following information:
This makes this file easy to integrate in a Bash script:
export$(cat build/version.properties | xargs)
The versionFile task can be customised with two properties. The defaults are given below:
versionFile {
// Path to the file to be written
file =newFile(project.buildDir, 'version.properties')
// Prefix to apply to the properties
prefix ='VERSION_'
}
Customisation
The collection of the versioning info can be customised by setting some properties in the versioning extension.
The default properties are shown below:
versioning {
/** * Defines the SCM to use in order to collect information. * * At the moment, only Git (git) and Subversion (svn) are supported.*/
scm ='git'/** * Computation of the release type and the base, by parsing the scm info. * By default, we use "/" as a separator in branch name between the type and the base. If not * present, the type is the branch and the base is empty. * F.e. if you want use tag name instead of branch you may provide something like:*/
releaseParser = { scmInfo, separator='/'->List<String> part = scmInfo.tag.split('/') +''newnet.nemerosa.versioning.ReleaseInfo(type: part[0], base: part[1])
}
/** * Fetch branch name from environment variables. Useful when using CI like * Travis or Jenkins.*/
branchEnv = ['TRAVIS_BRANCH', 'GIT_BRANCH', 'SVN_BRANCH', 'BRANCH_NAME']
/** * Computation of the full version*/
full = { scmInfo->"${scmInfo.branch}-${scmInfo.abbreviated}" }
/** * Set of eligible branch types for computing a display version from the branch base name*/
releases = ['release']
/** * Pattern used to match when looking for the last tag. By default, checks for any * tag having a last part being numeric. At least one numeric grouping * expression is required. The first one will be used to reverse order * the tags in Git.*/
lastTagPattern =/(\d+)$/
}
Dirty versions
The behaviour of the version computation is slightly different when the working
copy is dirty - meaning that the working copy contains some files which are not
staged or not committed.
When the working copy the version is computed from, the default behaviour is to
append the -dirty suffix to the display and full version.
This can be customised with the following attributes on the versioning extension:
versioning {
/** * Dirty mode. * * Closure that takes a version (display or full) and processes it to produce a <i>dirty</i> * indicator. By default, it appends the dirtySuffix value to the version.*/
dirty = { version->"${version}${dirtySuffix}" }
/** * Default dirty suffix*/
dirtySuffix ='-dirty'/** * If set to true, the build will fail if working copy is dirty and if the branch type is * part of the releases list ("release" only by default).*/
dirtyFailOnReleases =false/** * If set to true, no warning will be printed in case the workspace is dirty. Default is * to print a warning.*/
noWarningOnDirty =false/** * If set to true, displays the scm status in case the workspace is dirty. Default is false.*/
dirtyStatusLog =false
}
Snapshots
Recommended configuration for development with -SNAPSHOT, for details see below.
versioning {
releaseBuild =false// own control, which build is really release, set to true in CI-server release job
releaseMode ='snapshot'// how to compute version on release-branches
displayMode ='snapshot'// how to compute version on non-release-branches
dirty = { t-> t } // switch off dirty-suffix ( could be usefull for local development )
}
Snapshots on release branches
Sometimes, you do not want to have the display version for a release branch being the next tag if you are already on a tag.
( release branch is defined in the releases-set. )
By default, the versioning plug-in will behave correctly if you tag only as the very end of your delivery pipeline,
when the project is actually delivered. But if you want to tag upfront, you probably need to indicate that your display version
is a snapshot or similar (see issue [#19|#19] for the discussion).
In such a case, you can specify a snapshot release mode:
versioning {
releaseMode ='snapshot'
}
In this case, if the HEAD is not exactly associated with a tag, the -SNAPSHOT string will be appended to the display version. For example, if there is a previous tag 2.1.0, then the display version will be 2.1.1-SNAPSHOT. But if the HEAD is exactly on the 2.1.0 tag, then the display version is also 2.1.0.
You can customise the -SNAPSHOT suffix used the snapshot property:
The meaning of the parameters is illustrated by the diagrams below:
nextTag = 2.1.2 - computed
lastTag = 2.1.1 - last tag from the HEAD
currentTag = 2.1.1 - exact tag for the HEAD
nextTag = 2.1.1 - computed
lastTag = 2.1.0 - last tag from the HEAD
currentTag = none - exact tag for the HEAD
The extension parameter is the content of the versioning configuration object.
Note that the display mode based on the current tag is not supported in Subversion. It is kind of tricky
to get the tag associated to a given revision.
If You want to have more control when release or snapshot build is performed, You can use releaseBuild boolean property.
This is useful in case of usage central maven repository, which forbids replacement of released final artifacts.
versioning {
releaseBuild =false// this could be set as build argument of gradle
releaseMode ='snapshot'
}
Snapshots on non-release branches
Non-release branches are all which doesn't exists in release-set.
In case you prefer maven way for creating artifacts and You want to use -SNAPSHOT suffix , it's recomended to use displayMode.
versioning {
displayMode ='snapshot'
}
Possible values for displayMode are defined as closures :
Version number computation can be customised by setting some properties in the versioning extension.
versioning {
/** * Digit precision for computing version code. * * With a precision of 2, 1.25.3 will become 12503. * With a precision of 3, 1.25.3 will become 1250003.*/int precision =2/** * Default number to use when no version number can be extracted from version string.*/int defaultNumber =0/** * Closure that takes major, minor and patch integers in parameter and is computing versionCode number.*/Closure<Integer> computeVersionCode = { intmajor, intminor, intpatch->return (major *10**(2* precision)) + (minor *10**precision) + patch
}
/** * Compute version number * * Closure that compute VersionNumber from <i>scmInfo</i>, <i>versionReleaseType</i>, <i>versionBranchId</i>, * <i>versionFull</i>, <i>versionBase</i> and <i>versionDisplay</i> * * By default it tries to find this pattern in display : '([0-9]+)[.]([0-9]+)[.]([0-9]+)(.*)$'. * Version code is computed with this algo : code = group(1) * 10^2precision + group(2) * 10^precision + group(3) * * Example : * * - with precision = 2 * * 1.2.3 -> 10203 * 10.55.62 -> 105562 * 20.3.2 -> 200302 * * - with precision = 3 * * 1.2.3 -> 1002003 * 10.55.62 -> 100055062 * 20.3.2 -> 20003002 **/Closure<VersionNumber> parseVersionNumber = { SCMInfo scmInfo, String versionReleaseType, String versionBranchId,
String versionFull, String versionBase, String versionDisplay ->// We are specifying all these parameters because we want to leave the choice to the developer// to use data that's right to him// Regex explained :// - 1st group one digit that is major version// - 2nd group one digit that is minor version// - It can be followed by a qualifier name// - 3rd group and last part is one digit that is patch versionMatcher m = (versionDisplay =~'([0-9]+)[.]([0-9]+).*[.]([0-9]+)(.*)$')
if (m.find()) {
try {
int n1 =Integer.parseInt(m.group(1))
int n2 =Integer.parseInt(m.group(2))
int n3 =Integer.parseInt(m.group(3))
String q = m.group(4) ?:''returnnewVersionNumber(n1, n2, n3, q, computeVersionCode(n1, n2, n3).intValue(), versionDisplay)
} catch (Exception ignore) {
// Should never go herereturnnewVersionNumber(0, 0, 0, '', defaultNumber, versionDisplay)
}
} else {
returnnewVersionNumber(0, 0, 0, '', defaultNumber, versionDisplay)
}
}
}
Detached and shallow clone support
When a repository is checked out in detached mode, the branch will be set to HEAD and both the display and
full version will be set to HEAD-<commit> where <commit> is the abbreviated commit hash.
When a repository is checked out in shallow mode, no history is available and the display version for a release
branch cannot be correctly computed. In this case, we have two situations:
if the HEAD commit has a tag, we use the tag name as display version
if it has no tag, we use the base version and the SNAPSHOT suffix to indicate that the release's exact version
cannot be computed.
In both cases, the VersionInfo object contains a shallow property which is set to true.
External Git repository
In some very specific cases,
the Git directory might be external to the project.
In order to support this case, you can specify the gitRepoRootDir property:
Subversion is supported starting from version 1.1.0 of the Versioning plug-in. In order to enable your working copy
to work with Subversion, set scm to svn:
versioning {
scm ='svn'
}
The branches are read from under the branches/ folder, and the branch type is parsed
using '-' as a separator. The table below gives some examples for Subversion based branches:
Property
Description
SVN: trunk @ rev 12
SVN: branches/feature-great @ rev 12
SVN: branches/release-2.0 @ rev 12
scm
SCM source
svn
svn
svn
branch
Branch name
trunk
feature-great
release-2.0
branchType
Type of branch
trunk
feature
release
branchId
Branch as an identifier
trunk
feature-great
release-2.0
commit
Revision
12
12
12
build
Revision
12
12
12
full
Branch ID and build
master-12
feature-great-12
release-2.0-12
base
Base version for the display version
``
great
2.0
display
Display version
trunk
great
2.0.0, 2.0.1, ...
The rules for the display mode remain the same for Git.
Collecting the version information using Subversion requires remote access to the repository. Credentials can optionally be configured using following configuration parameters:
versioning {
scm ='svn'// Optional credentials
user ='xxx'
password ='xx
请发表评论