Tag Driven Release Automation

We use a CI system to do builds for our projects, currently TeamCity from Jetbrains. This is a great way to let your teammates know when your build has failed. Until now we have manually managed uploading and preparing new versions for distribution services like HockeyApp. It's not a major hassle, but when you're attempting to get a build out the door before heading home to your family, every minute counts!

To ensure my wife remains happy I have shaved a few precious minutes off the build process. TLDR: to release your build, create an annotated git tag and push. The CI takes care of the rest.

The key trick to doing this in TeamCity is to let it recognize tags as branches and add certain tags to the list of "branches" to monitor. This can be set up in the VCS Root:

This will of course cause all new tags you push to trigger a new build unless you modify your trigger. We have chosen to tag all releases using the following pattern; release-<version>. To trigger only on these tags, we limit the VCS trigger in the build configuration:

Finally, for reasons that will become clear below, we make the VCS checkout happen on the agent;

After the build and tests have finished, we add a step to deploy the package. Most services offer an API for this, and HockeyApp is no exception. Before we upload, we use the fact that the Git repo is in the current working directory and collect the text from the annotated tag:

lastTag=$(git tag | tail -n1)
annotatedMessage=$(git show -s $lastTag --format=%N | grep -v $lastTag | grep -v Tagger)

We use annotated tags to store the release notes since our commit messages are typically too technical for app testers, but you could just as easily use your commit log for this purpose if you like.

With that in place, we can embed the release notes in the upload of the binary;

set -x
curl \
 -F "status=2" \
 -F "notify=0" \
 -F "notes=$annotatedMessage" \
 -F "notes_type=0" \
 -F "[email protected]" \
 -F "[email protected]" \
 -H "X-HockeyAppToken: APP_TOKEN_HERE" \
    https://rink.hockeyapp.net/api/2/apps/APP_ID_HERE/app_versions/upload

Finally, to test the above CI configuration, just create an annotated tag locally (which will pop up an editor allowing you to write the tag annotation)

git tag -a release-1.0.7
git push origin release-1.0.7
git push --tags

and voila; the app will be built, tested and uploaded to your favorite distribution service and in your customer's hands while you're rushing home to change that freshly baked diaper.