Here is an example deploy.rb with a bunch of features specific to deploying Drupal on CUL servers. (You'll need to change all the TODO's)
require 'capistrano/ext/multistage' set :application, "features.library.cornell.edu" # TODO - name your application default_run_options[:shell] = '/bin/bash' # based on: # http://guides.beanstalkapp.com/deployments/deploy-with-capistrano.html # http://www.58bits.com/blog/2013/03/23/deploying-drupal-with-capistrano # https://github.com/antistatique/capdrupal # TODO: list of modules to enable # drush pm-list | grep Enabled | grep -o '(.\+)' | grep -o '[^()]\+' | tr '\n' ' ' && echo "" set :enabled_modules, File.open("drupal_config/enabled_modules.txt", "r") { |file| file.read.split(" ") } # override these in production set :disabled_modules, File.open("drupal_config/disabled_modules.txt", "r") { |file| file.read.split(" ") } set :default_theme, File.open("drupal_config/default_theme.txt", "r") { |file| file.read.split(" ") } #SSH and PTY Options default_run_options[:pty] = true ssh_options[:forward_agent] = true set :use_sudo, false #set :port, 5144 #On Mac OS X ssh_options[:compression] = "none" #Application settings set :user, ENV['USER'] # can also come from ~/.caprc set :runner, ENV['USER'] # when sudo-ing use this user set :runner_group, "lib_web_dev_role" set :admin_runner, ENV['USER'] # when sudo-ing during :setup use this set :php_user, "apache" # user php runs as set :stages, ["local", "staging", "production"] # TODO - define different stages set :default_stage, "staging" set :keep_releases, 5 set :drush_cmd, "drush" set :scm, :git set :repository, "git@git.library.cornell.edu:features_test_library_cornell_edu.git" # TODO - your git repo here set :branch, "master" # prevent errors from missing javascripts,stylesheets,images directories set :normalize_asset_timestamps, false # now use the regular cap deploy instead of drupal #before 'deploy', 'deploy:drush:site_offline', 'drupal:db:backup', 'git:push_deploy_tag' before 'deploy' do git.push_deploy_tag drupal.drush.site_offline drupal.db.backup drupal.drush.site_online end #after 'deploy', 'drupal:link_filesystem', 'drupal:drush:set_files_paths', 'drupal:drush:updatedb', 'deploy:drush:site_online' after 'deploy' do drupal.link_filesystem drupal.drush.site_offline drupal.drush.set_files_paths drupal.drush.enabler(enabled_modules) drupal.drush.updatedb drupal.drush.disabler(disabled_modules) drupal.drush.revert_features drupal.drush.set_theme(default_theme) drupal.drush.clear_all_caches drupal.drush.site_online end after 'deploy:rollback' do drupal.link_filesystem drupal.drush.clear_all_caches drupal.drush.site_offline drupal.db.reload_previous drupal.drush.site_online end before 'drupal:db:grab', 'drupal:drush:site_offline', 'drupal:drush:clear_all_caches' after 'drupal:db:grab', 'drupal:drush:site_online' before 'drupal:db:install', 'drupal:drush:site_offline' after 'drupal:db:install', 'drupal:drush:set_files_paths', 'drupal:drush:clear_all_caches', 'drupal:drush:site_online' before 'drupal:db:install_latest', 'drupal:drush:site_offline' after 'drupal:db:install_latest', 'drupal:drush:set_files_paths', 'drupal:drush:clear_all_caches', 'drupal:drush:site_online' after 'deploy:setup', 'drupal:site_setup', 'deploy:update', 'drupal:link_filesystem', 'drupal:site_setup_permissions' after 'drupal:post_install_configuration' do drupal.drush.set_files_paths drupal.drush.enabler(enabled_modules) drupal.drush.updatedb drupal.drush.disabler(disabled_modules) drupal.drush.set_theme(default_theme) end after 'drupal:fix_undefined_index', 'drupal:drush:clear_all_caches' namespace :deploy do task :start do ; end task :stop do ; end task :restart, :roles => :app, :except => { :no_release => true } do #Place holder for app restart - in Ruby apps this would touch restart.txt. end end #Drupal application and project specific tasks. namespace :drupal do desc "Real list of modules to enable" task :read_enabled_modules do contents = File.open("config/enabled_modules.txt", "r") { |file| file.read } return contents end #desc "Perform a Drupal application deploy." # see before/after deploy above task :default, :roles => :app, :except => { :no_release => true } do site_offline clear_all_caches backupdb deploy.default link_filesystem set_files_paths updatedb site_online end desc "Initial remote setup for Drupal" task :site_setup, :roles => :app do commands = [] commands << "mkdir -p #{deploy_to}/backup" commands << "mkdir -p #{deploy_to}/cache" commands << "mkdir -p #{deploy_to}/files" commands << "mkdir -p #{deploy_to}/log" commands << "mkdir -p #{deploy_to}/private_files" commands << "mkdir -p #{deploy_to}/subsites" commands << "mkdir -p #{deploy_to}/tmp" run commands.join(' && ') if commands.any? end #desc "Set permissions for php to write to some directories" task :site_setup_permissions, :roles => :app do sudo "chown #{php_user} #{deploy_to}/backup" sudo "chown #{php_user} #{deploy_to}/cache" sudo "chown #{php_user} #{deploy_to}/files" sudo "chown #{php_user} #{deploy_to}/private_files" sudo "chown #{php_user} #{deploy_to}/tmp" sudo "chown #{php_user} #{deploy_to}/settings.php" end desc "Get the user to run the Drupal install, then do final configuration" task :post_install_configuration, :roles => :app do servers = find_servers_for_task(current_task) server = servers.first default_ans = 'yes' ans = Capistrano::CLI.ui.ask "Have you run http://#{server}/install.php? [#{default_ans}]" ans = default_ans if ans.empty? abort "Please install Drupal first" if ans != default_ans end #desc "This should not be run on its own - so comment out the description. # "Recreate the required Drupal symlinks to static directories and clear all caches." task :link_filesystem, :roles => :app, :except => { :no_release => true } do commands = [] commands << "if [ ! -f #{deploy_to}/settings.php ]; then cp #{app_path}/sites/default/default.settings.php #{deploy_to}/settings.php; fi" commands << "cat /dev/null > #{app_path}/.htaccess" commands << "mkdir -p #{app_path}/sites/default" commands << "ln -nfs #{share_path}/settings.php #{app_path}/sites/default/settings.php" commands << "ln -nfs #{share_path}/files #{app_path}/sites/default/files" commands << "ln -nfs #{share_path}/tmp #{app_path}/sites/default/tmp" commands << "ln -nfs #{share_path}/cache #{app_path}/cache" commands << "find #{app_path} -type d -print0 | xargs -0 chmod 755" commands << "find #{app_path} -type f -print0 | xargs -0 chmod 644" run commands.join(' && ') if commands.any? end namespace :db do desc "returns a stage and time stamped backup file name" def backup_file_name(stage) backup_time = release_name # use capistrano's variable %Y%m%d%H%M%S return make_backup_file_name(stage, backup_time) end def make_backup_file_name(stage, backup_time) filename = "backup/#{stage}-snapshot-#{backup_time}.sql" return filename end desc "gets the most recent database backup file with a given prefix" def latest_backup(backup_prefix) tmax = Time.at 0 latestfile = nil Dir.glob("backup/#{backup_prefix}-snapshot-*") do |filename| mt = File.mtime(filename) if mt > tmax tmax = mt latestfile = filename end end return latestfile end desc "upload and install database" def upload_install(filename) puts "uploading #{filename}" top.upload("#{filename}", "#{deploy_to}/#{filename}") puts "loading drupal with database" drush.load_drupal("#{deploy_to}/#{filename}") end desc "backup the database" task :backup, :roles => :app, :except => { :no_release => true } do backup_file = backup_file_name(stage) drush.dump_drupal(backup_file) puts "#{backup_file}" end desc "Grab local copy of remote database" # cap production drupal:db:grab task :grab, :roles => :app, :except => { :no_release => true } do backup_file = backup_file_name(stage) drush.dump_drupal(backup_file) puts "#{backup_file}" download "#{deploy_to}/#{backup_file}", "#{backup_file}" end desc "Install latest local database snapshot" # cap staging drupal:db:install_latest -s from=production task :install_latest, :roles => :app, :except => { :no_release => true } do set :source_stage, fetch(:from, '') if source_stage.empty? puts "useage:" abort "cap staging drupal:db:install_latest -s from=production" else filename = latest_backup(source_stage) if filename.nil? abort "first grab a copy of the datatbase: cap #{source_stage} drupal:db:grab" else puts "Moving database from #{source_stage} to #{stage}" upload_install(filename) end end end desc "Install a specific local database snapshot" # cap staging drupal:db:install -s file=backup/staging-snapshot-2013-10-25-13-17-23.sql task :install, :roles => :app, :except => { :no_release => true } do set :filename, fetch(:file, '') if filename.empty? puts "useage:" abort "cap staging drupal:db:install -s file=backup/production-snapshot-2013-10-25-13-17-23.sql" else puts "Moving database from #{filename} to #{stage}" upload_install(filename) end end desc "reload database from previous release" task :reload_previous, :roles => :app, :except => { :no_release => true } do previous_release_name = File.basename(previous_release) filename = make_backup_file_name(stage, previous_release_name) puts "reloading database from #{filename}" drush.load_drupal("#{deploy_to}/#{filename}") end end namespace :drush do desc "Backup the database." task :backupdb, :on_error => :continue do run "#{drush_cmd} -r #{app_path} sql-dump --result-file=#{deploy_to}/backup/release-drupal-db.sql" end #desc "Backup the database" # we don't want to require backup_migrate task :backupdb_bam, :on_error => :continue do run "#{drush_cmd} -r #{app_path} bam-backup" end desc "Clear all caches" task :clear_all_caches, :roles => :app, :except => { :no_release => true } do run "#{drush_cmd} -r #{app_path} --uri=#{drush_uri} cc all" end desc "error message fix - undefined index: <name, version>" # see https://drupal.org/node/1170362 task :fix_undefined_index, :roles => :app, :except => { :no_release => true } do run "#{drush_cmd} -r #{app_path} vset --yes install_profile \"standard\"" run "#{drush_cmd} -r #{app_path} sql-query \"UPDATE system SET status=1 WHERE name='standard';\"" end desc "Revert all features to install the newest versions" task :revert_features, :on_error => :continue do run "#{drush_cmd} -r #{app_path} features-revert-all -y" end desc "set the private_files & tmp path for the deploy environment" task :set_files_paths, :on_error => :continue do run "#{drush_cmd} -r #{app_path} vset --yes file_public_path sites/default/files" run "#{drush_cmd} -r #{app_path} vset --yes file_private_path #{deploy_to}/private_files" run "#{drush_cmd} -r #{app_path} vset --yes file_temporary_path sites/default/tmp" end desc "Set the site offline" task :site_offline, :on_error => :continue do run "#{drush_cmd} -r #{app_path} vset site_offline 1 -y" run "#{drush_cmd} -r #{app_path} vset maintenance_mode 1 -y" end desc "Set the site online" task :site_online, :on_error => :continue do run "#{drush_cmd} -r #{app_path} vset site_offline 0 -y" run "#{drush_cmd} -r #{app_path} vset maintenance_mode 0 -y" end desc "Run Drupal database updates for new core/modules/themes if required." task :updatedb, :on_error => :continue do run "#{drush_cmd} -r #{app_path} updatedb -y" end desc "backup the Drupal database to a timestamped file" def dump_drupal(filename) run "#{drush_cmd} -r #{app_path} sql-dump --result-file=#{deploy_to}/#{filename}" end desc "load the Drupal database from an sql dump" def load_drupal(filename) run "`#{drush_cmd} -r #{app_path} sql-connect` < #{filename}" end desc "enable an array of modules" def enabler(modules) run "#{drush_cmd} -r #{app_path} pm-enable -y #{modules.join(' ')}" end desc "disable an array of modules" def disabler(modules) run "#{drush_cmd} -r #{app_path} pm-disable -y #{modules.join(' ')}" end desc "set the default theme" def set_theme(theme) run "#{drush_cmd} -r #{app_path} vset theme_default #{theme}" end end end namespace :git do desc "Place release tag into Git and push it to origin server." task :push_deploy_tag do user = `git config --get user.name` email = `git config --get user.email` tag = "release_#{release_name}" if exists?(:stage) tag = "#{stage}_#{tag}" end puts `git tag #{tag} #{revision} -m "Deployed by #{user} <#{email}>"` puts `git push origin tag #{tag}` end end namespace :explore do desc "Local variables" task :locals, :on_error => :continue do local_variables.each {|var| puts "#{var} fetch(:#{var})"} puts "shared_path #{shared_path}" puts "stage #{stage}" puts "args #{args}" puts "release_name #{release_name}" puts "previous_revision #{previous_revision}" puts "current_revision #{current_revision}" # deploy.instance_variables.map do |var| # puts [var, deploy.instance_variable_get(var)].join(":") # end end desc "check paths for mysql and mysqldump" task :check_mysql, :on_error => :continue do puts "$PATH" run "echo $PATH" puts "Which mysql?" run "which mysql" puts "Which mysqldump?" run "which mysqldump" puts "connect statement:" run "#{drush_cmd} -r #{app_path} sql-connect" end desc "test du jour" task :testdujour, :on_error => :continue do mysqlcmd = %x[ echo `#{drush_cmd} -r #{app_path} sql-connect` ] puts "mysql command: #{mysqlcmd}" puts "current_path #{current_path}" puts "deploy_to #{deploy_to}" end desc "find code for a task" task :find, :on_error => :continue do # load all the tasks associated with the rails app Rails.application.load_tasks # get the source locations of actions called by a task task_name = 'deploy:cold' # fully scoped task name Rake.application[task_name].actions.map(&:source_location) end desc "try out enabler" task :tryout do modules = ['aaa', 'bbb', 'ccc', 'ploop'] drupal.drush.enabler(modules) end end