*** This version of Confluence is for testing only and contains a copy of content from June 29th 2026. No changes will be preserved. ***
Here is an example deploy.rb with a bunch of features specific to deploying Drupal on CUL servers. First, a list of all the commands:(You'll need to change all the TODO's)
| Code Block |
|---|
require 'capistrano/ext/multistage'
default_run_options[:shell] = '/bin/bash'
set :application, "features.library.cornell.edu" # TODO - name your application
# 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
#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, "local"
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.updatedb
drupal.drush.revert_features
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', 'drupal:drush:set_files_paths', 'drupal:drush:updatedb'
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 "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 << "chmod g+w #{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:"
|
| Code Block |
bash> cap -T cap deploy # Deploys your project. cap deploy:check abort "cap staging drupal:db:install # Test deployment dependencies. cap deploy:cleanup-s file=backup/production-snapshot-2013-10-25-13-17-23.sql" else puts "Moving database from #{filename} to # Clean up old releases. cap deploy:cold{stage}" upload_install(filename) end end desc "reload #database Deploysfrom and starts a `cold' application. cap deploy:create_symlinkprevious release" task :reload_previous, :roles => :app, :except => { :no_release => # Updates the symlink to the most recently deployed version. cap deploy:migratetrue } do previous_release_name = File.basename(previous_release) filename = make_backup_file_name(stage, previous_release_name) puts "reloading database from #{filename}" # Run the migrate rake task. cap deploy:migrations drush.load_drupal("#{deploy_to}/#{filename}") end end namespace :drush do desc #"Backup Deploy and run pending migrations. cap deploy:pendingthe database." task :backupdb, :on_error => :continue do run # Displays the commits since your last deploy. cap deploy:pending:diff "#{drush_cmd} -r #{app_path} sql-dump --result-file=#{deploy_to}/backup/release-drupal-db.sql" end #desc "Backup the database" # Displays the `diff' since your# last deploy. cap deploy:rollback we don't want to require backup_migrate task :backupdb_bam, :on_error => :continue do run "# Rolls back to a previous version and restarts. cap deploy:rollback:code {drush_cmd} -r #{app_path} bam-backup" end desc "Clear all caches" task :clear_all_caches, :roles => # Rolls back to the previously deployed version. cap deploy:setup :app, :except => { :no_release => true } do run "#{drush_cmd} -r #{app_path} --uri=#{drush_uri} cc all" end desc #"error Preparesmessage onefix or- moreundefined serversindex: for deployment. cap deploy:symlink<name, version>" # see https://drupal.org/node/1170362 task :fix_undefined_index, :roles => :app, :except => { :no_release => #true Deprecated} API. cap deploy:update do run "#{drush_cmd} -r #{app_path} vset --yes install_profile \"standard\"" run "#{drush_cmd} -r #{app_path} sql-query \"UPDATE system #SET Copiesstatus=1 your project and updates the symlink. cap deploy:update_code WHERE name='standard';\"" end desc "Revert all features to install the newest versions" # Copies your project to the remote servers. cap deploy:upload # Copy files to the currently deployed version. cap deploy:web:disable 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} Presentvset a maintenance page to visitors. cap deploy:web:enable--yes file_public_path sites/default/files" run "#{drush_cmd} -r #{app_path} vset --yes file_private_path #{deploy_to}/private_files" run "# Makes the application web-accessible again. cap drupal:db:backup {drush_cmd} -r #{app_path} vset --yes file_temporary_path sites/default/tmp" end desc "Set the site offline" task :site_offline, # backup the database cap drupal:db:grab:on_error => :continue do run "#{drush_cmd} -r #{app_path} vset site_offline 1 -y" run "# Grab local copy of remote database cap drupal:db:install {drush_cmd} -r #{app_path} vset maintenance_mode 1 -y" end desc "Set the # Install a specific local database snapshot cap drupal:db:install_latest site online" task :site_online, :on_error => :continue do run "# Install latest local database snapshot cap drupal:db:reload_previous{drush_cmd} -r #{app_path} vset site_offline 0 -y" run "#{drush_cmd} -r #{app_path} reloadvset databasemaintenance_mode from previous release cap drupal:drush:backupdb0 -y" end desc "Run # Backup the database. cap drupal:drush:clear_all_caches # Clear all caches cap drupal:drush:fix_undefined_index # error message fix - undefined index: <name, version> cap drupal:drush:revert_features # Revert all features to install the newest versions cap drupal:drush:set_files_paths # set the private_files & tmp path for the deploy environment cap drupal:drush:site_offline # Set the site offline cap drupal:drush:site_online # Set the site online cap drupal:drush:updatedb # Run Drupal database updates for new core/modules/themes if required. cap drupal:post_install_configuration # Get the user to run the Drupal install, then do final configuration cap drupal:site_setup # Initial remote setup for Drupal cap explore:check_mysql # check paths for mysql and mysqldump cap explore:find # find code for a task cap explore:locals # Local variables cap explore:testdujour # test du jour cap git:push_deploy_tag # Place release tag into Git and push it to origin server. cap invoke # Invoke a single command on the remote servers. cap local # Set the target stage to `local'. cap multistage:prepare # Stub out the staging config files. cap production # Set the target stage to `production'. cap shell # Begin an interactive Capistrano session. cap staging # Set the target stage to `staging'.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 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 end |