The Buckblog

assorted ramblings by Jamis Buck

Capistrano: Multistage

23 July 2007 — 2-minute read

Some have long wanted a built-in way to support multiple-stages in Capistrano. I’ve been pushing back with the statement that it is easy enough to do in Capistrano manually. Still, I finally compromised and added a “multistage” component to the “capistrano-ext” plugin. You want staging support? Just “gem install capistrano-ext” and then:

1
require 'capistrano/ext/multistage'

Then, put your custom stage-specific code in config/deploy/staging.rb and config/deploy/production.rb. That’s it. You now deploy via “cap production deploy” and “cap staging deploy”.

If you have other stages you want to support, just set the :stages variable to an array of strings, naming each stage, prior to requiring the multistage module:

1
2
set :stages, %w(staging production testing)
require 'capistrano/ext/multistage'

By default, if you omit the stage when you execute a task, Capistrano will abort with a message saying that you need to specify a stage. If you’d rather just default to a stage, set the :default_stage variable:

1
2
3
set :stages, %w(staging production testing)
set :default_stage, "testing"
require 'capistrano/ext/multistage'

Then, when you do “cap deploy”, it will default to “cap testing deploy”.

Done!

Reader Comments

Ah, that is excellent. We’ll definitely be using this!

And just days after I finally got my multistage deployment recipe working!

Thanks for the great work.

@Gaius – Ha ha! Me too. I have a simple case statement that takes an argument to switch up some variables for deployment to various spots.

This looks excellent. Great work (as is the rest of Capistrano).

One question though: why the need to explicitly state available stages in the recipe? Can’t this be determined by the contents of config/deploy?

Good point, Tom. I’ll see about making that more implicit in a future release.

The line

require ‘capistrano/ext/multistage’

goes in config/deploy.rb right?

Brilliant. I know it’s easy to build by hand, but having this as an official gem makes it much easier to use. Opinionated, so to speak. <g>

@Newbie, yes.

@joost, that was part of the motivation, to provide a standard way of doing it, so that it was easier to troubleshoot issues that arise. :)

This is excellent. Thank you very much for this and all the work that goes into Capistrano and the tool in general. Top notch!

This looks interesting but I am not clear about what Multistage is or what problem this solves. Could someone elaborate a little?

Thanks!

Ben, if it doesn’t make sense to you, then you almost certainly don’t need it. :) The idea is that for your applications, you’ll have your production environment that is public facing. But then you might also have a “staging” environment, where you can test in-house, maybe have a few beta testers hit, and so forth, without exposing all those glorious new features (and nasty bugs) to your real users. The multistage module this post announces is one way to configure Capistrano so that you can deploy the same application to these different environments, with a minimum of duplication.

Thanks a lot for this! I had been rolling my own version of it, and yours is a fair bit more elegant.

Not only is this nice for multiple “staging” environments (qa, production, etc), but it’s also nice if you deploy the same app to different clients: client_one-qa, client_one-production, client_two-nightly, client_two-qa, client_two-production, etc.

This is exactly what I’ve been looking for. Thanks for that.

Very nice. I was just getting to the point where I was going to have to deal with just this issue. Thanks Jamis.

One question: Is there a method available in our recipes for determining the current stage? Might help DRY out lines like:

set :deploy_to, ”/path/to/#{application}”/#{stage}

Instead of having to put that line in each deployment file.

@Hob, that would work, just put the variable in a proc, so it is evaluated lazily:

set(:deploy_to) { ”/path/to/#{application}/#{stage}” }

Hi Jamis, thanks for this handy write up.

I think capistrano-ext needs a small tweak to remove a deprecation message with Cap 2.0.

`cap deploy:setup` gives: [DEPRECATION] Capistrano.configuration is deprecated. Use Capistrano::Configuration.instance instead

I believe the deprecation message comes from line 292 in monitor.rb in capistrano-ext-1.2.0. Not sure if/where there is a Trac for capistrano-ext…?

On my last comment, I think I spoke too soon—it looks like you specifically crafted the logic to work both with Cap 1.x and 2.0. :) I think I’ll just tweak my local source code to get rid of the deprecation message.

Ok, last post of the evening (crossing fingers). recipes.rb of mongrel_cluster-1.0.2 was the real culprit, not capistrano-ext. I changed the beginning of recipes.rb to look like this (borrowing some code from capistrano-ext, thanks!):

configuration = Capistrano::Configuration.respond_to?(:instance) ? Capistrano::Configuration.instance(:must_exist) : Capistrano.configuration(:must_exist)

configuration.load do set :mongrel_servers, 2 set :mongrel_port, 8000

-DJ