gradle-semver-plugin
gradle-semver-plugin copied to clipboard
Gradle Plugin for Automated Semantic Versioning
Gradle Semver Plugin
This plugin adds a flexible approach to adding semantic versioning to your gradle project using git history. It supports multi-module gradle projects, running in CI, and multiple types of git strategies.
- Usage
- Overview
- Using with CI
- Version Calculation
- Branch Matching Strategy
- Unsupported
Usage
plugins {
id("com.figure.gradle.semver-plugin") version "<latest version>"
}
// The semver extension must be declared before invoking semver.version
semver {
// All properties are optional, but it's a good idea to declare those that you would want
// to override with Gradle properties or environment variables, e.g. "overrideVersion" below
tagPrefix("v")
initialVersion("0.0.1")
findProperty("semver.overrideVersion")?.toString()?.let { overrideVersion(it) }
}
// must be called after semver {}
version = semver.version
If you're using a Gradle Version Catalog, feel free to use these entries:
[versions]
figure-gradle-semver = "<latest version>"
[plugins]
gradle-semver = { id = "com.figure.gradle.semver-plugin", version.ref = "figure-gradle-semver" }
plugins {
alias(libs.plugins.gradle.semver)
}
Overview
Whenever a gradle task is ran, such as ./gradlew clean build
, the semver plugin will calculate the current semantic
version based on git history.
This calculation is done using:
- The version of the target branch
- The current branch
- The branch matching strategy
This calculated semantic version is then available as an output with the extension properties semver.version
and semver.versionTagName
.
Glossary
Item | Definition | Example |
---|---|---|
current branch | The branch you are working on. | fix-bug |
target branch | The branch that the current branch targets, often the default branch. | main , master , develop |
latest version | The latest published git tag on the target branch. | 1.0.2 |
current / calculated version | The version that is calculated when it runs. This will be ahead of the latest version. | 1.0.3 |
Plugin Extension Properties
These variables come from the plugin extension, and are only available after the semver {}
extension is configured.
Variable | Type | Description |
---|---|---|
version |
String |
The current version, e.g. 1.0.1 |
versionTagName |
String |
The tag name for the current calculated version, i.e. tagPrefix + version , e.g. v1.0.1 |
Example:
semver {
// ...
}
version = semver.version
Plugin Tasks
Task Name | Description |
---|---|
currentSemver |
Print the current version and versionTagName |
generateVersionFile |
Generate the build/semver/version.txt file containing the raw version and the tag version, often used in CI |
createAndPushVersionTag |
Create a git tag from semver.versionTagName and push the tag to the remote repo. Be careful using :createAndPushVersionTag in a multi module project as it will attempt to create duplicate tags for each project. |
Using with CI
When using this plugin in CI, ensure that all branches & tags are checked out to get an accurate version calculation.
By default, the actions/checkout
action only pulls the latest commit, which can cause some issues with this plugin.
GitHub Actions Example:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0 # <-- This config is the most important part, and checks out the entire history of the repo
Version Calculation
This plugin comes bundled with a single Version Calculator that implements a target branch calculator - the version of
the current
branch is based on the latest version of the branch it targets, e.g. develop
is branched from main
, so the version
of develop
is based on the current version of main
.
The Target Branch Version Calculator includes two Branch Matching strategies, based on the git strategy that is being
used.
By default, the Flow
strategy is selected if a develop
branch is present, otherwise the Flat
strategy will be
used.
-
Flat
- Ideal for projects using a single branch strategy withmain
ormaster
.
branch | pre release label | target branch | example |
---|---|---|---|
main or master |
main or master | 1.2.3 | |
rc/my-release-candidate |
rc | main or master | 1.2.4-rc.2 |
xxx |
xxx | main or master | 1.2.4-xxx.13 |
-
Flow
- Broadly based on a Git Flow workflow without release branches, the following branches are supported:
branch | pre release label | target branch | example |
---|---|---|---|
main or master |
'' | main or master | 1.2.3 |
develop |
beta | main or master | 1.2.4-beta.13 |
rc/my-release-candidate |
rc | main or master | 1.2.4-rc.2 |
xxx |
xxx | develop | 1.2.5-xxx.13 |
Branch Matching Detection Order
The following outlines the branch matching detection order from first matched to last matched:
- Custom version strategy
-
main
anddevelop
exist -
master
anddevelop
exist -
main
only exists -
master
only exists - Throw unsupported branching strategy
Branch Matching Strategy
A Strategy contains a list of BranchMatchingConfiguration
instances which are applied in order until the first match
is reached, it contains the following properties:
- Branch name regex
- Target branch
- Version modifier: modifies the major, minor or patch components of the semver
- Version qualifier: optionally qualifies the semver with a prerelease label and build metadata
The VersionModifier
can be set for all BranchMatchingConfiguration
instances in the strategy with the plugin
extension:
semver {
versionModifier { nextPatch() }
// OR
versionModifier("patch")
}
Only a single BranchMatchingConfiguration
whose regex matches the current branch will be applied, so effectively this
sets the VersionModifier
for the current branch.
The supported values are major
, minor
and patch
.
Advanced Usage
plugins {
id("com.figure.gradle.semver-plugin") version "<latest version>"
}
// The semver extension must be declared before invoking semver.version
semver {
// All properties are optional, but it's a good idea to declare those that you would want
// to override with Gradle properties or environment variables, e.g. "overrideVersion" below
tagPrefix("v")
initialVersion("0.0.3")
findProperty("semver.overrideVersion")?.toString()?.let { overrideVersion(it) }
// This is only used for non-user defined strategies, i.e. predefined Flow or Flat
findProperty("semver.modifier")?.toString()
?.let { versionModifier(buildVersionModifier(it)) }
// Manually specifying the gitDir location is typically not necessary. However, in cases where you have a composite
// gradle build, it will become necessary to define where your .git directory is in correlation to your composite
// build. In the following example, you may have a build at `parent/child`. `child` specifies that the parent
// directory to its projectDir should contain the `.git` directory.
gitDir("${rootProject.projectDir.parent}/.git")
}
version = semver.version
Using a custom Strategy (not currently supported by the configuration cache):
semver {
// All properties are optional, but it's a good idea to declare those that you would want
// to override with Gradle properties or environment variables, e.g. "overrideVersion" below
tagPrefix("v")
initialVersion("0.0.3")
findProperty("semver.overrideVersion")?.toString()?.let { overrideVersion(it) }
val semVerModifier = findProperty("semver.modifier")?.toString()
?.let { buildVersionModifier(it) } ?: { nextMinor() }
versionCalculatorStrategy(
FlatVersionCalculatorStrategy(semVerModifier)
)
// OR from scratch - this is rarely used now that Flat and Flow support anything - .*
versionCalculatorStrategy(
listOf(
BranchMatchingConfiguration("""^main$""".toRegex(), GitRef.Branch.Main, { "" to "" }, semVerModifier),
BranchMatchingConfiguration(
""".*""".toRegex(),
GitRef.Branch.Main,
{ preReleaseWithCommitCount(it, GitRef.Branch.Main, it.sanitizedNameWithoutPrefix()) to "" },
semVerModifier
),
)
)
}
PLEASE NOTE: the semver
extension should be declared before the semver
extension functions are used.
Not Supported
- Separate versions for subprojects - all subprojects are calculated with the same version