Nobody likes boring and repeatable tasks, that’s why we want to automate them as much as possible. One of such tasks is maintaining software version numbers.
When done manually it’s mundane task, often confusing and prone to errors.
At the beginning of each project there is always a issue of software version numbers. What version number schema to choose ? How to assign version numbers ? What about snapshots ?
Each mature enough project had that issue solved at some point. Sometimes it’s manually assigned by development team, sometimes it’s managed by the build system, sometimes taking Git commit hash or combination of any above methods.
Why not let our CI/CD handle that automatically? Today we’ll see how to automate version number generation using Git tags and TeamCity dynamic build numbers.
Our end-goal is to have automatically generated version numbers that:
- Do not repeat
- Uniquely identify each software build
- Generation process is independent of programming language or build system
- Requires as few human actions as possible (ideally once per release)
Git Setup
For automated versions generations we’ll use strategically placed Git tags. Different branching models will work but for sake of our example let’s consider the following model:
Where
develop
branch holds code for next planned releaserelease
branches are created from develop to finalize release preparation (QA, bug fixes etc…). Release branch will eventually hold released software versionhotfix
branches are created from release branches as needed- changes from release and
hotfix
branches are merged back to develop
Highlighted tags mark currently developed version. All commits that proceed tagged ones will belong to this version.
For “regular” development, tags are assigned to develop branch commits, right after release branch was spawned. This means that all commits after this belong to next version and all commits to release branch belong to release version.
Hot-fixes are tagged on their own branches to not interrupt regular development.
Creating Git tags:
git tag 1.0.0 git push && git push --tags
To summarize, in order to determine version that commit belongs to, simply follow the arrows backward. First tag you encounter, that’s the version commit belongs to.
To determine most recent, reachable tag use following command:
git describe --tags --abbrev=0 HEAD
that will return most recent tag that is reachable from current commit.
TeamCity Build Configuration
With Git tags setup we can proceed to TeamCity build plan configuration.
First thing we need to do for tag-based version number generation is to change Checkout policy setting to Do not use mirrors.
Without this setting TeamCity will use repository mirror and we won’t have access to Git tags information in our build.
With this thing out of the way we can configure Command Line build step with following content:
LAST_TAG=$(git describe --tags --abbrev=0 %build.vcs.number%) echo "Tag: ${LAST_TAG:-0.0.0}" echo "##teamcity[buildNumber '${LAST_TAG:-0.0.0}.%build.counter%']"
Where
LAST_TAG=$(git describe --tags --abbrev=0 %build.vcs.number%)
Sets LAST_TAG
variable to result of git describe
command output. The TeamCity built-in variable %build.vsc.number%
is replaced with current Git commit hash.
Next line prints LAST_TAG
content. If not set it’ll display 0.0.0
echo "Tag: ${LAST_TAG:-0.0.0}"
Finally
echo "##teamcity[buildNumber '${LAST_TAG:-0.0.0}.%build.counter%']"
use TeamCity built-in feature to dynamically update build number. TeamCity scans output logs and if ##teamcity[
is found it’ll be parsed and applied to current build settings. Read https://www.jetbrains.com/help/teamcity/service-messages.html for more details.
Here buildNumber
will be updated with ${LAST_TAG:-0.0.0}.%build.counter%'
. LAST_TAG
holds the value we got from Git tag and %build.counter%
is TeamCity built-in automatically incremented variable.
If we have other tags in our repository we can filter them out using --match
parameter like this:
LAST_TAG=$(git describe --abbrev=0 --match [0-9].[0-9].[0-9] %build.vcs.number% --tags)