Hotfix releases with Travis CI

If your engineering organization uses a staged release process, it might be implemented like this:

Development work happens on the master branch, and periodically, releases are created and tagged. In order to reach the production environment, a release must be promoted from Dev to QA to Production. This could mean that release 0.1 is running on production while release 0.2 is being QAed, and the developers just finished 0.3 and are starting to work on new features for the next release.

With this release model, when a bug is discovered in production, a hotfix might be necessary, because otherwise you’d be promoting the bugfix along with a bunch of unreleased changes straight to production. Instead, typically, a branch is created from the tag that is running on production and the bug is fixed there. This hotfix release can go through the same promotion process. The theory is that this will be smoother because there are fewer changes.

One challenge with this approach is getting your continuous integration system to build an artifact in order to make the hotfix deployable. By default on Travis CI, only master branch builds run the deploy stage. If you don’t know the name of the branch to deploy ahead of time, you need to configure the deploy stage for all branches with a condition:

deploy:
  provider: script
  script: your_deploy_script.sh
  on: 
    branch: all_branches
    condition: $FOO = "awesome"

In order to get hotfix deployments working, I assumed I could use git rev-parse to check the name of the branch:

deploy:
  provider: script
  script: your_deploy_script.sh
  on: 
    branch: all_branches
    condition: $(git rev-parse --abbrev-ref HEAD) =~ ^(master|.*hotfix.*)$

However, this doesn’t work because of how Travis CI checks out your project to build. Travis CI clones your branch and then checks out the ref to build directly. This makes sense – it guarantees that Travis builds exactly what triggered it – but doesn’t work with rev-parse.

Fortunately, you can check the $TRAVIS_BRANCH environment variable and use that instead. But be careful, because pull request builds (which represent the merge of the branch with master) also set $TRAVIS_BRANCH.

Here’s a working solution for releasing master and branches containing hotfix:

deploy:
  provider: script
  script: your_deploy_script.sh
  on:
    all_branches: true
      # Deploy when this is Push build and the branch is either master or contains "hotfix"
      # NOTE: The check for TRAVIS_PULL_REQUEST is necessary because for a pull request build
      # TRAVIS_BRANCH will be the target of the pull request (typically master).
      # See: https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
      #      https://docs.travis-ci.com/user/deployment/#Conditional-Releases-with-on%3A
      condition: $TRAVIS_PULL_REQUEST = "false" && $TRAVIS_BRANCH =~ ^(master|.*hotfix.*)$

If you use this process with Travis CI, hopefully this will save you some time. Time you can use to switch to continuous deployment instead of rolling releases. Sorry, sore subject.