read

Recently one of our test engineers asked if it would be possible to embed an increasing build number on "About" page in our mobile app. The purpose of such build number is to have a single reference point when reporting failed test suites or new problems in issue management tool (eg. Bugzilla). It is like a dogtag for software: useless for normal users and in daily use -- but much needed in case of emergency. And crashing software is an emergency.

At office we are not using any kind of continuous integration server (like Hudson CI) or separate build scripts for small projects. Such servers/scripts are usually configured to create build numbers themselves. For our purpose builds are prepared either by developer or tester in development environment and shared.

Build number requirements

Requirements for build numbers are simple:

  1. Build numbers must be unique.

    Using the same source code clone/checkout must give the same build number.

  2. Build numbers must reference a single point in project history.

    There can't be two different checkouts giving the same build number.

  3. Build numbers must be increasing.

    Consecutive and iterative builds must show progress is build numbers. It would be best if they are strictly sequential (N+1) but that's not a hard requirement. Usual approach to build numbers includes embedding date/hour and maybe some sequentially generated number. However if you have several builds a day then date-based number is insufficient. It does not identify uniquely a code version that was used to create the target. Thus you need something more specific.

Solution for Git

If Subversion is your VCS of choice, you are on the green. Just bring svnversion into play to get highest revision number from source files. You are done here.

Not so easy with Git.

Git uses SHA1 cryptographic hash to "describe" each of working tree states committed into repository. Using commit-sha as a build number will fail our requirement 3 completely. Given two commit-shas it is not possible to tell which is older and which is newer. We need more. Git scripts to the rescue. As a solution I have developed following post-merge script:

#!/bin/sh

DIR='./'
count=`git rev-list HEAD | wc -l | sed -e 's/ *//g' | xargs -n1 printf %04d` (1)
commit=`git show --abbrev-commit HEAD | grep '^commit' | sed -e 's/commit //'` (2)
buildno=b"$count.$commit"
echo $buildno > "${DIR}/subdir/version.txt"

Then contents of version.txt are simply inserted into our source code.

Detailed explanation

Lines (1) and (2) of the script are working horses; they generate parts of the build number. Line (1) lists all commit-shas that build up revision specified by HEAD (see rev-list), counts them and print as a 4 digit number. This fulfills our requirement 3.

Beware however that it is possible that two branches will have exactly the same number of commits even if they are totally different. Hence we need second part. Line (2) extracts HEAD commit-sha in abbreviated form (see show); that is instead of using 40-digit commit-sha show command evaluates shortest abbreviation possible that is still unique. Since Git is versioning whole tree states (and not single files) this fulfills our requirements 1 and 2. Combining both values we have unique and increasing build numbers.

Why a post-merge script?

Each developer/tester has to put this post-merge script into .git/hooks directory in his repository clone. I have tested different post- hooks and this one seemed best. It is executed when you pull from remote and source code has changed. In such case a merge must always occur: be it automatic merge, fast-forward or manual merge of conflicted code -- the version.txt is always properly generated.

Conclusion

This solution is not perfect. First, each developer has to manually copy post-merge script into git's hooks directory. Second, when you merge your own branches it will be executed so you have to remember not to give private builds for testing. Third, a fully automated solution should possibly generate a build number on the repository server after commit. And last, you should probably use proper build system that will do it automatically. However, it has proven to be sufficient for our needs. Let's hear your opinions and feedback in comments!

Blog Logo

Marcin Gil


Published

Image

When grass was greener

Rants on programming, photography, life and everything

Back to Overview