You are currently viewing Auto-generated version numbers with TeamCity and Git

Auto-generated version numbers with TeamCity and Git

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:

branching strategy

Where

  • develop branch holds code for next planned release
  • release branches are created from develop to finalize release preparation (QA, bug fixes etc…). Release branch will eventually hold released software version
  • hotfix 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.

checkout policy - 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%']"
command line TeamCity step

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)

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.