1
0
Fork 0
mirror of https://github.com/capistrano/capistrano synced 2023-03-27 23:21:18 -04:00

make the compat script more general. Add some missing deploy tasks. Make sure on_rollback is safely ignored outside of a transaction

git-svn-id: http://svn.rubyonrails.org/rails/tools/capistrano@6468 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
Jamis Buck 2007-03-27 06:10:05 +00:00
parent 5a893823a2
commit 9a6d2fb7b6
6 changed files with 177 additions and 41 deletions

View file

@ -59,9 +59,11 @@ module Capistrano
# or any subsequent task then fails, and a transaction is active, this
# hook will be executed.
def on_rollback(&block)
if transaction?
task_call_frames.last.rollback = block
rollback_requests << task_call_frames.last
end
end
# Returns the TaskDefinition object for the currently executing task.
# It returns nil if there is no task being executed.

View file

@ -4,38 +4,20 @@
# Depends on the deployment system
load 'deploy'
desc "DEPRECATED: See deploy:pending:diff."
task :diff_from_last_deploy do
warn "[DEPRECATION] `diff_from_last_deploy' is deprecated. Use `deploy:pending:diff' instead."
deploy.pending.diff
end
map = { "diff_from_last_deploy" => "deploy:pending:diff",
"update" => "deploy:update",
"update_code" => "deploy:update_code",
"symlink" => "deploy:symlink",
"restart" => "deploy:restart",
"rollback" => "deploy:rollback",
"cleanup" => "deploy:cleanup",
"disable_web" => "deploy:web:disable",
"enable_web" => "deploy:web:enable" }
desc "DEPRECATED: See deploy:update."
task :update do
warn "[DEPRECATION] `update' is deprecated. Use `deploy:update' instead."
deploy.update
end
desc "DEPRECATED: See deploy:update_code."
task :update_code do
warn "[DEPRECATION] `update_code' is deprecated. Use `deploy:update_code' instead."
deploy.update_code
end
desc "DEPRECATED: See deploy:symlink."
task :symlink do
warn "[DEPRECATION] `symlink' is deprecated. Use `deploy:symlink' instead."
deploy.symlink
end
desc "DEPRECATED: See deploy:restart."
task :restart do
warn "[DEPRECATION] `restart' is deprecated. Use `deploy:restart' instead."
deploy.restart
end
desc "DEPRECATED: See deploy:rollback."
task :rollback do
warn "[DEPRECATION] `rollback' is deprecated. Use `deploy:rollback' instead."
deploy.rollback
map.each do |old, new|
desc "DEPRECATED: See #{new}."
eval "task(#{old.inspect}) do
warn \"[DEPRECATED] `#{old}' is deprecated. Use `#{new}' instead.\"
find_and_execute_task(#{new.inspect})
end"
end

View file

@ -18,9 +18,6 @@ set(:repository) { abort "Please specify the repository that houses your applic
set :scm, :subversion
set :deploy_via, :checkout
set :restart_via, :sudo
set :group_writable, true
set(:deploy_to) { "/u/apps/#{application}" }
set(:revision) { source.head } unless exists?(:revision)
@ -115,7 +112,7 @@ will lastly touch all assets in public/images, public/stylesheets, and \
public/javascripts so that the times are consistent (so that asset timestamping \
works)."
task :finalize_update, :except => { :no_release => true } do
run "chmod -R g+w #{release_path}" if group_writable
run "chmod -R g+w #{release_path}" if fetch(:group_writable, true)
run <<-CMD
rm -rf #{release_path}/log #{release_path}/public/system #{release_path}/tmp/pids &&
@ -174,7 +171,7 @@ you can indicate that restarts should use `run' instead by setting the \
set :restart_via, :run"
task :restart, :roles => :app, :except => { :no_release => true } do
invoke_command "#{current_path}/script/process/reaper", :via => restart_via
invoke_command "#{current_path}/script/process/reaper", :via => fetch(:restart_via, :sudo)
end
desc "Rolls back to the previously deployed version. The `current' symlink will \
@ -197,6 +194,67 @@ where you were, on the previously deployed version."
restart
end
desc "Run the migrate rake task. By default, it runs this in most recently \
deployed version of the app. However, you can specify a different release \
via the migrate_target variable, which must be one of :latest (for the \
default behavior), or :current (for the release indicated by the `current' \
symlink). latest release to be deployed with the update_code task). Strings will work \
for those values instead of symbols, too. You can also specify additional \
environment variables to pass to rake via the migrate_env variable. Finally, \
you can specify the full path to the rake executable by setting the rake \
variable. The defaults are:
set :rake, \"rake\"
set :rails_env, \"production\"
set :migrate_env, \"\"
set :migrate_target, :latest"
task :migrate, :roles => :db, :only => { :primary => true } do
rake = fetch(:rake, "rake")
rails_env = fetch(:rails_env, "production")
migrate_env = fetch(:migrate_env, "")
migrate_target = fetch(:migrate_target, :latest)
directory = case migrate_target.to_sym
when :current then current_path
when :latest then current_release
else raise ArgumentError, "unknown migration target #{migrate_target.inspect}"
end
run "cd #{directory}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate"
end
desc "Deploy and run pending migrations. This will work similarly to the \
`deploy' task, but will also run any pending migrations (via the `deploy:migrate' \
task) prior to updating the symlink. Note that the update in this case it is \
not atomic, and transactions are not used, because migrations are not \
guaranteed to be reversible."
task :with_migrations do
set :migrate_target, :latest
update_code
migrate
symlink
restart
end
desc "Clean up old releases. By default, the last 5 releases are kept on each \
server (though you can change this with the keep_releases variable). All other \
deployed revisions are removed from the servers. By default, this will use \
sudo to clean up the old releases, but if sudo is not available for your \
environment, set the :cleanup_via variable to :run instead."
task :cleanup, :except => { :no_release => true } do
count = fetch(:keep_releases, 5).to_i
if count >= releases.length
logger.important "no old releases to clean up"
else
logger.info "keeping #{count} of #{releases.length} deployed releases"
directories = (releases - releases.last(count)).map { |release|
File.join(releases_path, release) }.join(" ")
invoke_command "rm -rf #{directories}", :via => fetch(:cleanup_via, :sudo)
end
end
namespace :pending do
desc "Displays the `diff' since your last deploy. This is useful if you want \
to examine what changes are about to be deployed. Note that this might not be \
@ -212,4 +270,39 @@ not be supported on all SCM's."
system(source.log(current_revision))
end
end
namespace :web do
desc "Present a maintenance page to visitors. Disables your application's web \
interface by writing a \"maintenance.html\" file to each web server. The \
servers must be configured to detect the presence of this file, and if it is \
present, always display it instead of performing the request.
By default, the maintenance page will just say the site is down for \
\"maintenance\", and will be back \"shortly\", but you can customize the page \
by specifying the REASON and UNTIL environment variables:
$ cap deploy:web:disable BECAUSE=\"hardware upgrade\" \\
UNTIL=\"12pm Central Time\"
Further customization will require that you write your own task."
task :disable, :roles => :web, :except => { :no_release => true } do
require 'erb'
on_rollback { run "rm #{shared_path}/system/maintenance.html" }
reason = ENV['REASON']
deadline = ENV['UNTIL']
template = File.read(File.join(File.dirname(__FILE__), "templates", "maintenance.rhtml"))
result = ERB.new(template).result(binding)
put result, "#{shared_path}/system/maintenance.html", :mode => 0644
end
desc "Makes the application web-accessible again. Removes the \"maintenance.html\" \
page generated by deploy:web:disable, which (if your web servers are \
configured correclty) will make your application web-accessible again."
task :enable, :roles => :web, :except => { :no_release => true } do
run "rm #{shared_path}/system/maintenance.html"
end
end
end

View file

@ -0,0 +1,53 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>System down for maintenance</title>
<style type="text/css">
div.outer {
position: absolute;
left: 50%;
top: 50%;
width: 500px;
height: 300px;
margin-left: -260px;
margin-top: -150px;
}
.DialogBody {
margin: 0;
padding: 10px;
text-align: left;
border: 1px solid #ccc;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
background-color: #fff;
}
body { background-color: #fff; }
</style>
</head>
<body>
<div class="outer">
<div class="DialogBody" style="text-align: center;">
<div style="text-align: center; width: 200px; margin: 0 auto;">
<p style="color: red; font-size: 16px; line-height: 20px;">
The system is down for <%= reason ? reason : "maintenance" %>
as of <%= Time.now.strftime("%H:%M %Z") %>.
</p>
<p style="color: #666;">
It'll be back <%= deadline ? deadline : "shortly" %>.
</p>
</div>
</div>
</div>
</body>
</html>

View file

@ -43,7 +43,7 @@
as of <%= Time.now.strftime("%H:%M %Z") %>.
</p>
<p style="color: #666;">
It'll be back <%= deadline ? "by #{deadline}" : "shortly" %>.
It'll be back <%= deadline ? deadline : "shortly" %>.
</p>
</div>
</div>

View file

@ -103,6 +103,12 @@ class ConfigurationExecutionTest < Test::Unit::TestCase
@config.execute_task(first)
end
def test_on_rollback_should_have_no_effect_outside_of_transaction
aaa = new_task(@config, :aaa) { on_rollback { state[:rollback] = true }; raise "boom" }
assert_raises(RuntimeError) { @config.execute_task(aaa) }
assert_nil @config.state[:rollback]
end
def test_exception_raised_in_transaction_should_call_all_registered_rollback_handlers_in_reverse_order
aaa = new_task(@config, :aaa) { on_rollback { (state[:rollback] ||= []) << :aaa } }
bbb = new_task(@config, :bbb) { on_rollback { (state[:rollback] ||= []) << :bbb } }