Stuck? Need startup advice?

Deploying branches with Capistrano

Fb613ae74d247c05eba250f575e2c9b0?size=150
by Michiel Sikkes on September 02, 2013 with comments

We follow pretty much the same process as GitHub to deploy our apps. There are some differences and that is that we don't always use a CI server (we test ourselves) and we deploy with Capistrano.

Here's our process:

  • Create a pull request from your branch.
  • Deploy the branch using Capistrano.
  • Verify that the changes work.
  • Merge in the pull request.
  • Deploy the master branch using Capistrano.

How do we deploy branches with Capistrano? Here's how:

In our deploy.rb we specify that the branch can be overriden by the command line by typing something like:

BRANCH=my-feature-branch cap production deploy 

The single line that allows us to do this in deploy.rb is:

set :branch, ENV['BRANCH'] || "master"

When you don't pass a branch, it will default to deploying master.

There is one potential problem that can occur: This occurs when two people want to deploy the feature branch for verification at the same time. Here's how we solve that in Capistrano.

Developing and deploying multiple branches at time same time

Most of the time, we're working on 2-3 features at the same time and also release a bunch of bugfixes a few times a day. Because of this, it's possible that someone accidentally deploys his feature branch while I am still verifying my changes on production. This will result in confusion, because suddenly the button I just added will have magically disappeared one refresh later.

We've solved this by configuring Capistrano to fail with a message when someone tries to deploy a feature branch when another branch is already "active" on production. It works like this:

On every deploy, our Capistrano recipe creates a file BRANCH in the deployment directory on our servers. This file contains the name of the branch, and the username of the person that did the deploy:

$ cd /u/apps/intercity_production/current
$ cat BRANCH
server-logs:michiels

My Capistrano will then compare the branchname server-logs from this file with the branch that I am trying to deploy. If the branch name is different than the currently deployed branch AND different from "master" Capistrano will give me a message:

Sorry, joshua is already deploying his branch awesome-button.

As soon as joshua has merged in his branch into master and deployed it to production, I'm allowed to push my own branch.

Here is the snippet from our deploy.rb that takes care of this:

set :branch, ENV['BRANCH'] || "master"

if ENV['BRANCH']
  before "deploy", "deploy:check_branch"
end
after "deploy:finalize_update", "deploy:put_branch"

namespace :deploy do
  task :check_branch do
    current_branch_info = capture("cat #{current_path}/BRANCH; true")
    current_branch = current_branch_info.split(':')[0]
    deployer = current_branch_info.split(':')[1]

    if branch != 'master' && current_branch != 'master' && current_branch != branch
      puts "Sorry, #{deployer} is already deploying the feature #{current_branch}"
      exit
    end
  end

  task :put_branch do
    put "#{branch}:#{ENV['USER']}", "#{release_path}/BRANCH"
  end
end

I hope this post helps you deploy specific branches with Capistrano. Let me know if you have any questions.

comments powered by Disqus