Capistrano: Multistage
Posted by Jamis on July 23, 2007 @ 07:59 AM
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!

1. Ryan Allen said...
Ah, that is excellent. We’ll definitely be using this!
2. Gaius said...
And just days after I finally got my multistage deployment recipe working!
Thanks for the great work.
3. Ben Reubenstein said...
@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.
4. Tom Ward said...
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?
5. Jamis said...
Good point, Tom. I’ll see about making that more implicit in a future release.
6. Capify Newbie said...
The line
require ‘capistrano/ext/multistage’
goes in config/deploy.rb right?
7. joost said...
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>
8. Jamis said...
@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. :)
9. Kent said...
This is excellent. Thank you very much for this and all the work that goes into Capistrano and the tool in general. Top notch!
10. Ben said...
This looks interesting but I am not clear about what Multistage is or what problem this solves. Could someone elaborate a little?
Thanks!
11. Jamis said...
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.
12. nicholas a. evans said...
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.
13. Brian McQuay said...
This is exactly what I’ve been looking for. Thanks for that.
14. Hob said...
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.
15. Jamis said...
@Hob, that would work, just put the variable in a proc, so it is evaluated lazily:
set(:deploy_to) { ”/path/to/#{application}/#{stage}” }
16. David James said...
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…?
17. David James said...
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.
18. David James said...
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