Upgrade "Gotchas"

Capistrano 2.0 is just enough similar to, and yet different from, Capistrano 1.0 that you might find yourself getting bitten by things that you would expect to work. Here are a few things to watch for as you are upgrading your recipe files.

Capistrano extensions

All bets are off if you are using any Capistrano extensions (this includes the capistrano-ext gem). Until those extensions are updated to work with Capistrano 2, they may very well fail to load at all in your recipes.

The reason for this breakage is that Capistrano 2.0 has significantly refactored its internals. Whereas Capistrano 1.x had both a Configuration class and an Actor class, Capistrano 2.0 has merged the two into a single Configuration class. That change alone will probably break a good many extensions.

Task Namespaces

The deployment recipes are namespaced, now. This means that if you are explicitly overriding any of the deployment tasks, you'll need to change your recipe to include the namespace. For example, suppose you had overridden the "restart" task; you need to change your definition to look like this:

deploy.task :restart, :roles => :app do
  # ...
end

The namespace comes first, followed by a '.', and then the task definition. You're effectively calling the @task@ method of the @deploy@ namespace. If you prefer longhand, or if you need to redefine multiple tasks, you can also do it like this:

namespace :deploy do
  task :restart, :roles => :app do
    # ...
  end
end

Technically, the before and after hooks should be defined the same way, but to keep people from having to do too much work, Capistrano will search the parent namespaces for before and after hooks, too. So defining "after_update_code" in the top-level namespace will still work as an after hook for deploy:update_code.

Renamed Tasks

In addition to namespacing being added, several of the deployment tasks have been renamed. These include are:

Old nameNew name
diff_from_last_deploydeploy:pending:diff
cold_deploydeploy:cold
deploy_with_migrationsdeploy:migrations
disable_webdeploy:web:disable
enable_webdeploy:web:enable

There is a "compatibility" mode available, which aliases many of the new task-names by their original names. You can access this compatibility mode by adding the following line to the top of your Capfile:

load 'compat'

Alternatively, if you just want compatibility mode for one invocation, you can just invoke cap with the -f option, and specifying the "compat" recipes:

cap -f compat ...

At any time, you can pass the -T option to cap to see a list of all available tasks. This new format is much more concise and scannable than the older "cap show_tasks" format. Additionally, longer help may be available for many tasks; you can read it by passing the name of the task to the -e ("explain") switch:

cap -e deploy:cold
SCM Module Changes

Your SCM-of-choice may not be supported right now, even if it was originally supported in Capistrano 1.x. Even if your SCM is supported, it may behave slightly differently, accepting different variables than it used to. In many cases, where you might have had a "svn_username" variable, it is now a more general "scm_username".

No more "cap --apply-to"

With Capistrano 1.x, the easy way to make a new project play nicely with Capistrano was to use "cap -A", which set up the project with a set of tasks and such. It was very, very Rails-specific, and would not work unless you were applying Capistrano to a Rails project.

With Capistrano 2.0, there is now a separate "capify" script. It tries to be much more general, and will work with any kind of project. Just specify the path to the project you want capify, and it will take care of the rest.

The "delete" helper is gone

Your recipes may be using the "delete" helper to delete files or directories on the remote server. That helper has been removed; you should just use the "run" helper directly, calling the "rm" command.

No more "render" helper

The "render" helper was originally intended to be used for dynamically generating scripts and pages for use on the remote servers. After evaluating it a bit, though, it was really just a thin wrapper around ERB, and so in the interests of simplifying things, it got pulled.

If you need to do dynamic generation of scripts or pages from a template file, you should just call ERB directly:

require 'erb'
template = File.read(path_to_template_file)
result = ERB.new(template).result(binding)