| 1 |
require 'yaml' |
|---|
| 2 |
require 'capistrano/recipes/deploy/scm' |
|---|
| 3 |
require 'capistrano/recipes/deploy/strategy' |
|---|
| 4 |
|
|---|
| 5 |
def _cset(name, *args, &block) |
|---|
| 6 |
unless exists?(name) |
|---|
| 7 |
set(name, *args, &block) |
|---|
| 8 |
end |
|---|
| 9 |
end |
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
_cset(:application) { abort "Please specify the name of your application, set :application, 'foo'" } |
|---|
| 17 |
_cset(:repository) { abort "Please specify the repository that houses your application's code, set :repository, 'foo'" } |
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
_cset :scm, :subversion |
|---|
| 25 |
_cset :deploy_via, :checkout |
|---|
| 26 |
|
|---|
| 27 |
_cset(:deploy_to) { "/u/apps/#{application}" } |
|---|
| 28 |
_cset(:revision) { source.head } |
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 |
|
|---|
| 36 |
_cset(:source) { Capistrano::Deploy::SCM.new(scm, self) } |
|---|
| 37 |
_cset(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") { ` |
|---|
| 38 |
|
|---|
| 39 |
_cset(:strategy) { Capistrano::Deploy::Strategy.new(deploy_via, self) } |
|---|
| 40 |
|
|---|
| 41 |
_cset(:release_name) { set :deploy_timestamped, true; Time.now.utc.strftime("%Y%m%d%H%M%S") } |
|---|
| 42 |
|
|---|
| 43 |
_cset :version_dir, "releases" |
|---|
| 44 |
_cset :shared_dir, "shared" |
|---|
| 45 |
_cset :current_dir, "current" |
|---|
| 46 |
|
|---|
| 47 |
_cset(:releases_path) { File.join(deploy_to, version_dir) } |
|---|
| 48 |
_cset(:shared_path) { File.join(deploy_to, shared_dir) } |
|---|
| 49 |
_cset(:current_path) { File.join(deploy_to, current_dir) } |
|---|
| 50 |
_cset(:release_path) { File.join(releases_path, release_name) } |
|---|
| 51 |
|
|---|
| 52 |
_cset(:releases) { capture("ls -x #{releases_path}").split.sort } |
|---|
| 53 |
_cset(:current_release) { File.join(releases_path, releases.last) } |
|---|
| 54 |
_cset(:previous_release) { File.join(releases_path, releases[-2]) } |
|---|
| 55 |
|
|---|
| 56 |
_cset(:current_revision) { capture("cat #{current_path}/REVISION").chomp } |
|---|
| 57 |
_cset(:latest_revision) { capture("cat #{current_release}/REVISION").chomp } |
|---|
| 58 |
_cset(:previous_revision) { capture("cat #{previous_release}/REVISION").chomp } |
|---|
| 59 |
|
|---|
| 60 |
_cset(:run_method) { fetch(:use_sudo, true) ? :sudo : :run } |
|---|
| 61 |
|
|---|
| 62 |
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 |
|
|---|
| 67 |
_cset(:latest_release) { exists?(:deploy_timestamped) ? release_path : current_release } |
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
def depend(location, type, *args) |
|---|
| 76 |
deps = fetch(:dependencies, {}) |
|---|
| 77 |
deps[location] ||= {} |
|---|
| 78 |
deps[location][type] ||= [] |
|---|
| 79 |
deps[location][type] << args |
|---|
| 80 |
set :dependencies, deps |
|---|
| 81 |
end |
|---|
| 82 |
|
|---|
| 83 |
|
|---|
| 84 |
|
|---|
| 85 |
def with_env(name, value) |
|---|
| 86 |
saved, ENV[name] = ENV[name], value |
|---|
| 87 |
yield |
|---|
| 88 |
ensure |
|---|
| 89 |
ENV[name] = saved |
|---|
| 90 |
end |
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 |
|
|---|
| 98 |
namespace :deploy do |
|---|
| 99 |
desc <<-DESC |
|---|
| 100 |
Deploys your project. This calls both `update' and `restart'. Note that \ |
|---|
| 101 |
this will generally only work for applications that have already been deployed \ |
|---|
| 102 |
once. For a "cold" deploy, you'll want to take a look at the `deploy:cold' \ |
|---|
| 103 |
task, which handles the cold start specifically. |
|---|
| 104 |
DESC |
|---|
| 105 |
task :default do |
|---|
| 106 |
update |
|---|
| 107 |
restart |
|---|
| 108 |
end |
|---|
| 109 |
|
|---|
| 110 |
desc <<-DESC |
|---|
| 111 |
Prepares one or more servers for deployment. Before you can use any \ |
|---|
| 112 |
of the Capistrano deployment tasks with your project, you will need to \ |
|---|
| 113 |
make sure all of your servers have been prepared with `cap deploy:setup'. When \ |
|---|
| 114 |
you add a new server to your cluster, you can easily run the setup task \ |
|---|
| 115 |
on just that server by specifying the HOSTS environment variable: |
|---|
| 116 |
|
|---|
| 117 |
$ cap HOSTS=new.server.com deploy:setup |
|---|
| 118 |
|
|---|
| 119 |
It is safe to run this task on servers that have already been set up; it \ |
|---|
| 120 |
will not destroy any deployed revisions or data. |
|---|
| 121 |
DESC |
|---|
| 122 |
task :setup, :except => { :no_release => true } do |
|---|
| 123 |
dirs = [deploy_to, releases_path, shared_path] |
|---|
| 124 |
dirs += %w(system log pids).map { |d| File.join(shared_path, d) } |
|---|
| 125 |
run "umask 02 && mkdir -p #{dirs.join(' ')}" |
|---|
| 126 |
end |
|---|
| 127 |
|
|---|
| 128 |
desc <<-DESC |
|---|
| 129 |
Copies your project and updates the symlink. It does this in a \ |
|---|
| 130 |
transaction, so that if either `update_code' or `symlink' fail, all \ |
|---|
| 131 |
changes made to the remote servers will be rolled back, leaving your \ |
|---|
| 132 |
system in the same state it was in before `update' was invoked. Usually, \ |
|---|
| 133 |
you will want to call `deploy' instead of `update', but `update' can be \ |
|---|
| 134 |
handy if you want to deploy, but not immediately restart your application. |
|---|
| 135 |
DESC |
|---|
| 136 |
task :update do |
|---|
| 137 |
transaction do |
|---|
| 138 |
update_code |
|---|
| 139 |
symlink |
|---|
| 140 |
end |
|---|
| 141 |
end |
|---|
| 142 |
|
|---|
| 143 |
desc <<-DESC |
|---|
| 144 |
Copies your project to the remote servers. This is the first stage \ |
|---|
| 145 |
of any deployment; moving your updated code and assets to the deployment \ |
|---|
| 146 |
servers. You will rarely call this task directly, however; instead, you \ |
|---|
| 147 |
should call the `deploy' task (to do a complete deploy) or the `update' \ |
|---|
| 148 |
task (if you want to perform the `restart' task separately). |
|---|
| 149 |
|
|---|
| 150 |
You will need to make sure you set the :scm variable to the source \ |
|---|
| 151 |
control software you are using (it defaults to :subversion), and the \ |
|---|
| 152 |
:deploy_via variable to the strategy you want to use to deploy (it \ |
|---|
| 153 |
defaults to :checkout). |
|---|
| 154 |
DESC |
|---|
| 155 |
task :update_code, :except => { :no_release => true } do |
|---|
| 156 |
on_rollback { run "rm -rf #{release_path}; true" } |
|---|
| 157 |
strategy.deploy! |
|---|
| 158 |
finalize_update |
|---|
| 159 |
end |
|---|
| 160 |
|
|---|
| 161 |
desc <<-DESC |
|---|
| 162 |
[internal] Touches up the released code. This is called by update_code \ |
|---|
| 163 |
after the basic deploy finishes. It assumes a Rails project was deployed, \ |
|---|
| 164 |
so if you are deploying something else, you may want to override this \ |
|---|
| 165 |
task with your own environment's requirements. |
|---|
| 166 |
|
|---|
| 167 |
This task will make the release group-writable (if the :group_writable \ |
|---|
| 168 |
variable is set to true, which is the default). It will then set up \ |
|---|
| 169 |
symlinks to the shared directory for the log, system, and tmp/pids \ |
|---|
| 170 |
directories, and will lastly touch all assets in public/images, \ |
|---|
| 171 |
public/stylesheets, and public/javascripts so that the times are \ |
|---|
| 172 |
consistent (so that asset timestamping works). |
|---|
| 173 |
DESC |
|---|
| 174 |
task :finalize_update, :except => { :no_release => true } do |
|---|
| 175 |
run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true) |
|---|
| 176 |
|
|---|
| 177 |
|
|---|
| 178 |
|
|---|
| 179 |
run <<-CMD |
|---|
| 180 |
rm -rf |
|---|
| 181 |
mkdir -p |
|---|
| 182 |
mkdir -p |
|---|
| 183 |
ln -s |
|---|
| 184 |
ln -s |
|---|
| 185 |
ln -s |
|---|
| 186 |
CMD |
|---|
| 187 |
|
|---|
| 188 |
stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S") |
|---|
| 189 |
asset_paths = %w(images stylesheets javascripts).map { |p| "#{latest_release}/public/#{p}" }.join(" ") |
|---|
| 190 |
run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" } |
|---|
| 191 |
end |
|---|
| 192 |
|
|---|
| 193 |
desc <<-DESC |
|---|
| 194 |
Updates the symlink to the most recently deployed version. Capistrano works \ |
|---|
| 195 |
by putting each new release of your application in its own directory. When \ |
|---|
| 196 |
you deploy a new version, this task's job is to update the `current' symlink \ |
|---|
| 197 |
to point at the new version. You will rarely need to call this task \ |
|---|
| 198 |
directly; instead, use the `deploy' task (which performs a complete \ |
|---|
| 199 |
deploy, including `restart') or the 'update' task (which does everything \ |
|---|
| 200 |
except `restart'). |
|---|
| 201 |
DESC |
|---|
| 202 |
task :symlink, :except => { :no_release => true } do |
|---|
| 203 |
on_rollback { run "rm -f #{current_path}; ln -s #{previous_release} #{current_path}; true" } |
|---|
| 204 |
run "rm -f #{current_path} && ln -s #{latest_release} #{current_path}" |
|---|
| 205 |
end |
|---|
| 206 |
|
|---|
| 207 |
desc <<-DESC |
|---|
| 208 |
Copy files to the currently deployed version. This is useful for updating \ |
|---|
| 209 |
files piecemeal, such as when you need to quickly deploy only a single \ |
|---|
| 210 |
file. Some files, such as updated templates, images, or stylesheets, \ |
|---|
| 211 |
might not require a full deploy, and especially in emergency situations \ |
|---|
| 212 |
it can be handy to just push the updates to production, quickly. |
|---|
| 213 |
|
|---|
| 214 |
To use this task, specify the files and directories you want to copy as a \ |
|---|
| 215 |
comma-delimited list in the FILES environment variable. All directories \ |
|---|
| 216 |
will be processed recursively, with all files being pushed to the \ |
|---|
| 217 |
deployment servers. Any file or directory starting with a '.' character \ |
|---|
| 218 |
will be ignored. |
|---|
| 219 |
|
|---|
| 220 |
$ cap deploy:upload FILES=templates,controller.rb |
|---|
| 221 |
DESC |
|---|
| 222 |
task :upload, :except => { :no_release => true } do |
|---|
| 223 |
files = (ENV["FILES"] || ""). |
|---|
| 224 |
split(","). |
|---|
| 225 |
map { |f| f.strip!; File.directory?(f) ? Dir["#{f}/**/*"] : f }. |
|---|
| 226 |
flatten. |
|---|
| 227 |
reject { |f| File.directory?(f) || File.basename(f)[0] == ?. } |
|---|
| 228 |
|
|---|
| 229 |
abort "Please specify at least one file to update (via the FILES environment variable)" if files.empty? |
|---|
| 230 |
|
|---|
| 231 |
files.each do |file| |
|---|
| 232 |
content = File.open(file, "rb") { |f| f.read } |
|---|
| 233 |
put content, File.join(current_path, file) |
|---|
| 234 |
end |
|---|
| 235 |
end |
|---|
| 236 |
|
|---|
| 237 |
desc <<-DESC |
|---|
| 238 |
Restarts your application. This works by calling the script/process/reaper \ |
|---|
| 239 |
script under the current path. |
|---|
| 240 |
|
|---|
| 241 |
By default, this will be invoked via sudo as the `app' user. If \ |
|---|
| 242 |
you wish to run it as a different user, set the :runner variable to \ |
|---|
| 243 |
that user. If you are in an environment where you can't use sudo, set \ |
|---|
| 244 |
the :use_sudo variable to false: |
|---|
| 245 |
|
|---|
| 246 |
set :use_sudo, false |
|---|
| 247 |
DESC |
|---|
| 248 |
task :restart, :roles => :app, :except => { :no_release => true } do |
|---|
| 249 |
as = fetch(:runner, "app") |
|---|
| 250 |
via = fetch(:run_method, :sudo) |
|---|
| 251 |
invoke_command "#{current_path}/script/process/reaper", :via => via, :as => as |
|---|
| 252 |
end |
|---|
| 253 |
|
|---|
| 254 |
desc <<-DESC |
|---|
| 255 |
Rolls back to the previously deployed version. The `current' symlink will \ |
|---|
| 256 |
be updated to point at the previously deployed version, and then the \ |
|---|
| 257 |
current release will be removed from the servers. You'll generally want \ |
|---|
| 258 |
to call `rollback' instead, as it performs a `restart' as well. |
|---|
| 259 |
DESC |
|---|
| 260 |
task :rollback_code, :except => { :no_release => true } do |
|---|
| 261 |
if releases.length < 2 |
|---|
| 262 |
abort "could not rollback the code because there is no prior release" |
|---|
| 263 |
else |
|---|
| 264 |
run "rm #{current_path}; ln -s #{previous_release} #{current_path} && rm -rf #{current_release}" |
|---|
| 265 |
end |
|---|
| 266 |
end |
|---|
| 267 |
|
|---|
| 268 |
desc <<-DESC |
|---|
| 269 |
Rolls back to a previous version and restarts. This is handy if you ever \ |
|---|
| 270 |
discover that you've deployed a lemon; `cap rollback' and you're right \ |
|---|
| 271 |
back where you were, on the previously deployed version. |
|---|
| 272 |
DESC |
|---|
| 273 |
task :rollback do |
|---|
| 274 |
rollback_code |
|---|
| 275 |
restart |
|---|
| 276 |
end |
|---|
| 277 |
|
|---|
| 278 |
desc <<-DESC |
|---|
| 279 |
Run the migrate rake task. By default, it runs this in most recently \ |
|---|
| 280 |
deployed version of the app. However, you can specify a different release \ |
|---|
| 281 |
via the migrate_target variable, which must be one of :latest (for the \ |
|---|
| 282 |
default behavior), or :current (for the release indicated by the \ |
|---|
| 283 |
`current' symlink). Strings will work for those values instead of symbols, \ |
|---|
| 284 |
too. You can also specify additional environment variables to pass to rake \ |
|---|
| 285 |
via the migrate_env variable. Finally, you can specify the full path to the \ |
|---|
| 286 |
rake executable by setting the rake variable. The defaults are: |
|---|
| 287 |
|
|---|
| 288 |
set :rake, "rake" |
|---|
| 289 |
set :rails_env, "production" |
|---|
| 290 |
set :migrate_env, "" |
|---|
| 291 |
set :migrate_target, :latest |
|---|
| 292 |
DESC |
|---|
| 293 |
task :migrate, :roles => :db, :only => { :primary => true } do |
|---|
| 294 |
rake = fetch(:rake, "rake") |
|---|
| 295 |
rails_env = fetch(:rails_env, "production") |
|---|
| 296 |
migrate_env = fetch(:migrate_env, "") |
|---|
| 297 |
migrate_target = fetch(:migrate_target, :latest) |
|---|
| 298 |
|
|---|
| 299 |
directory = case migrate_target.to_sym |
|---|
| 300 |
when :current then current_path |
|---|
| 301 |
when :latest then current_release |
|---|
| 302 |
else raise ArgumentError, "unknown migration target #{migrate_target.inspect}" |
|---|
| 303 |
end |
|---|
| 304 |
|
|---|
| 305 |
run "cd #{directory}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate" |
|---|
| 306 |
end |
|---|
| 307 |
|
|---|
| 308 |
desc <<-DESC |
|---|
| 309 |
Deploy and run pending migrations. This will work similarly to the \ |
|---|
| 310 |
`deploy' task, but will also run any pending migrations (via the \ |
|---|
| 311 |
`deploy:migrate' task) prior to updating the symlink. Note that the \ |
|---|
| 312 |
update in this case it is not atomic, and transactions are not used, \ |
|---|
| 313 |
because migrations are not guaranteed to be reversible. |
|---|
| 314 |
DESC |
|---|
| 315 |
task :migrations do |
|---|
| 316 |
set :migrate_target, :latest |
|---|
| 317 |
update_code |
|---|
| 318 |
migrate |
|---|
| 319 |
symlink |
|---|
| 320 |
restart |
|---|
| 321 |
end |
|---|
| 322 |
|
|---|
| 323 |
desc <<-DESC |
|---|
| 324 |
Clean up old releases. By default, the last 5 releases are kept on each \ |
|---|
| 325 |
server (though you can change this with the keep_releases variable). All \ |
|---|
| 326 |
other deployed revisions are removed from the servers. By default, this \ |
|---|
| 327 |
will use sudo to clean up the old releases, but if sudo is not available \ |
|---|
| 328 |
for your environment, set the :use_sudo variable to false instead. |
|---|
| 329 |
DESC |
|---|
| 330 |
task :cleanup, :except => { :no_release => true } do |
|---|
| 331 |
count = fetch(:keep_releases, 5).to_i |
|---|
| 332 |
if count >= releases.length |
|---|
| 333 |
logger.important "no old releases to clean up" |
|---|
| 334 |
else |
|---|
| 335 |
logger.info "keeping #{count} of #{releases.length} deployed releases" |
|---|
| 336 |
|
|---|
| 337 |
directories = (releases - releases.last(count)).map { |release| |
|---|
| 338 |
File.join(releases_path, release) }.join(" ") |
|---|
| 339 |
|
|---|
| 340 |
invoke_command "rm -rf #{directories}", :via => run_method |
|---|
| 341 |
end |
|---|
| 342 |
end |
|---|
| 343 |
|
|---|
| 344 |
desc <<-DESC |
|---|
| 345 |
Test deployment dependencies. Checks things like directory permissions, \ |
|---|
| 346 |
necessary utilities, and so forth, reporting on the things that appear to \ |
|---|
| 347 |
be incorrect or missing. This is good for making sure a deploy has a \ |
|---|
| 348 |
chance of working before you actually run `cap deploy'. |
|---|
| 349 |
|
|---|
| 350 |
You can define your own dependencies, as well, using the `depend' method: |
|---|
| 351 |
|
|---|
| 352 |
depend :remote, :gem, "tzinfo", ">=0.3.3" |
|---|
| 353 |
depend :local, :command, "svn" |
|---|
| 354 |
depend :remote, :directory, "/u/depot/files" |
|---|
| 355 |
DESC |
|---|
| 356 |
task :check, :except => { :no_release => true } do |
|---|
| 357 |
dependencies = strategy.check! |
|---|
| 358 |
|
|---|
| 359 |
other = fetch(:dependencies, {}) |
|---|
| 360 |
other.each do |location, types| |
|---|
| 361 |
types.each do |type, calls| |
|---|
| 362 |
if type == :gem |
|---|
| 363 |
dependencies.send(location).command(fetch(:gem_command, "gem")).or("`gem' command could not be found. Try setting :gem_command") |
|---|
| 364 |
end |
|---|
| 365 |
|
|---|
| 366 |
calls.each do |args| |
|---|
| 367 |
dependencies.send(location).send(type, *args) |
|---|
| 368 |
end |
|---|
| 369 |
end |
|---|
| 370 |
end |
|---|
| 371 |
|
|---|
| 372 |
if dependencies.pass? |
|---|
| 373 |
puts "You appear to have all necessary dependencies installed" |
|---|
| 374 |
else |
|---|
| 375 |
puts "The following dependencies failed. Please check them and try again:" |
|---|
| 376 |
dependencies.reject { |d| d.pass? }.each do |d| |
|---|
| 377 |
puts "--> #{d.message}" |
|---|
| 378 |
end |
|---|
| 379 |
abort |
|---|
| 380 |
end |
|---|
| 381 |
end |
|---|
| 382 |
|
|---|
| 383 |
desc <<-DESC |
|---|
| 384 |
Deploys and starts a `cold' application. This is useful if you have not \ |
|---|
| 385 |
deployed your application before, or if your application is (for some \ |
|---|
| 386 |
other reason) not currently running. It will deploy the code, run any \ |
|---|
| 387 |
pending migrations, and then instead of invoking `deploy:restart', it will \ |
|---|
| 388 |
invoke `deploy:start' to fire up the application servers. |
|---|
| 389 |
DESC |
|---|
| 390 |
task :cold do |
|---|
| 391 |
update |
|---|
| 392 |
migrate |
|---|
| 393 |
start |
|---|
| 394 |
end |
|---|
| 395 |
|
|---|
| 396 |
desc <<-DESC |
|---|
| 397 |
Start the application servers. This will attempt to invoke a script \ |
|---|
| 398 |
in your application called `script/spin', which must know how to start \ |
|---|
| 399 |
your application listeners. For Rails applications, you might just have \ |
|---|
| 400 |
that script invoke `script/process/spawner' with the appropriate \ |
|---|
| 401 |
arguments. |
|---|
| 402 |
|
|---|
| 403 |
By default, the script will be executed via sudo as the `app' user. If \ |
|---|
| 404 |
you wish to run it as a different user, set the :runner variable to \ |
|---|
| 405 |
that user. If you are in an environment where you can't use sudo, set \ |
|---|
| 406 |
the :use_sudo variable to false. |
|---|
| 407 |
DESC |
|---|
| 408 |
task :start, :roles => :app do |
|---|
| 409 |
as = fetch(:runner, "app") |
|---|
| 410 |
via = fetch(:run_method, :sudo) |
|---|
| 411 |
invoke_command "sh -c 'cd #{current_path} && nohup script/spin'", :via => via, :as => as |
|---|
| 412 |
end |
|---|
| 413 |
|
|---|
| 414 |
desc <<-DESC |
|---|
| 415 |
Stop the application servers. This will call script/process/reaper for \ |
|---|
| 416 |
both the spawner process, and all of the application processes it has \ |
|---|
| 417 |
spawned. As such, it is fairly Rails specific and may need to be \ |
|---|
| 418 |
overridden for other systems. |
|---|
| 419 |
|
|---|
| 420 |
By default, the script will be executed via sudo as the `app' user. If \ |
|---|
| 421 |
you wish to run it as a different user, set the :runner variable to \ |
|---|
| 422 |
that user. If you are in an environment where you can't use sudo, set \ |
|---|
| 423 |
the :use_sudo variable to false. |
|---|
| 424 |
DESC |
|---|
| 425 |
task :stop, :roles => :app do |
|---|
| 426 |
as = fetch(:runner, "app") |
|---|
| 427 |
via = fetch(:run_method, :sudo) |
|---|
| 428 |
|
|---|
| 429 |
invoke_command "if [ -f #{current_path}/tmp/pids/dispatch.spawner.pid ]; then #{current_path}/script/process/reaper -a kill -r dispatch.spawner.pid; fi", :via => via, :as => as |
|---|
| 430 |
invoke_command "#{current_path}/script/process/reaper -a kill", :via => via, :as => as |
|---|
| 431 |
end |
|---|
| 432 |
|
|---|
| 433 |
namespace :pending do |
|---|
| 434 |
desc <<-DESC |
|---|
| 435 |
Displays the `diff' since your last deploy. This is useful if you want \ |
|---|
| 436 |
to examine what changes are about to be deployed. Note that this might \ |
|---|
| 437 |
not be supported on all SCM's. |
|---|
| 438 |
DESC |
|---|
| 439 |
task :diff, :except => { :no_release => true } do |
|---|
| 440 |
system(source.local.diff(current_revision)) |
|---|
| 441 |
end |
|---|
| 442 |
|
|---|
| 443 |
desc <<-DESC |
|---|
| 444 |
Displays the commits since your last deploy. This is good for a summary \ |
|---|
| 445 |
of the changes that have occurred since the last deploy. Note that this \ |
|---|
| 446 |
might not be supported on all SCM's. |
|---|
| 447 |
DESC |
|---|
| 448 |
task :default, :except => { :no_release => true } do |
|---|
| 449 |
from = source.next_revision(current_revision) |
|---|
| 450 |
system(source.local.log(from)) |
|---|
| 451 |
end |
|---|
| 452 |
end |
|---|
| 453 |
|
|---|
| 454 |
namespace :web do |
|---|
| 455 |
desc <<-DESC |
|---|
| 456 |
Present a maintenance page to visitors. Disables your application's web \ |
|---|
| 457 |
interface by writing a "maintenance.html" file to each web server. The \ |
|---|
| 458 |
servers must be configured to detect the presence of this file, and if \ |
|---|
| 459 |
it is present, always display it instead of performing the request. |
|---|
| 460 |
|
|---|
| 461 |
By default, the maintenance page will just say the site is down for \ |
|---|
| 462 |
"maintenance", and will be back "shortly", but you can customize the \ |
|---|
| 463 |
page by specifying the REASON and UNTIL environment variables: |
|---|
| 464 |
|
|---|
| 465 |
$ cap deploy:web:disable \\ |
|---|
| 466 |
REASON="hardware upgrade" \\ |
|---|
| 467 |
UNTIL="12pm Central Time" |
|---|
| 468 |
|
|---|
| 469 |
Further customization will require that you write your own task. |
|---|
| 470 |
DESC |
|---|
| 471 |
task :disable, :roles => :web, :except => { :no_release => true } do |
|---|
| 472 |
require 'erb' |
|---|
| 473 |
on_rollback { run "rm #{shared_path}/system/maintenance.html" } |
|---|
| 474 |
|
|---|
| 475 |
reason = ENV['REASON'] |
|---|
| 476 |
deadline = ENV['UNTIL'] |
|---|
| 477 |
|
|---|
| 478 |
template = File.read(File.join(File.dirname(__FILE__), "templates", "maintenance.rhtml")) |
|---|
| 479 |
result = ERB.new(template).result(binding) |
|---|
| 480 |
|
|---|
| 481 |
put result, "#{shared_path}/system/maintenance.html", :mode => 0644 |
|---|
| 482 |
end |
|---|
| 483 |
|
|---|
| 484 |
desc <<-DESC |
|---|
| 485 |
Makes the application web-accessible again. Removes the \ |
|---|
| 486 |
"maintenance.html" page generated by deploy:web:disable, which (if your \ |
|---|
| 487 |
web servers are configured correctly) will make your application \ |
|---|
| 488 |
web-accessible again. |
|---|
| 489 |
DESC |
|---|
| 490 |
task :enable, :roles => :web, :except => { :no_release => true } do |
|---|
| 491 |
run "rm #{shared_path}/system/maintenance.html" |
|---|
| 492 |
end |
|---|
| 493 |
end |
|---|
| 494 |
end |
|---|