UPDATE: This post was written using Capistrano 1, which has since been superseded. An updated version—covering deployment of Drupal with Capistrano 2—can be found here.
It’s easy to get spoiled building rails apps. Tools like migrations make it so much easier to keep databases in sync, the way environments are managed helps considerably, and there’s Capistrano which makes rapid deployments a breeze. I miss those things when I have to work with other systems.
A few months back there had been a brief conversation about using capistrano with drupal and there are several blog posts ( like this one) about using it with PHP. So today, tired of resolving folders full of uploaded files, I decided to write a quick deploy.rb to use capistrano with drupal.
I’m presuming here that we already have capistrano installed locally, that a recent version of drupal is set up on the server, and that we’re deploying to the sites folder. Within that we’re going to end up with capistrano’s standard ‘releases’ and ‘shared’ folders, but in this case ‘current’ will actually take on the domain name of our app and shared will contain ‘files’ rather than the usual system, log and pids.
So here’s how it goes. Firstly we want to define some variables
set :application, "MyApp"
set :site_name, "www.example.com"
set :svn_user, "james.stewart"
# I like to have capistrano prompt me for the password.
# You can replace this with a standard assignment
set :svn_password, Proc.new { Capistrano::CLI.password_prompt("SVN Password for #{svn_user}: ") }
set :deploy_to, "/home/mp_app/public_html/sites"
role :web, "www.example.com"
So far, so much like a regular deploy.rb file. But if we want the app’s folder within sites to be called something other than ‘current’, we’ll need to add:
set :current_path, "#{deploy_to}/#{site_name}"
So that’s our configuration taken care of. Next we need to override a few of capistrano’s default tasks since we probably won’t be wanting to restart lighttpd/fastcgi, or change the permissions:
task :set_permissions, :except => { :no_release => true } do
# do nothing
end
task :restart do
# do nothing
end
task :deploy do
update
# restart
end
And finally we want to update the setup and update_code tasks to make use of our altered directory structure.
desc < { :no_release => true } do
on_rollback { delete release_path, :recursive => true }
source.checkout(self)
set_permissions
run < { :no_release => true } do
run < <-CMD
umask 02 &&
mkdir -p #{deploy_to} #{releases_path} #{shared_path} #{shared_path}/files
CMD
end
Now we can save this file somewhere appropriate and deploy new versions as simply as:
% cap -f /my/path/deploy.rb deploy
People using one sites folder to run multiple applications may need to make some further alterations so their ‘shared’ and ‘releases’ folders don’t clash, but I’ll leave those as an exercise for the comments or related blog entries!