Deploying trunk or tags with capistrano

On my current project, we use capistrano for all of our deployments. In the simplest case, you tell capistrano the URL of your repository, and then you deploy by performing a checkout from this repository:

set :repository,  "http://www.example.com/svn/myproject/trunk"

However, putting this line in the capistrano recipe only lets you deploy from trunk. We needed the ability to deploy either the trunk or a tag of our choice. We generally deploy the trunk to development servers and the latest tag to staging and production servers.

We started out with something more complicated, but with the help of Jamis Buck on the capistrano mailing list, we came up with the following solution:

set :repository_root, "http://www.example.com/svn/myproject"
set(:tag) { Capistrano::CLI.ui.ask("Tag to deploy (or type 'trunk' to deploy from trunk): ") }
set(:repository) { (tag == "trunk") ? "#{repository_root}/trunk" : "#{repository_root}/tags/#{tag}" }

This deploy script will prompt the user to enter either a tag name or the word trunk. It will then use that variable to set the repository to the correct path. The output of a deploy will look like:

% cap deploy
  * executing `deploy'
...
  * executing `deploy:update'
 ** transaction: start
  * executing `deploy:update_code'
Tag to deploy (or type 'trunk' to deploy from trunk): trunk
  * executing "svn checkout -q  -r2210 http://www.example.com/svn/myproject/trunk /var/www/myproject/releases/20081029012754 && (echo 2210 > /var/www/myproject/releases/20081029012754/REVISION)"
...

Capistrano evaluates variables lazily. It will only fetch the repository variable if it needs it, which will then fetch the tag variable, which will then prompt the user. Therefore, if you run a command that does not require the repository, it will not prompt. For example, running the following command will not prompt the user:

cap deploy:restart

Next, we created a convenience rake task to deploy the trunk without prompting:

namespace :deploy do
  task :trunk do
    sh "cap -s tag=trunk deploy"
  end
end

This rake task sets the tag variable on the command line. Therefore, capistrano will not need to evaluate the set(:tag) command and will deploy the trunk without prompting.