capistrano 2.5.5 → 2.5.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +10 -0
- data/README.rdoc +90 -0
- data/Rakefile +1 -0
- data/bin/capify +24 -3
- data/capistrano.gemspec +8 -6
- data/lib/capistrano/cli/options.rb +2 -0
- data/lib/capistrano/command.rb +2 -2
- data/lib/capistrano/configuration/connections.rb +16 -12
- data/lib/capistrano/configuration/execution.rb +24 -13
- data/lib/capistrano/recipes/deploy.rb +11 -155
- data/lib/capistrano/recipes/deploy/scm/git.rb +7 -0
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +2 -2
- data/lib/capistrano/recipes/deploy/scm/perforce.rb +6 -1
- data/lib/capistrano/recipes/ext/rails-database-migrations.rb +50 -0
- data/lib/capistrano/recipes/ext/rails-shared-directories.rb +21 -0
- data/lib/capistrano/recipes/ext/web-disable-enable.rb +40 -0
- data/lib/capistrano/version.rb +1 -1
- data/test/command_test.rb +12 -12
- data/test/deploy/scm/git_test.rb +20 -3
- data/test/deploy/scm/mercurial_test.rb +5 -0
- metadata +12 -5
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 2.5.6 / 25 May 2009
|
2
|
+
|
3
|
+
* Clean the cached git repository [Graeme Mathieson]
|
4
|
+
* Fixes perforce issues reported at http://bit.ly/wt0es [Scott Johnson]
|
5
|
+
* Improved back-tick handling code in relation to the above.
|
6
|
+
* Removes rails-assumptions, more info see a freshly generated config/deploy.rb
|
7
|
+
* Fixes a Git issue when submodules update upstream. (via mailing list) [sneakin]
|
8
|
+
* Ensures that the deploy_to directory is chowned :user/:user during deploy:setup
|
9
|
+
* Capify now creates the config directory in directories without one.
|
10
|
+
|
1
11
|
== 2.5.5 / 24 Feb 2009
|
2
12
|
|
3
13
|
* Make sure role(:foo) actually declares an (empty) role for :foo, even without server arguments [Jamis Buck]
|
data/README.rdoc
CHANGED
@@ -5,6 +5,39 @@ Capistrano is a utility and framework for executing commands in parallel on mult
|
|
5
5
|
Capistrano was originally designed to simplify and automate deployment of web applications to distributed environments, and originally came bundled with a set of tasks designed for deploying Rails applications. The deployment tasks are now (as of Capistrano 2.0) opt-in and require clients to explicitly put
|
6
6
|
"load 'deploy'" in their recipes.
|
7
7
|
|
8
|
+
== 2.5.6 Warning
|
9
|
+
|
10
|
+
_+Warning+_: while every care has been taken to make sure you do not feel too much disruption from existing deploys when upgrading to 2.5.6 unless you alter your capfile (see "New Style Capification" towards the end of the readme for more) will require a couple more lines to keep compatibility with old recipes.
|
11
|
+
|
12
|
+
The changes in 2.5.6 include bug fixes, but importantly also remove a number of rails assumptions. This has been done both to ensure that people who aren't deploy Rails applications aren't put-off using Capistrano, and also that those of us that do use Rails have a choice about certain things. (starting our app, restarting it, stopping it, do we want cap to manage migrations, etc..)
|
13
|
+
|
14
|
+
As a result failure to read this document thoroughly could lead to problems, if you do install 2.5.6 and your recipe breaks, please either uninstall the gem and file a bug report (we will try to fix them within hours if received through our lighthouse app account.) or invoke cap in the following way to dictate which version you wish to use:
|
15
|
+
|
16
|
+
cap _2.5.5_ deploy
|
17
|
+
cap _2.5.5_ staging my:task:here
|
18
|
+
cap _2.5.5_ -vT
|
19
|
+
cap _2.5.6_ -vT
|
20
|
+
|
21
|
+
Please open issues on the bug tracer at http://capistrano.lighthouseapp.com/ if you experience problems
|
22
|
+
|
23
|
+
== Documentation
|
24
|
+
|
25
|
+
We know that documentation is something that really lets us down, that's why there is a repository for a handbook below, please open an issue on it if you would like something documented:
|
26
|
+
|
27
|
+
* http://github.com/leehambley/capistrano-handbook
|
28
|
+
|
29
|
+
If you prefer the wiki style of documentation, then please see our wiki
|
30
|
+
|
31
|
+
* http://wiki.capify.org
|
32
|
+
|
33
|
+
Due to a failure of MySQL with PHP, searches shorter than three characters are all but ignored, we're going to rectify this, but in the meantime, please do what you can, tickets opened on the handbook for the wiki will be answered too, so please let us know if you don't find something you needed.
|
34
|
+
|
35
|
+
We take bug reports via lighthouse app, you can find that page here:
|
36
|
+
|
37
|
+
* http://capistrano.lighthouseapp.com
|
38
|
+
|
39
|
+
More documentation is on the way, if in doubt try opening the recipes that ship with capistrano.
|
40
|
+
|
8
41
|
== DEPENDENCIES
|
9
42
|
|
10
43
|
* Net::SSH v2 (http://net-ssh.rubyforge.org)
|
@@ -40,6 +73,63 @@ Use the +cap+ script as follows:
|
|
40
73
|
|
41
74
|
By default, the script will look for a file called one of +capfile+ or +Capfile+. The +someaction+ text indicates which task to execute. You can do "cap -h" to see all the available options and "cap -T" to see all the available tasks.
|
42
75
|
|
76
|
+
== Capistrano Edge
|
77
|
+
|
78
|
+
If you want to try Capistrano code that hasn't been formerly released yet, this repository now includes a gemspec that should build what you need, here's how to get a copy:
|
79
|
+
|
80
|
+
git clone git://github.com/capistrano/capistrano.git capistrano-capistrano
|
81
|
+
cd capistrano-capsitrano
|
82
|
+
gem build capistrano.gemspec
|
83
|
+
sudo gem install capistrano-*.gem
|
84
|
+
|
85
|
+
This will install the most recent version of capistrano and make it available for both cap, and capify.
|
86
|
+
|
87
|
+
We recommend that you capify a new test application, as the resulting files are different to previous versions.
|
88
|
+
|
89
|
+
If you have multiple versions of capistrano (or indeed any gem with a binary) installed, you can call `cap` like so to specify which version to use:
|
90
|
+
|
91
|
+
cap _2.5.5_ deploy
|
92
|
+
cap _2.5.6_ deploy:setup
|
93
|
+
|
94
|
+
== New Style Capification
|
95
|
+
|
96
|
+
When calling `capify` on a new application, the result will look something like the following, this is a big change to previous versions, please take this as a warning and read the following thoroughly:
|
97
|
+
|
98
|
+
set :application, "set your application name here"
|
99
|
+
set :repository, "set your repository location here"
|
100
|
+
|
101
|
+
# If you have previously been relying upon the code to start, stop
|
102
|
+
# and restart your mongrel application, or if you rely on the database
|
103
|
+
# migration code, please uncomment the lines you require below
|
104
|
+
|
105
|
+
# If you are deploying a rails app you probably need these:
|
106
|
+
|
107
|
+
# load 'ext/rails-database-migrations.rb'
|
108
|
+
# load 'ext/rails-shared-directories.rb'
|
109
|
+
|
110
|
+
# There are also new utility libaries shipped with the core these
|
111
|
+
# include the following, please see individual files for more
|
112
|
+
# documentation, or run `cap -vT` with the following lines commented
|
113
|
+
# out to see what they make available.
|
114
|
+
|
115
|
+
# load 'ext/spinner.rb' # Designed for use with script/spin
|
116
|
+
# load 'ext/passenger-mod-rails.rb' # Restart task for use with mod_rails
|
117
|
+
# load 'ext/web-disable-enable.rb' # Gives you web:disable and web:enable
|
118
|
+
|
119
|
+
# If you aren't deploying to /u/apps/\#{application} on the target
|
120
|
+
# servers (which is the default), you can specify the actual location
|
121
|
+
# via the :deploy_to variable:
|
122
|
+
# set :deploy_to, "/var/www/\#{application}"
|
123
|
+
|
124
|
+
# If you aren't using Subversion to manage your source code, specify
|
125
|
+
# your SCM below:
|
126
|
+
# set :scm, :subversion
|
127
|
+
# see a full list by running "gem contents capistrano | grep 'scm/'"
|
128
|
+
|
129
|
+
role :web, "your web-server here"
|
130
|
+
|
131
|
+
When adding or removing extensions, where you have previously tested a `deploy:setup` we recommend that you perform another, especially for example when adding the rails-shared-directory code.
|
132
|
+
|
43
133
|
== LICENSE:
|
44
134
|
|
45
135
|
(The MIT License)
|
data/Rakefile
CHANGED
data/bin/capify
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'optparse'
|
4
|
+
require 'fileutils'
|
4
5
|
|
5
6
|
OptionParser.new do |opts|
|
6
7
|
opts.banner = "Usage: #{File.basename($0)} [path]"
|
@@ -45,6 +46,24 @@ files = {
|
|
45
46
|
set :application, "set your application name here"
|
46
47
|
set :repository, "set your repository location here"
|
47
48
|
|
49
|
+
# If you have previously been relying upon the code to start, stop
|
50
|
+
# and restart your mongrel application, or if you rely on the database
|
51
|
+
# migration code, please uncomment the lines you require below
|
52
|
+
|
53
|
+
# If you are deploying a rails app you probably need these:
|
54
|
+
|
55
|
+
# load 'ext/rails-database-migrations.rb'
|
56
|
+
# load 'ext/rails-shared-directories.rb'
|
57
|
+
|
58
|
+
# There are also new utility libaries shipped with the core these
|
59
|
+
# include the following, please see individual files for more
|
60
|
+
# documentation, or run `cap -vT` with the following lines commented
|
61
|
+
# out to see what they make available.
|
62
|
+
|
63
|
+
# load 'ext/spinner.rb' # Designed for use with script/spin
|
64
|
+
# load 'ext/passenger-mod-rails.rb' # Restart task for use with mod_rails
|
65
|
+
# load 'ext/web-disable-enable.rb' # Gives you web:disable and web:enable
|
66
|
+
|
48
67
|
# If you aren't deploying to /u/apps/\#{application} on the target
|
49
68
|
# servers (which is the default), you can specify the actual location
|
50
69
|
# via the :deploy_to variable:
|
@@ -53,10 +72,10 @@ files = {
|
|
53
72
|
# If you aren't using Subversion to manage your source code, specify
|
54
73
|
# your SCM below:
|
55
74
|
# set :scm, :subversion
|
75
|
+
# see a full list by running "gem contents capistrano | grep 'scm/'"
|
56
76
|
|
57
|
-
role :app, "your app-server here"
|
58
77
|
role :web, "your web-server here"
|
59
|
-
|
78
|
+
|
60
79
|
FILE
|
61
80
|
}
|
62
81
|
|
@@ -68,7 +87,9 @@ files.each do |file, content|
|
|
68
87
|
elsif File.exists?(file.downcase)
|
69
88
|
warn "[skip] `#{file.downcase}' exists, which could conflict with `#{file}'"
|
70
89
|
elsif !File.exists?(File.dirname(file))
|
71
|
-
|
90
|
+
FileUtils.mkdir(File.dirname(file))
|
91
|
+
retry
|
92
|
+
warn "[skip] directory `#{File.dirname(file)}' did not exist, created."
|
72
93
|
else
|
73
94
|
puts "[add] writing `#{file}'"
|
74
95
|
File.open(file, "w") { |f| f.write(content) }
|
data/capistrano.gemspec
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{capistrano}
|
3
|
-
s.version = "2.5.
|
4
|
-
|
3
|
+
s.version = "2.5.6"
|
5
4
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
6
|
-
s.authors = ["Jamis Buck"]
|
5
|
+
s.authors = ["Jamis Buck", "Lee Hambley"]
|
7
6
|
s.date = %q{2009-02-24}
|
8
7
|
s.description = %q{Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH.}
|
9
|
-
s.email = %q{
|
8
|
+
s.email = %q{lee.hambley@gmail.com}
|
10
9
|
s.executables = ["cap", "capify"]
|
11
10
|
s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/capistrano/callback.rb", "lib/capistrano/cli/execute.rb", "lib/capistrano/cli/help.rb", "lib/capistrano/cli/help.txt", "lib/capistrano/cli/options.rb", "lib/capistrano/cli/ui.rb", "lib/capistrano/cli.rb", "lib/capistrano/command.rb", "lib/capistrano/configuration/actions/file_transfer.rb", "lib/capistrano/configuration/actions/inspect.rb", "lib/capistrano/configuration/actions/invocation.rb", "lib/capistrano/configuration/callbacks.rb", "lib/capistrano/configuration/connections.rb", "lib/capistrano/configuration/execution.rb", "lib/capistrano/configuration/loading.rb", "lib/capistrano/configuration/namespaces.rb", "lib/capistrano/configuration/roles.rb", "lib/capistrano/configuration/servers.rb", "lib/capistrano/configuration/variables.rb", "lib/capistrano/configuration.rb", "lib/capistrano/errors.rb", "lib/capistrano/extensions.rb", "lib/capistrano/logger.rb", "lib/capistrano/processable.rb", "lib/capistrano/recipes/compat.rb", "lib/capistrano/recipes/deploy/dependencies.rb", "lib/capistrano/recipes/deploy/local_dependency.rb", "lib/capistrano/recipes/deploy/remote_dependency.rb", "lib/capistrano/recipes/deploy/scm/accurev.rb", "lib/capistrano/recipes/deploy/scm/base.rb", "lib/capistrano/recipes/deploy/scm/bzr.rb", "lib/capistrano/recipes/deploy/scm/cvs.rb", "lib/capistrano/recipes/deploy/scm/darcs.rb", "lib/capistrano/recipes/deploy/scm/git.rb", "lib/capistrano/recipes/deploy/scm/mercurial.rb", "lib/capistrano/recipes/deploy/scm/none.rb", "lib/capistrano/recipes/deploy/scm/perforce.rb", "lib/capistrano/recipes/deploy/scm/subversion.rb", "lib/capistrano/recipes/deploy/scm.rb", "lib/capistrano/recipes/deploy/strategy/base.rb", "lib/capistrano/recipes/deploy/strategy/checkout.rb", "lib/capistrano/recipes/deploy/strategy/copy.rb", "lib/capistrano/recipes/deploy/strategy/export.rb", "lib/capistrano/recipes/deploy/strategy/remote.rb", "lib/capistrano/recipes/deploy/strategy/remote_cache.rb", "lib/capistrano/recipes/deploy/strategy.rb", "lib/capistrano/recipes/deploy/templates/maintenance.rhtml", "lib/capistrano/recipes/deploy.rb", "lib/capistrano/recipes/standard.rb", "lib/capistrano/recipes/templates/maintenance.rhtml", "lib/capistrano/recipes/upgrade.rb", "lib/capistrano/role.rb", "lib/capistrano/server_definition.rb", "lib/capistrano/shell.rb", "lib/capistrano/ssh.rb", "lib/capistrano/task_definition.rb", "lib/capistrano/transfer.rb", "lib/capistrano/version.rb", "lib/capistrano.rb", "README.rdoc"]
|
12
|
-
s.files = ["bin/cap", "bin/capify", "CHANGELOG.rdoc", "examples/sample.rb", "lib/capistrano/callback.rb", "lib/capistrano/cli/execute.rb", "lib/capistrano/cli/help.rb", "lib/capistrano/cli/help.txt", "lib/capistrano/cli/options.rb", "lib/capistrano/cli/ui.rb", "lib/capistrano/cli.rb", "lib/capistrano/command.rb", "lib/capistrano/configuration/actions/file_transfer.rb", "lib/capistrano/configuration/actions/inspect.rb", "lib/capistrano/configuration/actions/invocation.rb", "lib/capistrano/configuration/callbacks.rb", "lib/capistrano/configuration/connections.rb", "lib/capistrano/configuration/execution.rb", "lib/capistrano/configuration/loading.rb", "lib/capistrano/configuration/namespaces.rb", "lib/capistrano/configuration/roles.rb", "lib/capistrano/configuration/servers.rb", "lib/capistrano/configuration/variables.rb", "lib/capistrano/configuration.rb", "lib/capistrano/errors.rb",
|
11
|
+
s.files = ["bin/cap", "bin/capify", "CHANGELOG.rdoc", "examples/sample.rb", "lib/capistrano/callback.rb", "lib/capistrano/cli/execute.rb", "lib/capistrano/cli/help.rb", "lib/capistrano/cli/help.txt", "lib/capistrano/cli/options.rb", "lib/capistrano/cli/ui.rb", "lib/capistrano/cli.rb", "lib/capistrano/command.rb", "lib/capistrano/configuration/actions/file_transfer.rb", "lib/capistrano/configuration/actions/inspect.rb", "lib/capistrano/configuration/actions/invocation.rb", "lib/capistrano/configuration/callbacks.rb", "lib/capistrano/configuration/connections.rb", "lib/capistrano/configuration/execution.rb", "lib/capistrano/configuration/loading.rb", "lib/capistrano/configuration/namespaces.rb", "lib/capistrano/configuration/roles.rb", "lib/capistrano/configuration/servers.rb", "lib/capistrano/configuration/variables.rb", "lib/capistrano/configuration.rb", "lib/capistrano/errors.rb",
|
12
|
+
"lib/capistrano/extensions.rb", "lib/capistrano/logger.rb", "lib/capistrano/processable.rb", "lib/capistrano/recipes/compat.rb", "lib/capistrano/recipes/deploy/dependencies.rb", "lib/capistrano/recipes/deploy/local_dependency.rb", "lib/capistrano/recipes/deploy/remote_dependency.rb", "lib/capistrano/recipes/deploy/scm/accurev.rb", "lib/capistrano/recipes/deploy/scm/base.rb", "lib/capistrano/recipes/deploy/scm/bzr.rb", "lib/capistrano/recipes/deploy/scm/cvs.rb", "lib/capistrano/recipes/deploy/scm/darcs.rb", "lib/capistrano/recipes/deploy/scm/git.rb", "lib/capistrano/recipes/deploy/scm/mercurial.rb", "lib/capistrano/recipes/deploy/scm/none.rb", "lib/capistrano/recipes/deploy/scm/perforce.rb", "lib/capistrano/recipes/deploy/scm/subversion.rb", "lib/capistrano/recipes/deploy/scm.rb", "lib/capistrano/recipes/deploy/strategy/base.rb", "lib/capistrano/recipes/deploy/strategy/checkout.rb", "lib/capistrano/recipes/deploy/strategy/copy.rb", "lib/capistrano/recipes/deploy/strategy/export.rb", "lib/capistrano/recipes/deploy/strategy/remote.rb", "lib/capistrano/recipes/deploy/strategy/remote_cache.rb", "lib/capistrano/recipes/deploy/strategy.rb", "lib/capistrano/recipes/deploy/templates/maintenance.rhtml", "lib/capistrano/recipes/deploy.rb",
|
13
|
+
"lib/capistrano/recipes/ext/rails-shared-directories.rb",
|
14
|
+
"lib/capistrano/recipes/ext/rails-database-migrations.rb", "lib/capistrano/recipes/ext/web-disable-enable.rb", "lib/capistrano/recipes/standard.rb", "lib/capistrano/recipes/templates/maintenance.rhtml", "lib/capistrano/recipes/upgrade.rb", "lib/capistrano/role.rb", "lib/capistrano/server_definition.rb", "lib/capistrano/shell.rb", "lib/capistrano/ssh.rb", "lib/capistrano/task_definition.rb", "lib/capistrano/transfer.rb", "lib/capistrano/version.rb", "lib/capistrano.rb", "Rakefile", "README.rdoc", "setup.rb", "test/cli/execute_test.rb", "test/cli/help_test.rb", "test/cli/options_test.rb", "test/cli/ui_test.rb", "test/cli_test.rb", "test/command_test.rb", "test/configuration/actions/file_transfer_test.rb", "test/configuration/actions/inspect_test.rb", "test/configuration/actions/invocation_test.rb", "test/configuration/callbacks_test.rb", "test/configuration/connections_test.rb", "test/configuration/execution_test.rb", "test/configuration/loading_test.rb", "test/configuration/namespace_dsl_test.rb", "test/configuration/roles_test.rb", "test/configuration/servers_test.rb", "test/configuration/variables_test.rb", "test/configuration_test.rb", "test/deploy/local_dependency_test.rb", "test/deploy/remote_dependency_test.rb", "test/deploy/scm/accurev_test.rb", "test/deploy/scm/base_test.rb", "test/deploy/scm/git_test.rb", "test/deploy/scm/mercurial_test.rb", "test/deploy/strategy/copy_test.rb", "test/extensions_test.rb", "test/fixtures/cli_integration.rb", "test/fixtures/config.rb", "test/fixtures/custom.rb", "test/logger_test.rb", "test/role_test.rb", "test/server_definition_test.rb", "test/shell_test.rb", "test/ssh_test.rb", "test/task_definition_test.rb", "test/transfer_test.rb", "test/utils.rb", "Manifest", "capistrano.gemspec", "test/deploy/scm/none_test.rb"]
|
13
15
|
s.has_rdoc = true
|
14
16
|
s.homepage = %q{http://www.capify.org}
|
15
17
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Capistrano", "--main", "README.rdoc"]
|
16
18
|
s.require_paths = ["lib"]
|
17
19
|
s.rubyforge_project = %q{capistrano}
|
18
20
|
s.rubygems_version = %q{1.2.0}
|
19
|
-
s.summary = %q{
|
21
|
+
s.summary = %q{Simple. The way it should be.}
|
20
22
|
s.test_files = ["test/cli/execute_test.rb", "test/cli/help_test.rb", "test/cli/options_test.rb", "test/cli/ui_test.rb", "test/cli_test.rb", "test/command_test.rb", "test/configuration/actions/file_transfer_test.rb", "test/configuration/actions/inspect_test.rb", "test/configuration/actions/invocation_test.rb", "test/configuration/callbacks_test.rb", "test/configuration/connections_test.rb", "test/configuration/execution_test.rb", "test/configuration/loading_test.rb", "test/configuration/namespace_dsl_test.rb", "test/configuration/roles_test.rb", "test/configuration/servers_test.rb", "test/configuration/variables_test.rb", "test/configuration_test.rb", "test/deploy/local_dependency_test.rb", "test/deploy/remote_dependency_test.rb", "test/deploy/scm/accurev_test.rb", "test/deploy/scm/base_test.rb", "test/deploy/scm/git_test.rb", "test/deploy/scm/mercurial_test.rb", "test/deploy/scm/none_test.rb", "test/deploy/strategy/copy_test.rb", "test/extensions_test.rb", "test/logger_test.rb", "test/role_test.rb", "test/server_definition_test.rb", "test/shell_test.rb", "test/ssh_test.rb", "test/task_definition_test.rb", "test/transfer_test.rb"]
|
21
23
|
|
22
24
|
if s.respond_to? :specification_version then
|
@@ -24,6 +24,7 @@ module Capistrano
|
|
24
24
|
# line switches for Capistrano, and what their corresponding behaviors
|
25
25
|
# are.
|
26
26
|
def option_parser #:nodoc:
|
27
|
+
@logger = Logger.new
|
27
28
|
@option_parser ||= OptionParser.new do |opts|
|
28
29
|
opts.banner = "Usage: #{File.basename($0)} [options] action ..."
|
29
30
|
|
@@ -167,6 +168,7 @@ module Capistrano
|
|
167
168
|
%w(Capfile capfile).each do |file|
|
168
169
|
if File.file?(file)
|
169
170
|
options[:recipes] << file
|
171
|
+
@logger.info "Using recipes from #{File.join(current,file)}"
|
170
172
|
return
|
171
173
|
end
|
172
174
|
end
|
data/lib/capistrano/command.rb
CHANGED
@@ -209,8 +209,8 @@ module Capistrano
|
|
209
209
|
shell = nil
|
210
210
|
else
|
211
211
|
shell = "#{options[:shell] || "sh"} -c"
|
212
|
-
cmd = cmd.gsub(/
|
213
|
-
cmd = "
|
212
|
+
cmd = cmd.gsub(/'/) { |m| "'\\''" }
|
213
|
+
cmd = "'#{cmd}'"
|
214
214
|
end
|
215
215
|
|
216
216
|
command_line = [environment, shell, cmd].compact.join(" ")
|
@@ -51,24 +51,26 @@ module Capistrano
|
|
51
51
|
# A hash of the SSH sessions that are currently open and available.
|
52
52
|
# Because sessions are constructed lazily, this will only contain
|
53
53
|
# connections to those servers that have been the targets of one or more
|
54
|
-
# executed tasks.
|
55
|
-
|
54
|
+
# executed tasks. Stored on a per-thread basis to improve thread-safety.
|
55
|
+
def sessions
|
56
|
+
Thread.current[:sessions] ||= {}
|
57
|
+
end
|
56
58
|
|
57
59
|
def initialize_with_connections(*args) #:nodoc:
|
58
60
|
initialize_without_connections(*args)
|
59
|
-
|
60
|
-
|
61
|
+
Thread.current[:sessions] = {}
|
62
|
+
Thread.current[:failed_sessions] = []
|
61
63
|
end
|
62
64
|
|
63
65
|
# Indicate that the given server could not be connected to.
|
64
66
|
def failed!(server)
|
65
|
-
|
67
|
+
Thread.current[:failed_sessions] << server
|
66
68
|
end
|
67
69
|
|
68
70
|
# Query whether previous connection attempts to the given server have
|
69
71
|
# failed.
|
70
72
|
def has_failed?(server)
|
71
|
-
|
73
|
+
Thread.current[:failed_sessions].include?(server)
|
72
74
|
end
|
73
75
|
|
74
76
|
# Used to force connections to be made to the current task's servers.
|
@@ -116,9 +118,9 @@ module Capistrano
|
|
116
118
|
# Destroys sessions for each server in the list.
|
117
119
|
def teardown_connections_to(servers)
|
118
120
|
servers.each do |server|
|
119
|
-
|
120
|
-
|
121
|
-
|
121
|
+
sessions[server].close
|
122
|
+
sessions.delete(server)
|
123
|
+
end
|
122
124
|
end
|
123
125
|
|
124
126
|
# Determines the set of servers within the current task's scope and
|
@@ -186,11 +188,13 @@ module Capistrano
|
|
186
188
|
# prevents problems with the thread's scope seeing the wrong 'server'
|
187
189
|
# variable if the thread just happens to take too long to start up.
|
188
190
|
def establish_connection_to(server, failures=nil)
|
189
|
-
Thread.
|
191
|
+
current_thread = Thread.current
|
192
|
+
Thread.new { safely_establish_connection_to(server, current_thread, failures) }
|
190
193
|
end
|
191
194
|
|
192
|
-
def safely_establish_connection_to(server, failures=nil)
|
193
|
-
sessions
|
195
|
+
def safely_establish_connection_to(server, thread, failures=nil)
|
196
|
+
thread[:sessions] ||= {}
|
197
|
+
thread[:sessions][server] ||= connection_factory.connect_to(server)
|
194
198
|
rescue Exception => err
|
195
199
|
raise unless failures
|
196
200
|
failures << { :server => server, :error => err }
|
@@ -8,22 +8,11 @@ module Capistrano
|
|
8
8
|
base.send :alias_method, :initialize, :initialize_with_execution
|
9
9
|
end
|
10
10
|
|
11
|
-
# The call stack of the tasks. The currently executing task may inspect
|
12
|
-
# this to see who its caller was. The current task is always the last
|
13
|
-
# element of this stack.
|
14
|
-
attr_reader :task_call_frames
|
15
|
-
|
16
|
-
# The stack of tasks that have registered rollback handlers within the
|
17
|
-
# current transaction. If this is nil, then there is no transaction
|
18
|
-
# that is currently active.
|
19
|
-
attr_reader :rollback_requests
|
20
|
-
|
21
11
|
# A struct for representing a single instance of an invoked task.
|
22
12
|
TaskCallFrame = Struct.new(:task, :rollback)
|
23
13
|
|
24
14
|
def initialize_with_execution(*args) #:nodoc:
|
25
15
|
initialize_without_execution(*args)
|
26
|
-
@task_call_frames = []
|
27
16
|
end
|
28
17
|
private :initialize_with_execution
|
29
18
|
|
@@ -32,6 +21,25 @@ module Capistrano
|
|
32
21
|
!rollback_requests.nil?
|
33
22
|
end
|
34
23
|
|
24
|
+
# The call stack of the tasks. The currently executing task may inspect
|
25
|
+
# this to see who its caller was. The current task is always the last
|
26
|
+
# element of this stack.
|
27
|
+
def task_call_frames
|
28
|
+
Thread.current[:task_call_frames] ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# The stack of tasks that have registered rollback handlers within the
|
33
|
+
# current transaction. If this is nil, then there is no transaction
|
34
|
+
# that is currently active.
|
35
|
+
def rollback_requests
|
36
|
+
Thread.current[:rollback_requests]
|
37
|
+
end
|
38
|
+
|
39
|
+
def rollback_requests=(rollback_requests)
|
40
|
+
Thread.current[:rollback_requests] = rollback_requests
|
41
|
+
end
|
42
|
+
|
35
43
|
# Invoke a set of tasks in a transaction. If any task fails (raises an
|
36
44
|
# exception), all tasks executed within the transaction are inspected to
|
37
45
|
# see if they have an associated on_rollback hook, and if so, that hook
|
@@ -44,14 +52,14 @@ module Capistrano
|
|
44
52
|
|
45
53
|
logger.info "transaction: start"
|
46
54
|
begin
|
47
|
-
|
55
|
+
self.rollback_requests = []
|
48
56
|
yield
|
49
57
|
logger.info "transaction: commit"
|
50
58
|
rescue Object => e
|
51
59
|
rollback!
|
52
60
|
raise
|
53
61
|
ensure
|
54
|
-
|
62
|
+
self.rollback_requests = nil if Thread.main == Thread.current
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
@@ -99,6 +107,9 @@ module Capistrano
|
|
99
107
|
protected
|
100
108
|
|
101
109
|
def rollback!
|
110
|
+
return if Thread.current[:rollback_requests].nil?
|
111
|
+
Thread.current[:rolled_back] = true
|
112
|
+
|
102
113
|
# throw the task back on the stack so that roles are properly
|
103
114
|
# interpreted in the scope of the task in question.
|
104
115
|
rollback_requests.reverse.each do |frame|
|
@@ -151,9 +151,18 @@ namespace :deploy do
|
|
151
151
|
DESC
|
152
152
|
task :default do
|
153
153
|
update
|
154
|
-
restart
|
154
|
+
# restart
|
155
155
|
end
|
156
156
|
|
157
|
+
[:start, :stop, :restart].each do |deprecated_task|
|
158
|
+
desc "#{deprecated_task.to_s} is deprecated. Please see "
|
159
|
+
task deprecated_task do
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
|
157
166
|
desc <<-DESC
|
158
167
|
Prepares one or more servers for deployment. Before you can use any \
|
159
168
|
of the Capistrano deployment tasks with your project, you will need to \
|
@@ -222,23 +231,6 @@ namespace :deploy do
|
|
222
231
|
DESC
|
223
232
|
task :finalize_update, :except => { :no_release => true } do
|
224
233
|
run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)
|
225
|
-
|
226
|
-
# mkdir -p is making sure that the directories are there for some SCM's that don't
|
227
|
-
# save empty folders
|
228
|
-
run <<-CMD
|
229
|
-
rm -rf #{latest_release}/log #{latest_release}/public/system #{latest_release}/tmp/pids &&
|
230
|
-
mkdir -p #{latest_release}/public &&
|
231
|
-
mkdir -p #{latest_release}/tmp &&
|
232
|
-
ln -s #{shared_path}/log #{latest_release}/log &&
|
233
|
-
ln -s #{shared_path}/system #{latest_release}/public/system &&
|
234
|
-
ln -s #{shared_path}/pids #{latest_release}/tmp/pids
|
235
|
-
CMD
|
236
|
-
|
237
|
-
if fetch(:normalize_asset_timestamps, true)
|
238
|
-
stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
|
239
|
-
asset_paths = %w(images stylesheets javascripts).map { |p| "#{latest_release}/public/#{p}" }.join(" ")
|
240
|
-
run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" }
|
241
|
-
end
|
242
234
|
end
|
243
235
|
|
244
236
|
desc <<-DESC
|
@@ -287,21 +279,6 @@ namespace :deploy do
|
|
287
279
|
files.each { |file| top.upload(file, File.join(current_path, file)) }
|
288
280
|
end
|
289
281
|
|
290
|
-
desc <<-DESC
|
291
|
-
Restarts your application. This works by calling the script/process/reaper \
|
292
|
-
script under the current path.
|
293
|
-
|
294
|
-
By default, this will be invoked via sudo as the `app' user. If \
|
295
|
-
you wish to run it as a different user, set the :runner variable to \
|
296
|
-
that user. If you are in an environment where you can't use sudo, set \
|
297
|
-
the :use_sudo variable to false:
|
298
|
-
|
299
|
-
set :use_sudo, false
|
300
|
-
DESC
|
301
|
-
task :restart, :roles => :app, :except => { :no_release => true } do
|
302
|
-
try_runner "#{current_path}/script/process/reaper"
|
303
|
-
end
|
304
|
-
|
305
282
|
namespace :rollback do
|
306
283
|
desc <<-DESC
|
307
284
|
[internal] Points the current symlink at the previous revision.
|
@@ -328,8 +305,7 @@ namespace :deploy do
|
|
328
305
|
desc <<-DESC
|
329
306
|
Rolls back to the previously deployed version. The `current' symlink will \
|
330
307
|
be updated to point at the previously deployed version, and then the \
|
331
|
-
current release will be removed from the servers.
|
332
|
-
to call `rollback' instead, as it performs a `restart' as well.
|
308
|
+
current release will be removed from the servers.
|
333
309
|
DESC
|
334
310
|
task :code, :except => { :no_release => true } do
|
335
311
|
revision
|
@@ -343,56 +319,10 @@ namespace :deploy do
|
|
343
319
|
DESC
|
344
320
|
task :default do
|
345
321
|
revision
|
346
|
-
restart
|
347
322
|
cleanup
|
348
323
|
end
|
349
324
|
end
|
350
325
|
|
351
|
-
desc <<-DESC
|
352
|
-
Run the migrate rake task. By default, it runs this in most recently \
|
353
|
-
deployed version of the app. However, you can specify a different release \
|
354
|
-
via the migrate_target variable, which must be one of :latest (for the \
|
355
|
-
default behavior), or :current (for the release indicated by the \
|
356
|
-
`current' symlink). Strings will work for those values instead of symbols, \
|
357
|
-
too. You can also specify additional environment variables to pass to rake \
|
358
|
-
via the migrate_env variable. Finally, you can specify the full path to the \
|
359
|
-
rake executable by setting the rake variable. The defaults are:
|
360
|
-
|
361
|
-
set :rake, "rake"
|
362
|
-
set :rails_env, "production"
|
363
|
-
set :migrate_env, ""
|
364
|
-
set :migrate_target, :latest
|
365
|
-
DESC
|
366
|
-
task :migrate, :roles => :db, :only => { :primary => true } do
|
367
|
-
rake = fetch(:rake, "rake")
|
368
|
-
rails_env = fetch(:rails_env, "production")
|
369
|
-
migrate_env = fetch(:migrate_env, "")
|
370
|
-
migrate_target = fetch(:migrate_target, :latest)
|
371
|
-
|
372
|
-
directory = case migrate_target.to_sym
|
373
|
-
when :current then current_path
|
374
|
-
when :latest then current_release
|
375
|
-
else raise ArgumentError, "unknown migration target #{migrate_target.inspect}"
|
376
|
-
end
|
377
|
-
|
378
|
-
run "cd #{directory}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate"
|
379
|
-
end
|
380
|
-
|
381
|
-
desc <<-DESC
|
382
|
-
Deploy and run pending migrations. This will work similarly to the \
|
383
|
-
`deploy' task, but will also run any pending migrations (via the \
|
384
|
-
`deploy:migrate' task) prior to updating the symlink. Note that the \
|
385
|
-
update in this case it is not atomic, and transactions are not used, \
|
386
|
-
because migrations are not guaranteed to be reversible.
|
387
|
-
DESC
|
388
|
-
task :migrations do
|
389
|
-
set :migrate_target, :latest
|
390
|
-
update_code
|
391
|
-
migrate
|
392
|
-
symlink
|
393
|
-
restart
|
394
|
-
end
|
395
|
-
|
396
326
|
desc <<-DESC
|
397
327
|
Clean up old releases. By default, the last 5 releases are kept on each \
|
398
328
|
server (though you can change this with the keep_releases variable). All \
|
@@ -462,40 +392,6 @@ namespace :deploy do
|
|
462
392
|
DESC
|
463
393
|
task :cold do
|
464
394
|
update
|
465
|
-
migrate
|
466
|
-
start
|
467
|
-
end
|
468
|
-
|
469
|
-
desc <<-DESC
|
470
|
-
Start the application servers. This will attempt to invoke a script \
|
471
|
-
in your application called `script/spin', which must know how to start \
|
472
|
-
your application listeners. For Rails applications, you might just have \
|
473
|
-
that script invoke `script/process/spawner' with the appropriate \
|
474
|
-
arguments.
|
475
|
-
|
476
|
-
By default, the script will be executed via sudo as the `app' user. If \
|
477
|
-
you wish to run it as a different user, set the :runner variable to \
|
478
|
-
that user. If you are in an environment where you can't use sudo, set \
|
479
|
-
the :use_sudo variable to false.
|
480
|
-
DESC
|
481
|
-
task :start, :roles => :app do
|
482
|
-
run "cd #{current_path} && #{try_runner} nohup script/spin"
|
483
|
-
end
|
484
|
-
|
485
|
-
desc <<-DESC
|
486
|
-
Stop the application servers. This will call script/process/reaper for \
|
487
|
-
both the spawner process, and all of the application processes it has \
|
488
|
-
spawned. As such, it is fairly Rails specific and may need to be \
|
489
|
-
overridden for other systems.
|
490
|
-
|
491
|
-
By default, the script will be executed via sudo as the `app' user. If \
|
492
|
-
you wish to run it as a different user, set the :runner variable to \
|
493
|
-
that user. If you are in an environment where you can't use sudo, set \
|
494
|
-
the :use_sudo variable to false.
|
495
|
-
DESC
|
496
|
-
task :stop, :roles => :app do
|
497
|
-
run "if [ -f #{current_path}/tmp/pids/dispatch.spawner.pid ]; then #{try_runner} #{current_path}/script/process/reaper -a kill -r dispatch.spawner.pid; fi"
|
498
|
-
try_runner "#{current_path}/script/process/reaper -a kill"
|
499
395
|
end
|
500
396
|
|
501
397
|
namespace :pending do
|
@@ -519,44 +415,4 @@ namespace :deploy do
|
|
519
415
|
end
|
520
416
|
end
|
521
417
|
|
522
|
-
namespace :web do
|
523
|
-
desc <<-DESC
|
524
|
-
Present a maintenance page to visitors. Disables your application's web \
|
525
|
-
interface by writing a "maintenance.html" file to each web server. The \
|
526
|
-
servers must be configured to detect the presence of this file, and if \
|
527
|
-
it is present, always display it instead of performing the request.
|
528
|
-
|
529
|
-
By default, the maintenance page will just say the site is down for \
|
530
|
-
"maintenance", and will be back "shortly", but you can customize the \
|
531
|
-
page by specifying the REASON and UNTIL environment variables:
|
532
|
-
|
533
|
-
$ cap deploy:web:disable \\
|
534
|
-
REASON="hardware upgrade" \\
|
535
|
-
UNTIL="12pm Central Time"
|
536
|
-
|
537
|
-
Further customization will require that you write your own task.
|
538
|
-
DESC
|
539
|
-
task :disable, :roles => :web, :except => { :no_release => true } do
|
540
|
-
require 'erb'
|
541
|
-
on_rollback { run "rm #{shared_path}/system/maintenance.html" }
|
542
|
-
|
543
|
-
reason = ENV['REASON']
|
544
|
-
deadline = ENV['UNTIL']
|
545
|
-
|
546
|
-
template = File.read(File.join(File.dirname(__FILE__), "templates", "maintenance.rhtml"))
|
547
|
-
result = ERB.new(template).result(binding)
|
548
|
-
|
549
|
-
put result, "#{shared_path}/system/maintenance.html", :mode => 0644
|
550
|
-
end
|
551
|
-
|
552
|
-
desc <<-DESC
|
553
|
-
Makes the application web-accessible again. Removes the \
|
554
|
-
"maintenance.html" page generated by deploy:web:disable, which (if your \
|
555
|
-
web servers are configured correctly) will make your application \
|
556
|
-
web-accessible again.
|
557
|
-
DESC
|
558
|
-
task :enable, :roles => :web, :except => { :no_release => true } do
|
559
|
-
run "rm #{shared_path}/system/maintenance.html"
|
560
|
-
end
|
561
|
-
end
|
562
418
|
end
|
@@ -151,6 +151,7 @@ module Capistrano
|
|
151
151
|
|
152
152
|
if configuration[:git_enable_submodules]
|
153
153
|
execute << "#{git} submodule #{verbose} init"
|
154
|
+
execute << "#{git} submodule #{verbose} sync"
|
154
155
|
execute << "#{git} submodule #{verbose} update"
|
155
156
|
end
|
156
157
|
|
@@ -188,9 +189,15 @@ module Capistrano
|
|
188
189
|
|
189
190
|
if configuration[:git_enable_submodules]
|
190
191
|
execute << "#{git} submodule #{verbose} init"
|
192
|
+
execute << "for mod in `#{git} submodule status | awk '{ print $2 }'`; do #{git} config -f .git/config submodule.${mod}.url `#{git} config -f .gitmodules --get submodule.${mod}.url` && echo Synced $mod; done"
|
193
|
+
execute << "#{git} submodule #{verbose} sync"
|
191
194
|
execute << "#{git} submodule #{verbose} update"
|
192
195
|
end
|
193
196
|
|
197
|
+
# Make sure there's nothing else lying around in the repository (for
|
198
|
+
# example, a submodule that has subsequently been removed).
|
199
|
+
execute << "#{git} clean #{verbose} -d -x -f"
|
200
|
+
|
194
201
|
execute.join(" && ")
|
195
202
|
end
|
196
203
|
|
@@ -18,7 +18,7 @@ module Capistrano
|
|
18
18
|
# For mercurial HEAD == tip except that it bases this assumption on what
|
19
19
|
# tip is in the current repository (so push before you deploy)
|
20
20
|
def head
|
21
|
-
"tip"
|
21
|
+
configuration[:branch] || "tip"
|
22
22
|
end
|
23
23
|
|
24
24
|
# Clone the repository and update to the specified changeset.
|
@@ -134,4 +134,4 @@ module Capistrano
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
end
|
137
|
-
end
|
137
|
+
end
|
@@ -49,7 +49,7 @@ module Capistrano
|
|
49
49
|
|
50
50
|
# Returns a "p4 changes" command for the two revisions.
|
51
51
|
def log(from=1, to=head)
|
52
|
-
scm authentication, :changes, "-s submitted", "//#{p4client}/...#{rev_no(from)},#
|
52
|
+
scm authentication, :changes, "-s submitted", "//#{p4client}/...#{rev_no(from)},#{rev_no(to)}"
|
53
53
|
end
|
54
54
|
|
55
55
|
def query_revision(revision)
|
@@ -58,6 +58,11 @@ module Capistrano
|
|
58
58
|
yield(command)[/Change (\d+) on/, 1]
|
59
59
|
end
|
60
60
|
|
61
|
+
# Increments the given revision number and returns it.
|
62
|
+
def next_revision(revision)
|
63
|
+
revision.to_i + 1
|
64
|
+
end
|
65
|
+
|
61
66
|
# Determines what the response should be for a particular bit of text
|
62
67
|
# from the SCM. Password prompts, connection requests, passphrases,
|
63
68
|
# etc. are handled here.
|
@@ -0,0 +1,50 @@
|
|
1
|
+
namespace :deploy do
|
2
|
+
|
3
|
+
desc <<-DESC
|
4
|
+
Run the migrate rake task. By default, it runs this in most recently \
|
5
|
+
deployed version of the app. However, you can specify a different release \
|
6
|
+
via the migrate_target variable, which must be one of :latest (for the \
|
7
|
+
default behavior), or :current (for the release indicated by the \
|
8
|
+
`current' symlink). Strings will work for those values instead of symbols, \
|
9
|
+
too. You can also specify additional environment variables to pass to rake \
|
10
|
+
via the migrate_env variable. Finally, you can specify the full path to the \
|
11
|
+
rake executable by setting the rake variable. The defaults are:
|
12
|
+
|
13
|
+
set :rake, "rake"
|
14
|
+
set :rails_env, "production"
|
15
|
+
set :migrate_env, ""
|
16
|
+
set :migrate_target, :latest
|
17
|
+
DESC
|
18
|
+
task :migrate, :roles => :db, :only => { :primary => true } do
|
19
|
+
rake = fetch(:rake, "rake")
|
20
|
+
rails_env = fetch(:rails_env, "production")
|
21
|
+
migrate_env = fetch(:migrate_env, "")
|
22
|
+
migrate_target = fetch(:migrate_target, :latest)
|
23
|
+
|
24
|
+
directory = case migrate_target.to_sym
|
25
|
+
when :current then current_path
|
26
|
+
when :latest then current_release
|
27
|
+
else raise ArgumentError, "unknown migration target #{migrate_target.inspect}"
|
28
|
+
end
|
29
|
+
|
30
|
+
run "cd #{directory}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc <<-DESC
|
34
|
+
Deploy and run pending migrations. This will work similarly to the \
|
35
|
+
`deploy' task, but will also run any pending migrations (via the \
|
36
|
+
`deploy:migrate' task) prior to updating the symlink. Note that the \
|
37
|
+
update in this case it is not atomic, and transactions are not used, \
|
38
|
+
because migrations are not guaranteed to be reversible.
|
39
|
+
DESC
|
40
|
+
task :migrations do
|
41
|
+
set :migrate_target, :latest
|
42
|
+
update_code
|
43
|
+
migrate
|
44
|
+
symlink
|
45
|
+
restart
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
after('deploy:update_code', 'deploy:migrate')
|
@@ -0,0 +1,21 @@
|
|
1
|
+
_cset :shared_children, %w(system log pids)
|
2
|
+
|
3
|
+
after 'deploy:finalize_update' do
|
4
|
+
# mkdir -p is making sure that the directories are there for some SCM's that don't
|
5
|
+
# save empty folders
|
6
|
+
run <<-CMD
|
7
|
+
rm -rf #{latest_release}/log #{latest_release}/public/system #{latest_release}/tmp/pids &&
|
8
|
+
mkdir -p #{latest_release}/public &&
|
9
|
+
mkdir -p #{latest_release}/tmp &&
|
10
|
+
ln -s #{shared_path}/log #{latest_release}/log &&
|
11
|
+
ln -s #{shared_path}/system #{latest_release}/public/system &&
|
12
|
+
ln -s #{shared_path}/pids #{latest_release}/tmp/pids
|
13
|
+
CMD
|
14
|
+
|
15
|
+
if fetch(:normalize_asset_timestamps, true)
|
16
|
+
stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
|
17
|
+
asset_paths = %w(images stylesheets javascripts).map { |p| "#{latest_release}/public/#{p}" }.join(" ")
|
18
|
+
run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" }
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
namespace :web do
|
2
|
+
desc <<-DESC
|
3
|
+
Present a maintenance page to visitors. Disables your application's web \
|
4
|
+
interface by writing a "maintenance.html" file to each web server. The \
|
5
|
+
servers must be configured to detect the presence of this file, and if \
|
6
|
+
it is present, always display it instead of performing the request.
|
7
|
+
|
8
|
+
By default, the maintenance page will just say the site is down for \
|
9
|
+
"maintenance", and will be back "shortly", but you can customize the \
|
10
|
+
page by specifying the REASON and UNTIL environment variables:
|
11
|
+
|
12
|
+
$ cap deploy:web:disable \\
|
13
|
+
REASON="hardware upgrade" \\
|
14
|
+
UNTIL="12pm Central Time"
|
15
|
+
|
16
|
+
Further customization will require that you write your own task.
|
17
|
+
DESC
|
18
|
+
task :disable, :roles => :web, :except => { :no_release => true } do
|
19
|
+
require 'erb'
|
20
|
+
on_rollback { run "rm #{shared_path}/system/maintenance.html" }
|
21
|
+
|
22
|
+
reason = ENV['REASON']
|
23
|
+
deadline = ENV['UNTIL']
|
24
|
+
|
25
|
+
template = File.read(File.join(File.dirname(__FILE__), "templates", "maintenance.rhtml"))
|
26
|
+
result = ERB.new(template).result(binding)
|
27
|
+
|
28
|
+
put result, "#{shared_path}/system/maintenance.html", :mode => 0644
|
29
|
+
end
|
30
|
+
|
31
|
+
desc <<-DESC
|
32
|
+
Makes the application web-accessible again. Removes the \
|
33
|
+
"maintenance.html" page generated by deploy:web:disable, which (if your \
|
34
|
+
web servers are configured correctly) will make your application \
|
35
|
+
web-accessible again.
|
36
|
+
DESC
|
37
|
+
task :enable, :roles => :web, :except => { :no_release => true } do
|
38
|
+
run "rm #{shared_path}/system/maintenance.html"
|
39
|
+
end
|
40
|
+
end
|
data/lib/capistrano/version.rb
CHANGED
data/test/command_test.rb
CHANGED
@@ -20,7 +20,7 @@ class CommandTest < Test::Unit::TestCase
|
|
20
20
|
|
21
21
|
def test_command_with_pty_should_request_pty_and_register_success_callback
|
22
22
|
session = setup_for_extracting_channel_action(:request_pty, true) do |ch|
|
23
|
-
ch.expects(:exec).with(%(sh -c
|
23
|
+
ch.expects(:exec).with(%(sh -c 'ls'))
|
24
24
|
end
|
25
25
|
Capistrano::Command.new("ls", [session], :pty => true)
|
26
26
|
end
|
@@ -28,35 +28,35 @@ class CommandTest < Test::Unit::TestCase
|
|
28
28
|
def test_command_with_env_key_should_have_environment_constructed_and_prepended
|
29
29
|
session = setup_for_extracting_channel_action do |ch|
|
30
30
|
ch.expects(:request_pty).never
|
31
|
-
ch.expects(:exec).with(%(env FOO=bar sh -c
|
31
|
+
ch.expects(:exec).with(%(env FOO=bar sh -c 'ls'))
|
32
32
|
end
|
33
33
|
Capistrano::Command.new("ls", [session], :env => { "FOO" => "bar" })
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_env_with_symbolic_key_should_be_accepted_as_a_string
|
37
37
|
session = setup_for_extracting_channel_action do |ch|
|
38
|
-
ch.expects(:exec).with(%(env FOO=bar sh -c
|
38
|
+
ch.expects(:exec).with(%(env FOO=bar sh -c 'ls'))
|
39
39
|
end
|
40
40
|
Capistrano::Command.new("ls", [session], :env => { :FOO => "bar" })
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_env_as_string_should_be_substituted_in_directly
|
44
44
|
session = setup_for_extracting_channel_action do |ch|
|
45
|
-
ch.expects(:exec).with(%(env HOWDY=there sh -c
|
45
|
+
ch.expects(:exec).with(%(env HOWDY=there sh -c 'ls'))
|
46
46
|
end
|
47
47
|
Capistrano::Command.new("ls", [session], :env => "HOWDY=there")
|
48
48
|
end
|
49
49
|
|
50
50
|
def test_env_with_symbolic_value_should_be_accepted_as_string
|
51
51
|
session = setup_for_extracting_channel_action do |ch|
|
52
|
-
ch.expects(:exec).with(%(env FOO=bar sh -c
|
52
|
+
ch.expects(:exec).with(%(env FOO=bar sh -c 'ls'))
|
53
53
|
end
|
54
54
|
Capistrano::Command.new("ls", [session], :env => { "FOO" => :bar })
|
55
55
|
end
|
56
56
|
|
57
57
|
def test_env_value_should_be_escaped
|
58
58
|
session = setup_for_extracting_channel_action do |ch|
|
59
|
-
ch.expects(:exec).with(%(env FOO=(\\ \\\"bar\\\"\\ ) sh -c
|
59
|
+
ch.expects(:exec).with(%(env FOO=(\\ \\\"bar\\\"\\ ) sh -c 'ls'))
|
60
60
|
end
|
61
61
|
Capistrano::Command.new("ls", [session], :env => { "FOO" => '( "bar" )' })
|
62
62
|
end
|
@@ -68,7 +68,7 @@ class CommandTest < Test::Unit::TestCase
|
|
68
68
|
command =~ /\ba=b\b/ &&
|
69
69
|
command =~ /\bc=d\b/ &&
|
70
70
|
command =~ /\be=f\b/ &&
|
71
|
-
command =~ / sh -c
|
71
|
+
command =~ / sh -c 'ls'$/
|
72
72
|
end
|
73
73
|
end
|
74
74
|
Capistrano::Command.new("ls", [session], :env => { :a => :b, :c => :d, :e => :f })
|
@@ -90,14 +90,14 @@ class CommandTest < Test::Unit::TestCase
|
|
90
90
|
|
91
91
|
def test_successful_channel_should_send_command
|
92
92
|
session = setup_for_extracting_channel_action do |ch|
|
93
|
-
ch.expects(:exec).with(%(sh -c
|
93
|
+
ch.expects(:exec).with(%(sh -c 'ls'))
|
94
94
|
end
|
95
95
|
Capistrano::Command.new("ls", [session])
|
96
96
|
end
|
97
97
|
|
98
98
|
def test_successful_channel_with_shell_option_should_send_command_via_specified_shell
|
99
99
|
session = setup_for_extracting_channel_action do |ch|
|
100
|
-
ch.expects(:exec).with(%(/bin/bash -c
|
100
|
+
ch.expects(:exec).with(%(/bin/bash -c 'ls'))
|
101
101
|
end
|
102
102
|
Capistrano::Command.new("ls", [session], :shell => "/bin/bash")
|
103
103
|
end
|
@@ -111,7 +111,7 @@ class CommandTest < Test::Unit::TestCase
|
|
111
111
|
|
112
112
|
def test_successful_channel_should_send_data_if_data_key_is_present
|
113
113
|
session = setup_for_extracting_channel_action do |ch|
|
114
|
-
ch.expects(:exec).with(%(sh -c
|
114
|
+
ch.expects(:exec).with(%(sh -c 'ls'))
|
115
115
|
ch.expects(:send_data).with("here we go")
|
116
116
|
end
|
117
117
|
Capistrano::Command.new("ls", [session], :data => "here we go")
|
@@ -225,14 +225,14 @@ class CommandTest < Test::Unit::TestCase
|
|
225
225
|
|
226
226
|
def test_process_with_host_placeholder_should_substitute_placeholder_with_each_host
|
227
227
|
session = setup_for_extracting_channel_action do |ch|
|
228
|
-
ch.expects(:exec).with(%(sh -c
|
228
|
+
ch.expects(:exec).with(%(sh -c 'echo capistrano'))
|
229
229
|
end
|
230
230
|
Capistrano::Command.new("echo $CAPISTRANO:HOST$", [session])
|
231
231
|
end
|
232
232
|
|
233
233
|
def test_process_with_unknown_placeholder_should_not_replace_placeholder
|
234
234
|
session = setup_for_extracting_channel_action do |ch|
|
235
|
-
ch.expects(:exec).with(%(sh -c
|
235
|
+
ch.expects(:exec).with(%(sh -c 'echo $CAPISTRANO:OTHER$'))
|
236
236
|
end
|
237
237
|
Capistrano::Command.new("echo $CAPISTRANO:OTHER$", [session])
|
238
238
|
end
|
data/test/deploy/scm/git_test.rb
CHANGED
@@ -37,6 +37,10 @@ class DeploySCMGitTest < Test::Unit::TestCase
|
|
37
37
|
git = "/opt/local/bin/git"
|
38
38
|
@config[:scm_command] = git
|
39
39
|
assert_equal "#{git} clone -q git@somehost.com:project.git /var/www && cd /var/www && #{git} checkout -q -b deploy #{rev}", @source.checkout(rev, dest)
|
40
|
+
|
41
|
+
# with submodules
|
42
|
+
@config[:git_enable_submodules] = true
|
43
|
+
assert_equal "#{git} clone -q git@somehost.com:project.git /var/www && cd /var/www && #{git} checkout -q -b deploy #{rev} && #{git} submodule -q init && #{git} submodule -q sync && #{git} submodule -q update", @source.checkout(rev, dest)
|
40
44
|
end
|
41
45
|
|
42
46
|
def test_checkout_with_verbose_should_not_use_q_switch
|
@@ -88,12 +92,16 @@ class DeploySCMGitTest < Test::Unit::TestCase
|
|
88
92
|
def test_sync
|
89
93
|
dest = "/var/www"
|
90
94
|
rev = 'c2d9e79'
|
91
|
-
assert_equal "cd #{dest} && git fetch -q origin && git reset -q --hard #{rev}", @source.sync(rev, dest)
|
95
|
+
assert_equal "cd #{dest} && git fetch -q origin && git reset -q --hard #{rev} && git clean -q -d -x -f", @source.sync(rev, dest)
|
92
96
|
|
93
97
|
# With :scm_command
|
94
98
|
git = "/opt/local/bin/git"
|
95
99
|
@config[:scm_command] = git
|
96
|
-
assert_equal "cd #{dest} && #{git} fetch -q origin && #{git} reset -q --hard #{rev}", @source.sync(rev, dest)
|
100
|
+
assert_equal "cd #{dest} && #{git} fetch -q origin && #{git} reset -q --hard #{rev} && #{git} clean -q -d -x -f", @source.sync(rev, dest)
|
101
|
+
|
102
|
+
# with submodules
|
103
|
+
@config[:git_enable_submodules] = true
|
104
|
+
assert_equal "cd #{dest} && #{git} fetch -q origin && #{git} reset -q --hard #{rev} && #{git} submodule -q init && for mod in `#{git} submodule status | awk '{ print $2 }'`; do #{git} config -f .git/config submodule.${mod}.url `#{git} config -f .gitmodules --get submodule.${mod}.url` && echo Synced $mod; done && #{git} submodule -q sync && #{git} submodule -q update && #{git} clean -q -d -x -f", @source.sync(rev, dest)
|
97
105
|
end
|
98
106
|
|
99
107
|
def test_sync_with_remote
|
@@ -105,7 +113,7 @@ class DeploySCMGitTest < Test::Unit::TestCase
|
|
105
113
|
@config[:repository] = repository
|
106
114
|
@config[:remote] = remote
|
107
115
|
|
108
|
-
assert_equal "cd #{dest} && git config remote.#{remote}.url #{repository} && git config remote.#{remote}.fetch +refs/heads/*:refs/remotes/#{remote}/* && git fetch -q #{remote} && git reset -q --hard #{rev}", @source.sync(rev, dest)
|
116
|
+
assert_equal "cd #{dest} && git config remote.#{remote}.url #{repository} && git config remote.#{remote}.fetch +refs/heads/*:refs/remotes/#{remote}/* && git fetch -q #{remote} && git reset -q --hard #{rev} && git clean -q -d -x -f", @source.sync(rev, dest)
|
109
117
|
end
|
110
118
|
|
111
119
|
def test_shallow_clone
|
@@ -124,6 +132,15 @@ class DeploySCMGitTest < Test::Unit::TestCase
|
|
124
132
|
assert_equal "git clone -q -o username git@somehost.com:project.git /var/www && cd /var/www && git checkout -q -b deploy #{rev}", @source.checkout(rev, dest)
|
125
133
|
end
|
126
134
|
|
135
|
+
def test_remote_clone_with_submodules
|
136
|
+
@config[:repository] = "git@somehost.com:project.git"
|
137
|
+
@config[:remote] = "username"
|
138
|
+
@config[:git_enable_submodules] = true
|
139
|
+
dest = "/var/www"
|
140
|
+
rev = 'c2d9e79'
|
141
|
+
assert_equal "git clone -q -o username git@somehost.com:project.git /var/www && cd /var/www && git checkout -q -b deploy #{rev} && git submodule -q init && git submodule -q sync && git submodule -q update", @source.checkout(rev, dest)
|
142
|
+
end
|
143
|
+
|
127
144
|
# Tests from base_test.rb, makin' sure we didn't break anything up there!
|
128
145
|
def test_command_should_default_to_default_command
|
129
146
|
assert_equal "git", @source.command
|
@@ -17,6 +17,11 @@ class DeploySCMMercurialTest < Test::Unit::TestCase
|
|
17
17
|
assert_equal "tip", @source.head
|
18
18
|
end
|
19
19
|
|
20
|
+
def test_different_head
|
21
|
+
@config[:branch] = "staging"
|
22
|
+
assert_equal "staging", @source.head
|
23
|
+
end
|
24
|
+
|
20
25
|
def test_checkout
|
21
26
|
@config[:repository] = "http://example.com/project-hg"
|
22
27
|
dest = "/var/www"
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamis Buck
|
8
|
+
- Lee Hambley
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date: 2009-02-24 00:00:00
|
13
|
+
date: 2009-02-24 00:00:00 +00:00
|
13
14
|
default_executable:
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
@@ -73,7 +74,7 @@ dependencies:
|
|
73
74
|
version: "0"
|
74
75
|
version:
|
75
76
|
description: Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH.
|
76
|
-
email:
|
77
|
+
email: lee.hambley@gmail.com
|
77
78
|
executables:
|
78
79
|
- cap
|
79
80
|
- capify
|
@@ -194,6 +195,9 @@ files:
|
|
194
195
|
- lib/capistrano/recipes/deploy/strategy.rb
|
195
196
|
- lib/capistrano/recipes/deploy/templates/maintenance.rhtml
|
196
197
|
- lib/capistrano/recipes/deploy.rb
|
198
|
+
- lib/capistrano/recipes/ext/rails-shared-directories.rb
|
199
|
+
- lib/capistrano/recipes/ext/rails-database-migrations.rb
|
200
|
+
- lib/capistrano/recipes/ext/web-disable-enable.rb
|
197
201
|
- lib/capistrano/recipes/standard.rb
|
198
202
|
- lib/capistrano/recipes/templates/maintenance.rhtml
|
199
203
|
- lib/capistrano/recipes/upgrade.rb
|
@@ -247,8 +251,11 @@ files:
|
|
247
251
|
- test/utils.rb
|
248
252
|
- Manifest
|
249
253
|
- capistrano.gemspec
|
254
|
+
- test/deploy/scm/none_test.rb
|
250
255
|
has_rdoc: true
|
251
256
|
homepage: http://www.capify.org
|
257
|
+
licenses: []
|
258
|
+
|
252
259
|
post_install_message:
|
253
260
|
rdoc_options:
|
254
261
|
- --line-numbers
|
@@ -274,10 +281,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
274
281
|
requirements: []
|
275
282
|
|
276
283
|
rubyforge_project: capistrano
|
277
|
-
rubygems_version: 1.
|
284
|
+
rubygems_version: 1.3.4
|
278
285
|
signing_key:
|
279
286
|
specification_version: 2
|
280
|
-
summary:
|
287
|
+
summary: Simple. The way it should be.
|
281
288
|
test_files:
|
282
289
|
- test/cli/execute_test.rb
|
283
290
|
- test/cli/help_test.rb
|