Our continous integration server is TeamCity, a very good option when you need to handle builds on multiple platforms and you want to host your build server on your own (nothing stops you putting it to an elastic cloud instance or to an Azure VM though). Since we have read this blog post about TeamCity and GitHub pull request build integration, we desperately tried to implement it using Atlassian Stash (which is a correct GitHub Enterprise alternative).

The goal of course is to automatically build all pull requests on the build server and report this build status back to Stash to the pull request discussion page, which provides some level of confidence to the approver that merging this request won’t be a complete disaster (because build succeeded and all tests are still passing).

Internally, Github and Stash creates a ref for the pull request that is merged already with the specific branch, and this ref could be monitored by TeamCity using the following branch specification: +:refs/pull/(*/merge).

However, you cannot see this ref displayed anywhere as a branch in Stash web interface (because it is internal), and Mendhak build status reporter in TeamCity won’t update the status anywhere for the same reason. See this discussion about the problem. Long story short, this is the currently working solution:

  • Have your VCS root in TeamCity to monitor all refs, eg: use +:refs/heads/* in the branch specification
  • Use gitflow workflow, and don’t use forking worfklow. With gitflow your team members create branches in the same repo with a specific naming convention (bugfix/xyz and feature/xzy). Since TeamCity monitors all the refs in the VCS root, these branches will be recognized and built, while the forks won’t get noticed nor the pull requests from the forks.
  • Implement your build script in a way that it runs full integration (build, test, deploy) for only master or develop branches (see below), and only build/test for the feature/* or bugfix/* branches.
  • As a merge approver, you still will be able to see the last build status for the pull request (which is basically the last commit of the bugfix/ or feature/ branch merge candidate) on the Pull request discussion page in Stash.

Let’s see an example build script to do conditional deployments. For example, this one below is a bash script that runs on a Mac OS X agent. To make it work, you should define a system property parameter in TeamCity with the name system.git.branch, and its value should be %teamcity.build.branch%.

TeamCity system parameter

Now you can reference and evaluate this property in your bash script as shown below:

#!/bin/bash

# build your code...

# run your tests, import results, etc...

# only deploy if it is the master branch
if [ "%system.git.branch%" == "refs/heads/master" ]; then
  echo "running a master build, deploying to production environment..."
  # call your deployment script
fi

Note that the build will be executed and the build status in Stash will get updated (in the commit list for the branch) when a contributor pushes code to the branch, and not when the pull request is created. However, the build status is also displayed on the pull request page as shown below:

Stash build status

To support the same with fork workflow (or building only internal pull request refs), we either need to dig in to Stash build status reporting and create a hack, or wait for Atlassian until they make this feature available.