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:
parent
5a893823a2
commit
9a6d2fb7b6
6 changed files with 177 additions and 41 deletions
|
@ -59,8 +59,10 @@ module Capistrano
|
|||
# or any subsequent task then fails, and a transaction is active, this
|
||||
# hook will be executed.
|
||||
def on_rollback(&block)
|
||||
task_call_frames.last.rollback = block
|
||||
rollback_requests << task_call_frames.last
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
53
lib/capistrano/recipes/deploy/templates/maintenance.rhtml
Normal file
53
lib/capistrano/recipes/deploy/templates/maintenance.rhtml
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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 } }
|
||||
|
|
Loading…
Reference in a new issue