Gradle plugin for automatically versioning a project using semantic versioning and conventional commits with change log support based on git commit messages.
Apply the plugin using standard Gradle convention and set the version of the project:
plugins {
id 'com.github.jmongard.git-semver-plugin' version '<current version>'
}
//semver { ... } // Optionally add configuration for the plugin before getting the version
//Set the version for the current project:
version = semver.version
//Or in a multi project build set the version of all projects:
def ver = semver.version
allprojects {
version = ver
}
// Note: Using `allprojects` with configuration cache is currently not supported by Gradle.
// If you plan to use configuration cache, apply the plugin to each subproject separately.
For the latest published version see the plugins page at Gradle.org
The versioning system is designed to follow semantic versioning as described by https://semver.org/.
It works by recursively traversing the commit tree until it finds a version tag or release commit and then calculating the new version using from there using commit messages.
The plugin will look for conventional commit messages (fix:
, feat:
, refactor!:
, ...)
and will increase the corresponding version number.
The plugin has the opinion that you want to group several fixes/features or breaking changes into a single release.
Therefore, the major, minor or patch number will be increases by at most one compared to the previous release that is
not a pre-release version. Set property groupVersionIncrements = false
if you don't want the version changes to be combined.
(See Configuration reference below.)
The plugin will search the commit tree until it finds a commit it interprets as a release commit with a version number.
release:
The version number should consist of three numbers separated by a dot e.g. 1.0.0
. The version number does not need to
be at the start of the message e.g. release: v1.2.3
will be matched.
If no version changed has been triggered by any commit messages since the last release then the patch number will be increased by one.
If the current version is not a pre-release then -SNAPSHOT
will be added.
The semantic version is accessible using the semver
extension.
There is several options for getting the version:
semver extension property | example release tagged commit | example release with local changes | example one commits ahead of pre-release alpha.1 |
---|---|---|---|
semver.version |
1.0.1 | 1.0.2-SNAPSHOT | 2.0.0-alpha.2 |
semver.infoVersion |
1.0.1 | 1.0.2-SNAPSHOT | 2.0.0-alpha.2+001 |
semver.semVersion.toString() |
1.0.1+sha.1c792d5 | 1.0.2-SNAPSHOT+sha.1c792d5 | 2.0.0-alpha.2+001.sha.1c792d5 |
There is also the possibility to customize the version string returned using:
semver.semVersion.toInfoVersionString(commitCountStringFormat: String = "%03d", shaLength: Int = 0, version2: Boolean = true, appendPreReleaseLast: Boolean = false)
If Version2 flag is set to false, then semVer version one will be used stripping any non alpha-numeric characters from the pre-release string and removing the metadata part.
The appendPreReleaseLast
option can help when publishing to maven repositories if metadata is included but the version
string will not be semver compliant.
printVersion
This plugin adds a printVersion task, which will echo the project's calculated version to standard-out.
$ gradlew printVersion
> Task :printVersion
10.10.0-SNAPSHOT
printInfoVersion
This plugin adds a printInfoVersion task, which will echo the project's calculated version to standard-out including commit count.
$ gradlew printInfoVersion
> Task :printInfoVersion
10.10.0-SNAPSHOT+072
printSemVersion
This plugin adds a printSemVersion task, which will echo the project's calculated version to standard-out includning commit count and sha.
$ gradlew printSemVersion
> Task :printSemVersion
10.10.0-SNAPSHOT+072.sha.18b3106
printChangeLog
This plugin adds a printChangeLog task, which will format the commit message for the current version
and output them to standard-out. To avoid enoding problem in the console the change log can be outputed
to an UTF-8 encoded file using --file <filename>
e.g. ./gradlew printChangeLog --file build/changelog.md
Note: Use an absolute path for filename as the working directory might not be the one you expect if running
using gradle deamon.
$ gradlew printChangeLog
> Task :printChangeLog
## What's Changed
### Breaking Changes
- fix(#5)!: A breaking change
### Bug Fixes
- #1: A bug fix
- #2: Another bug fix
releaseVersion
The releaseVersion
task will by default create both a release commit, and a release tag. The releaseVersion task will
fail with an error if there exists local modification. It is possible to change this behaviour with the following options:
createReleaseTag=false
.)createReleaseTag=false
option otherwise this is the default.)createReleaseCommit=false
.)createReleaseCommit=false
option otherwise this is the default.)noDirtyCheck=true
.)--preRelease=alpha.1
.
Set the pre-release to "-" e.g. --preRelease=-
to promote a pre-release to a release.With setting: groupVersionIncrements = true
(default)
Command | Commit Text | Calculated version |
---|---|---|
git commit -m "Initial commit" | Initial commit | 0.0.1-SNAPSHOT+001 |
git commit -m "some changes" | some changes | 0.0.1-SNAPSHOT+002 |
gradle releaseVersion | release: v0.0.1 | 0.0.1 |
git commit -m "some changes" | some changes | 0.0.2-SNAPSHOT+001 |
gradle releaseVersion | release: v0.0.2 | 0.0.2 |
git commit -m "fix: a fix" | fix: a fix | 0.0.3-SNAPSHOT+001 |
git commit -m "fix: another fix" | fix: another fix | 0.0.3-SNAPSHOT+002 |
gradle releaseVersion | release: v0.0.3 | 0.0.3 |
git commit -m "feat: a feature" | feat: a feature | 0.1.0-SNAPSHOT+001 |
git commit -m "feat: another feature" | feat: another feature | 0.1.0-SNAPSHOT+002 |
git commit -m "feat!: breaking feature" | feat!: breaking feature | 1.0.0-SNAPSHOT+003 |
git commit -m "some changes" | some changes | 1.0.0-SNAPSHOT+004 |
git commit -m "feat: changes" | feat: changes | 1.0.0-SNAPSHOT+005 |
git commit -m "feat: changes" | feat: changes | 1.0.0-SNAPSHOT+006 |
git commit -m "fix: a fix" | fix: a fix | 1.0.0-SNAPSHOT+007 |
gradle releaseVersion | release: v1.0.0 | 1.0.0 |
git commit -m "some changes" | some changes | 1.0.1-SNAPSHOT+001 |
gradle releaseVersion --preRelease="alpha.1" | release: v1.0.1-alpha.1 | 1.0.1-alpha.1 |
git commit -m "some changes" | some changes | 1.0.1-alpha.2+001 |
gradle releaseVersion | release: v1.0.1-alpha.2 | 1.0.1-alpha.2 |
git commit -m "fix: a fix" | fix: a fix | 1.0.1-alpha.3+001 |
git commit -m "fix: another fix" | fix: another fix | 1.0.1-alpha.3+002 |
git commit -m "feat: a feature" | feat: a feature | 1.1.0-alpha.1+003 |
gradle releaseVersion | release: v1.1.0-alpha.1 | 1.1.0-alpha.1 |
git commit -m "feat: another feature" | feat: another feature | 1.1.0-alpha.2+001 |
git commit -m "feat!: breaking feature" | feat!: breaking feature | 2.0.0-alpha.1+002 |
gradle releaseVersion --preRelease="-" | release: v2.0.0 | 2.0.0 |
With setting: groupVersionIncrements = false
Command | Commit Text | Calculated version |
---|---|---|
git commit -m "Initial commit" | Initial commit | 0.0.1-SNAPSHOT+001 |
git commit -m "some changes" | some changes | 0.0.1-SNAPSHOT+002 |
gradle releaseVersion | release: v0.0.1 | 0.0.1 |
git commit -m "some changes" | some changes | 0.0.2-SNAPSHOT+001 |
gradle releaseVersion | release: v0.0.2 | 0.0.2 |
git commit -m "fix: a fix" | fix: a fix | 0.0.3-SNAPSHOT+001 |
git commit -m "fix: another fix" | fix: another fix | 0.0.4-SNAPSHOT+002 |
gradle releaseVersion | release: v0.0.4 | 0.0.4 |
git commit -m "feat: a feature" | feat: a feature | 0.1.0-SNAPSHOT+001 |
git commit -m "feat: another feature" | feat: another feature | 0.2.0-SNAPSHOT+002 |
git commit -m "feat!: breaking feature" | feat!: breaking feature | 1.0.0-SNAPSHOT+003 |
git commit -m "some changes" | some changes | 1.0.0-SNAPSHOT+004 |
git commit -m "feat: changes" | feat: changes | 1.1.0-SNAPSHOT+005 |
git commit -m "feat: changes" | feat: changes | 1.2.0-SNAPSHOT+006 |
git commit -m "fix: a fix" | fix: a fix | 1.2.1-SNAPSHOT+007 |
gradle releaseVersion | release: v1.2.1 | 1.2.1 |
git commit -m "some changes" | some changes | 1.2.2-SNAPSHOT+001 |
gradle releaseVersion --preRelease="alpha.1" | release: v1.2.2-alpha.1 | 1.2.2-alpha.1 |
git commit -m "some changes" | some changes | 1.2.2-alpha.2+001 |
gradle releaseVersion | release: v1.2.2-alpha.2 | 1.2.2-alpha.2 |
git commit -m "fix: a fix" | fix: a fix | 1.2.2-alpha.3+001 |
git commit -m "fix: another fix" | fix: another fix | 1.2.2-alpha.4+002 |
git commit -m "feat: a feature" | feat: a feature | 1.3.0-alpha.1+003 |
gradle releaseVersion | release: v1.3.0-alpha.1 | 1.3.0-alpha.1 |
git commit -m "feat: another feature" | feat: another feature | 1.3.0-alpha.2+001 |
git commit -m "feat!: breaking feature" | feat!: breaking feature | 2.0.0-alpha.1+002 |
gradle releaseVersion --preRelease="-" | release: v2.0.0 | 2.0.0 |
The plugin can be configured using the semver
extension. This needs to be done before retrieving the version:
semver {
//Example of each property with their respective default value.
//There is no need to set these unless you want to change the default.
defaultPreRelease = "SNAPSHOT"
releasePattern = "\\Arelease(?:\\([^()]+\\))?:"
majorPattern = "\\A\\w+(?:\\([^()]+\\))?!:|^BREAKING[ -]CHANGE:"
minorPattern = "\\Afeat(?:\\([^()]+\\))?:"
patchPattern = "\\Afix(?:\\([^()]+\\))?:"
releaseCommitTextFormat = "release: v%s\n\n%s"
releaseTagNameFormat = "%s"
groupVersionIncrements = true
noDirtyCheck = false
noAutoBump = false
gitDirectory = project.projectDir
createReleaseCommit = true
createReleaseTag = true
}
//Remember to retrieve the version after plugin has been configured
version = semver.version
releaseVersion
task for creating release commits. First parameter
is the version and second parameter is the message (if given using --message=).
This text should preferably match the releasePattern
.releaseVersion
task for creating release tags e.g. "v%s"
to prefix
version tags with "v".gradlew -PnoDirtyCheck=true someOtherTask
.Patterns is matched using java regular expressions with IGNORE_CASE and MULTILINE options enabled.
This plugin has been tested on Gradle 7.x and 8.x. (Version 0.4.3 and older should work on gradle 6.x and probably 5.x)
The plugin calculates the version using the commit tree. Make sure you check out all commits relevant and not just a shallow copy.
GitHub Actions example project
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Create GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag=$(git describe --tags --abbrev=0)
version=$(./gradlew -q printVersion)
./gradlew -q printChangeLog | gh release create $tag -d -t "Example Project $version" -F -
There is currently no special handling for version 0.x.x. If you make breaking changes and want to preserve the 0.x.x version create a release commit yourself and set the number as desired e.g.
git commit -m "release: 0.1.2" --allow-empty
The plugin does not handle commits reverting previous commits and referring to the reverted commit in the commit message. Set the version to the correct version after reverting as in the example above.