capistrano 2.5.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +29 -0
- data/capistrano.gemspec +3 -3
- data/lib/capistrano/cli/help.rb +28 -14
- data/lib/capistrano/cli/help.txt +5 -2
- data/lib/capistrano/cli/options.rb +16 -5
- data/lib/capistrano/configuration/actions/invocation.rb +2 -1
- data/lib/capistrano/configuration/connections.rb +6 -1
- data/lib/capistrano/configuration/namespaces.rb +2 -2
- data/lib/capistrano/configuration/servers.rb +11 -2
- data/lib/capistrano/extensions.rb +1 -1
- data/lib/capistrano/logger.rb +1 -1
- data/lib/capistrano/recipes/deploy.rb +8 -1
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +3 -2
- data/lib/capistrano/recipes/deploy/scm/base.rb +12 -8
- data/lib/capistrano/recipes/deploy/scm/cvs.rb +2 -2
- data/lib/capistrano/recipes/deploy/scm/git.rb +10 -3
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +3 -3
- data/lib/capistrano/recipes/deploy/scm/subversion.rb +3 -3
- data/lib/capistrano/recipes/deploy/strategy/base.rb +12 -3
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +8 -1
- data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +1 -1
- data/lib/capistrano/version.rb +1 -1
- data/test/cli/help_test.rb +32 -6
- data/test/cli/options_test.rb +3 -2
- data/test/configuration/actions/invocation_test.rb +6 -0
- data/test/configuration/loading_test.rb +1 -1
- data/test/configuration/namespace_dsl_test.rb +2 -2
- data/test/configuration/servers_test.rb +19 -3
- data/test/deploy/remote_dependency_test.rb +1 -1
- data/test/deploy/scm/git_test.rb +1 -1
- data/test/deploy/strategy/copy_test.rb +4 -4
- data/test/role_test.rb +1 -1
- metadata +2 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
== 2.5.1 / November 7, 2008
|
2
|
+
|
3
|
+
* Add -t (--tools) switch for better task lists for external tools [Jamis Buck]
|
4
|
+
|
5
|
+
* Make the RemoteDependency#try method use invoke_command instead of run, for sudo-ability [Matthias Marschall]
|
6
|
+
|
7
|
+
* Make locally executed commands in Windows more Windows-friendly [esad@esse.at]
|
8
|
+
|
9
|
+
* Added :scm_arguments variable for custom SCM arguments (subversion-only, currently) [David Abdemoulaie]
|
10
|
+
|
11
|
+
* Don't emit -p for sudo when :sudo_prompt is blank [Matthias Marschall]
|
12
|
+
|
13
|
+
* Copy symlinks when using rsync [Paul Paradise]
|
14
|
+
|
15
|
+
* Make sure git query-revision matches on exact branch name [grant@nightriot.com]
|
16
|
+
|
17
|
+
* Use -T <arg> to filter listed tasks by a pattern [Mathias Meyer, Geoffrey Grosenbach]
|
18
|
+
|
19
|
+
* Expose the #scm method on SCM::Base for building custom scm commands [Mathias Meyer]
|
20
|
+
|
21
|
+
* Start logging some locally executed commands [springyweb]
|
22
|
+
|
23
|
+
* Added HOSTFILTER environment variable for constraining tasks so they run only on hosts matching the given list of servers [Walter Smith]
|
24
|
+
|
25
|
+
* Make sure the glob matching for copy excludes does not delete parent directories [Fabio Akita]
|
26
|
+
|
27
|
+
* Ruby 1.9 compatibility [Jamis Buck]
|
28
|
+
|
29
|
+
|
1
30
|
== 2.5.0 / August 28, 2008
|
2
31
|
|
3
32
|
* Allow :gateway to be set to an array, in which case a chain of tunnels is created [Kerry Buckley]
|
data/capistrano.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
|
2
|
-
# Gem::Specification for Capistrano-2.5.
|
2
|
+
# Gem::Specification for Capistrano-2.5.1
|
3
3
|
# Originally generated by Echoe
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = %q{capistrano}
|
7
|
-
s.version = "2.5.
|
7
|
+
s.version = "2.5.1"
|
8
8
|
|
9
9
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
10
|
s.authors = ["Jamis Buck"]
|
11
|
-
s.date = %q{2008-
|
11
|
+
s.date = %q{2008-11-07}
|
12
12
|
s.description = %q{Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH.}
|
13
13
|
s.email = %q{jamis@jamisbuck.org}
|
14
14
|
s.executables = ["cap", "capify"]
|
data/lib/capistrano/cli/help.rb
CHANGED
@@ -12,7 +12,7 @@ module Capistrano
|
|
12
12
|
|
13
13
|
def execute_requested_actions_with_help(config)
|
14
14
|
if options[:tasks]
|
15
|
-
task_list(config)
|
15
|
+
task_list(config, options[:tasks])
|
16
16
|
elsif options[:explain]
|
17
17
|
explain_task(config, options[:explain])
|
18
18
|
else
|
@@ -20,11 +20,19 @@ module Capistrano
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def task_list(config) #:nodoc:
|
24
|
-
|
23
|
+
def task_list(config, pattern = true) #:nodoc:
|
24
|
+
tool_output = options[:tool]
|
25
|
+
|
26
|
+
if pattern.is_a?(String)
|
27
|
+
tasks = config.task_list(:all).select {|t| t.fully_qualified_name =~ /#{pattern}/}
|
28
|
+
end
|
29
|
+
if tasks.nil? || tasks.length == 0
|
30
|
+
warn "Pattern '#{pattern}' not found. Listing all tasks.\n\n" if !tool_output && !pattern.is_a?(TrueClass)
|
31
|
+
tasks = config.task_list(:all)
|
32
|
+
end
|
25
33
|
|
26
34
|
if tasks.empty?
|
27
|
-
warn "There are no tasks available. Please specify a recipe file to load."
|
35
|
+
warn "There are no tasks available. Please specify a recipe file to load." unless tool_output
|
28
36
|
else
|
29
37
|
all_tasks_length = tasks.length
|
30
38
|
if options[:verbose].to_i < 1
|
@@ -38,19 +46,25 @@ module Capistrano
|
|
38
46
|
max_length = MIN_MAX_LEN if max_length < MIN_MAX_LEN
|
39
47
|
|
40
48
|
tasks.each do |task|
|
41
|
-
|
49
|
+
if tool_output
|
50
|
+
puts "cap #{task.fully_qualified_name}"
|
51
|
+
else
|
52
|
+
puts "cap %-#{longest}s # %s" % [task.fully_qualified_name, task.brief_description(max_length)]
|
53
|
+
end
|
42
54
|
end
|
43
55
|
|
44
|
-
|
56
|
+
unless tool_output
|
57
|
+
if all_tasks_length > tasks.length
|
58
|
+
puts
|
59
|
+
puts "Some tasks were not listed, either because they have no description,"
|
60
|
+
puts "or because they are only used internally by other tasks. To see all"
|
61
|
+
puts "tasks, type `#{File.basename($0)} -vT'."
|
62
|
+
end
|
63
|
+
|
45
64
|
puts
|
46
|
-
puts "
|
47
|
-
puts "
|
48
|
-
puts "tasks, type `#{File.basename($0)} -Tv'."
|
65
|
+
puts "Extended help may be available for these tasks."
|
66
|
+
puts "Type `#{File.basename($0)} -e taskname' to view it."
|
49
67
|
end
|
50
|
-
|
51
|
-
puts
|
52
|
-
puts "Extended help may be available for these tasks."
|
53
|
-
puts "Type `#{File.basename($0)} -e taskname' to view it."
|
54
68
|
end
|
55
69
|
end
|
56
70
|
|
@@ -101,4 +115,4 @@ module Capistrano
|
|
101
115
|
end
|
102
116
|
end
|
103
117
|
end
|
104
|
-
end
|
118
|
+
end
|
data/lib/capistrano/cli/help.txt
CHANGED
@@ -43,8 +43,11 @@ The following options are understood:
|
|
43
43
|
<%= color '-s, --set NAME=VALUE', :bold %>
|
44
44
|
Sets the given variable to the given value, after loading all recipe files. This is useful when you want to override the value of a variable which is used in a task. Note that this will set the variables too late for them to affect conditions that are executed as the recipes are loaded.
|
45
45
|
|
46
|
-
<%= color '-T, --tasks', :bold %>
|
47
|
-
Displays the list of all tasks in all loaded recipe files. If a task has no description, or if the description starts with the [internal] tag, the task will not be listed unless you also specify -v.
|
46
|
+
<%= color '-T, --tasks PATTERN', :bold %>
|
47
|
+
Displays the list of all tasks (matching optional PATTERN) in all loaded recipe files. If a task has no description, or if the description starts with the [internal] tag, the task will not be listed unless you also specify -v.
|
48
|
+
|
49
|
+
<%= color '-t, --tool', :bold %>
|
50
|
+
Abbreviates the output of -T for integration with other tools. Without -t, -T will list tasks with their summaries, and may include additional instructive text at the bottom. When integrating with other tools (e.g., bash auto-expansion and the like) that additional text can get in the way. This switch makes it easier for those tools to parse the list of tasks. (The -t switch has no effect if the -T switch is not specified.)
|
48
51
|
|
49
52
|
<%= color '-V, --version', :bold %>
|
50
53
|
Shows the current Capistrano version number and exits.
|
@@ -79,13 +79,21 @@ module Capistrano
|
|
79
79
|
options[:vars][name.to_sym] = value
|
80
80
|
end
|
81
81
|
|
82
|
-
opts.on("-T", "--tasks",
|
83
|
-
"List all tasks in the loaded recipe files."
|
84
|
-
) do
|
85
|
-
options[:tasks] =
|
82
|
+
opts.on("-T", "--tasks [PATTERN]",
|
83
|
+
"List all tasks (matching optional PATTERN) in the loaded recipe files."
|
84
|
+
) do |value|
|
85
|
+
options[:tasks] = if value
|
86
|
+
value
|
87
|
+
else
|
88
|
+
true
|
89
|
+
end
|
86
90
|
options[:verbose] ||= 0
|
87
91
|
end
|
88
92
|
|
93
|
+
opts.on("-t", "--tool",
|
94
|
+
"Abbreviates the output of -T for tool integration."
|
95
|
+
) { options[:tool] = true }
|
96
|
+
|
89
97
|
opts.on("-V", "--version",
|
90
98
|
"Display the Capistrano version, and exit."
|
91
99
|
) do
|
@@ -96,7 +104,10 @@ module Capistrano
|
|
96
104
|
|
97
105
|
opts.on("-v", "--verbose",
|
98
106
|
"Be more verbose. May be given more than once."
|
99
|
-
)
|
107
|
+
) do
|
108
|
+
options[:verbose] ||= 0
|
109
|
+
options[:verbose] += 1
|
110
|
+
end
|
100
111
|
|
101
112
|
opts.on("-X", "--skip-system-config",
|
102
113
|
"Don't load the system config file (capistrano.conf)"
|
@@ -103,7 +103,8 @@ module Capistrano
|
|
103
103
|
command = parameters.first
|
104
104
|
user = options[:as] && "-u #{options.delete(:as)}"
|
105
105
|
|
106
|
-
|
106
|
+
sudo_prompt_option = "-p '#{sudo_prompt}'" unless sudo_prompt.empty?
|
107
|
+
sudo_command = [fetch(:sudo, "sudo"), sudo_prompt_option, user].compact.join(" ")
|
107
108
|
|
108
109
|
if command
|
109
110
|
command = sudo_command + " " + command
|
@@ -131,7 +131,12 @@ module Capistrano
|
|
131
131
|
servers = find_servers_for_task(task, options)
|
132
132
|
|
133
133
|
if servers.empty?
|
134
|
-
|
134
|
+
if ENV['HOSTFILTER']
|
135
|
+
logger.info "skipping `#{task.fully_qualified_name}' because no servers matched"
|
136
|
+
return
|
137
|
+
else
|
138
|
+
raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
|
139
|
+
end
|
135
140
|
end
|
136
141
|
|
137
142
|
if task.continue_on_error?
|
@@ -67,7 +67,7 @@ module Capistrano
|
|
67
67
|
raise ArgumentError, "expected a block" unless block_given?
|
68
68
|
|
69
69
|
namespace_already_defined = namespaces.key?(name)
|
70
|
-
if all_methods.
|
70
|
+
if all_methods.any? { |m| m.to_sym == name } && !namespace_already_defined
|
71
71
|
thing = tasks.key?(name) ? "task" : "method"
|
72
72
|
raise ArgumentError, "defining a namespace named `#{name}' would shadow an existing #{thing} with that name"
|
73
73
|
end
|
@@ -92,7 +92,7 @@ module Capistrano
|
|
92
92
|
raise ArgumentError, "expected a block" unless block_given?
|
93
93
|
|
94
94
|
task_already_defined = tasks.key?(name)
|
95
|
-
if all_methods.
|
95
|
+
if all_methods.any? { |m| m.to_sym == name } && !task_already_defined
|
96
96
|
thing = namespaces.key?(name) ? "namespace" : "method"
|
97
97
|
raise ArgumentError, "defining a task named `#{name}' would shadow an existing #{thing} with that name"
|
98
98
|
end
|
@@ -21,6 +21,9 @@ module Capistrano
|
|
21
21
|
# variable will take precedence over other options. If both HOSTS and
|
22
22
|
# ROLES are given, HOSTS wins.
|
23
23
|
#
|
24
|
+
# Yet additionally, if the HOSTFILTER environment variable is set, it
|
25
|
+
# will limit the result to hosts found in that (comma-separated) list.
|
26
|
+
#
|
24
27
|
# Usage:
|
25
28
|
#
|
26
29
|
# # return all known servers
|
@@ -37,7 +40,7 @@ module Capistrano
|
|
37
40
|
hosts = server_list_from(ENV['HOSTS'] || options[:hosts])
|
38
41
|
|
39
42
|
if hosts.any?
|
40
|
-
hosts.uniq
|
43
|
+
filter_server_list(hosts.uniq)
|
41
44
|
else
|
42
45
|
roles = role_list_from(ENV['ROLES'] || options[:roles] || self.roles.keys)
|
43
46
|
only = options[:only] || {}
|
@@ -46,12 +49,18 @@ module Capistrano
|
|
46
49
|
servers = roles.inject([]) { |list, role| list.concat(self.roles[role]) }
|
47
50
|
servers = servers.select { |server| only.all? { |key,value| server.options[key] == value } }
|
48
51
|
servers = servers.reject { |server| except.any? { |key,value| server.options[key] == value } }
|
49
|
-
servers.uniq
|
52
|
+
filter_server_list(servers.uniq)
|
50
53
|
end
|
51
54
|
end
|
52
55
|
|
53
56
|
protected
|
54
57
|
|
58
|
+
def filter_server_list(servers)
|
59
|
+
return servers unless ENV['HOSTFILTER']
|
60
|
+
filters = ENV['HOSTFILTER'].split(/,/)
|
61
|
+
servers.select { |server| filters.include?(server.host) }
|
62
|
+
end
|
63
|
+
|
55
64
|
def server_list_from(hosts)
|
56
65
|
hosts = hosts.split(/,/) if String === hosts
|
57
66
|
hosts = build_list(hosts)
|
@@ -25,7 +25,7 @@ module Capistrano
|
|
25
25
|
Capistrano::Configuration.protected_instance_methods +
|
26
26
|
Capistrano::Configuration.private_instance_methods
|
27
27
|
|
28
|
-
if methods.
|
28
|
+
if methods.any? { |m| m.to_sym == name }
|
29
29
|
raise Capistrano::Error, "registering a plugin named `#{name}' would shadow a method on Capistrano::Configuration with the same name"
|
30
30
|
end
|
31
31
|
|
data/lib/capistrano/logger.rb
CHANGED
@@ -30,7 +30,7 @@ module Capistrano
|
|
30
30
|
def log(level, message, line_prefix=nil)
|
31
31
|
if level <= self.level
|
32
32
|
indent = "%*s" % [MAX_LEVEL, "*" * (MAX_LEVEL - level)]
|
33
|
-
message.each do |line|
|
33
|
+
(RUBY_VERSION >= "1.9" ? message.lines : message).each do |line|
|
34
34
|
if line_prefix
|
35
35
|
device.puts "#{indent} [#{line_prefix}] #{line.strip}\n"
|
36
36
|
else
|
@@ -34,7 +34,7 @@ _cset(:revision) { source.head }
|
|
34
34
|
# =========================================================================
|
35
35
|
|
36
36
|
_cset(:source) { Capistrano::Deploy::SCM.new(scm, self) }
|
37
|
-
_cset(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") {
|
37
|
+
_cset(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") { run_locally(cmd) } } }
|
38
38
|
|
39
39
|
_cset(:strategy) { Capistrano::Deploy::Strategy.new(deploy_via, self) }
|
40
40
|
|
@@ -90,6 +90,13 @@ ensure
|
|
90
90
|
ENV[name] = saved
|
91
91
|
end
|
92
92
|
|
93
|
+
# logs the command then executes it locally.
|
94
|
+
# returns the command output as a string
|
95
|
+
def run_locally(cmd)
|
96
|
+
logger.trace "executing locally: #{cmd.inspect}" if logger
|
97
|
+
`#{cmd}`
|
98
|
+
end
|
99
|
+
|
93
100
|
# If a command is given, this will try to execute the given command, as
|
94
101
|
# described below. Otherwise, it will return a string for use in embedding in
|
95
102
|
# another command, for executing that command as described below.
|
@@ -9,6 +9,7 @@ module Capistrano
|
|
9
9
|
def initialize(configuration)
|
10
10
|
@configuration = configuration
|
11
11
|
@success = true
|
12
|
+
@hosts = nil
|
12
13
|
end
|
13
14
|
|
14
15
|
def directory(path, options={})
|
@@ -83,7 +84,7 @@ module Capistrano
|
|
83
84
|
|
84
85
|
def message
|
85
86
|
s = @message.dup
|
86
|
-
s << " (#{@hosts})" if @hosts
|
87
|
+
s << " (#{@hosts})" if @hosts
|
87
88
|
s
|
88
89
|
end
|
89
90
|
|
@@ -91,7 +92,7 @@ module Capistrano
|
|
91
92
|
|
92
93
|
def try(command, options)
|
93
94
|
return unless @success # short-circuit evaluation
|
94
|
-
configuration.
|
95
|
+
configuration.invoke_command(command, options) do |ch,stream,out|
|
95
96
|
warn "#{ch[:server]}: #{out}" if stream == :err
|
96
97
|
yield ch, stream, out if block_given?
|
97
98
|
end
|
@@ -54,7 +54,7 @@ module Capistrano
|
|
54
54
|
# and "local_scm_command" to be set, if the two differ.
|
55
55
|
#
|
56
56
|
# Alternatively, it may be called with a block, and for the duration of
|
57
|
-
# the block, all requests on this configuration object will be
|
57
|
+
# the block, all requests on this configuration object will be
|
58
58
|
# considered local.
|
59
59
|
def local
|
60
60
|
if block_given?
|
@@ -150,6 +150,13 @@ module Capistrano
|
|
150
150
|
command || default_command
|
151
151
|
end
|
152
152
|
|
153
|
+
# A helper method that can be used to define SCM commands naturally.
|
154
|
+
# It returns a single string with all arguments joined by spaces,
|
155
|
+
# with the scm command prefixed onto it.
|
156
|
+
def scm(*args)
|
157
|
+
[command, *args].compact.join(" ")
|
158
|
+
end
|
159
|
+
|
153
160
|
private
|
154
161
|
|
155
162
|
# A helper for accessing variable values, which takes into
|
@@ -174,17 +181,14 @@ module Capistrano
|
|
174
181
|
self.class.default_command
|
175
182
|
end
|
176
183
|
|
177
|
-
# A helper method that can be used to define SCM commands naturally.
|
178
|
-
# It returns a single string with all arguments joined by spaces,
|
179
|
-
# with the scm command prefixed onto it.
|
180
|
-
def scm(*args)
|
181
|
-
[command, *args].compact.join(" ")
|
182
|
-
end
|
183
|
-
|
184
184
|
# A convenience method for accessing the declared repository value.
|
185
185
|
def repository
|
186
186
|
variable(:repository)
|
187
187
|
end
|
188
|
+
|
189
|
+
def arguments
|
190
|
+
variable(:scm_arguments)
|
191
|
+
end
|
188
192
|
end
|
189
193
|
|
190
194
|
end
|
@@ -123,9 +123,9 @@ module Capistrano
|
|
123
123
|
def cvs_revision(rev)
|
124
124
|
revision = ""
|
125
125
|
revision << case revision_type(rev)
|
126
|
-
when :date
|
126
|
+
when :date
|
127
127
|
"-D \"#{rev}\"" if revision_type(rev) == :date
|
128
|
-
when :revision
|
128
|
+
when :revision
|
129
129
|
"-r #{rev}"
|
130
130
|
else
|
131
131
|
"-r #{head}"
|
@@ -210,10 +210,17 @@ module Capistrano
|
|
210
210
|
def query_revision(revision)
|
211
211
|
raise ArgumentError, "Deploying remote branches has been deprecated. Specify the remote branch as a local branch for the git repository you're deploying from (ie: '#{revision.gsub('origin/', '')}' rather than '#{revision}')." if revision =~ /^origin\//
|
212
212
|
return revision if revision =~ /^[0-9a-f]{40}$/
|
213
|
-
command = scm('ls-remote', repository, revision)
|
213
|
+
command = scm('ls-remote -h -t', repository, revision)
|
214
214
|
result = yield(command)
|
215
|
-
revdata = result.split(
|
216
|
-
|
215
|
+
revdata = result.split(/[\t\n]/)
|
216
|
+
newrev = nil
|
217
|
+
revdata.each_slice(2) do |refs|
|
218
|
+
rev, ref = *refs
|
219
|
+
if ref.sub(/refs\/.*?\//, '') == revision
|
220
|
+
newrev = rev
|
221
|
+
break
|
222
|
+
end
|
223
|
+
end
|
217
224
|
raise "Unable to resolve revision for '#{revision}' on repository '#{repository}'." unless newrev =~ /^[0-9a-f]{40}$/
|
218
225
|
return newrev
|
219
226
|
end
|
@@ -119,9 +119,9 @@ module Capistrano
|
|
119
119
|
# verbosity configuration grokking :)
|
120
120
|
def verbose
|
121
121
|
case variable(:scm_verbose)
|
122
|
-
when nil
|
123
|
-
when false
|
124
|
-
else
|
122
|
+
when nil then nil
|
123
|
+
when false then "--quiet"
|
124
|
+
else "--verbose"
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
@@ -21,19 +21,19 @@ module Capistrano
|
|
21
21
|
# Returns the command that will check out the given revision to the
|
22
22
|
# given destination.
|
23
23
|
def checkout(revision, destination)
|
24
|
-
scm :checkout, verbose, authentication, "-r#{revision}", repository, destination
|
24
|
+
scm :checkout, arguments, verbose, authentication, "-r#{revision}", repository, destination
|
25
25
|
end
|
26
26
|
|
27
27
|
# Returns the command that will do an "svn update" to the given
|
28
28
|
# revision, for the working copy at the given destination.
|
29
29
|
def sync(revision, destination)
|
30
|
-
scm :update, verbose, authentication, "-r#{revision}", destination
|
30
|
+
scm :update, arguments, verbose, authentication, "-r#{revision}", destination
|
31
31
|
end
|
32
32
|
|
33
33
|
# Returns the command that will do an "svn export" of the given revision
|
34
34
|
# to the given destination.
|
35
35
|
def export(revision, destination)
|
36
|
-
scm :export, verbose, authentication, "-r#{revision}", repository, destination
|
36
|
+
scm :export, arguments, verbose, authentication, "-r#{revision}", repository, destination
|
37
37
|
end
|
38
38
|
|
39
39
|
# Returns the command that will do an "svn diff" for the two revisions.
|
@@ -48,8 +48,17 @@ module Capistrano
|
|
48
48
|
|
49
49
|
# A wrapper for Kernel#system that logs the command being executed.
|
50
50
|
def system(*args)
|
51
|
-
|
52
|
-
|
51
|
+
cmd = args.join(' ')
|
52
|
+
if RUBY_PLATFORM =~ /win32/
|
53
|
+
cmd.gsub!('/','\\') # Replace / with \\
|
54
|
+
cmd.gsub!(/^cd /,'cd /D ') # Replace cd with cd /D
|
55
|
+
cmd.gsub!(/&& cd /,'&& cd /D ') # Replace cd with cd /D
|
56
|
+
logger.trace "executing locally: #{cmd}"
|
57
|
+
super(cmd)
|
58
|
+
else
|
59
|
+
logger.trace "executing locally: #{cmd}"
|
60
|
+
super
|
61
|
+
end
|
53
62
|
end
|
54
63
|
|
55
64
|
private
|
@@ -67,4 +76,4 @@ module Capistrano
|
|
67
76
|
|
68
77
|
end
|
69
78
|
end
|
70
|
-
end
|
79
|
+
end
|
@@ -80,7 +80,14 @@ module Capistrano
|
|
80
80
|
|
81
81
|
if copy_exclude.any?
|
82
82
|
logger.debug "processing exclusions..."
|
83
|
-
copy_exclude.
|
83
|
+
if copy_exclude.any?
|
84
|
+
copy_exclude.each do |pattern|
|
85
|
+
delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
|
86
|
+
# avoid the /.. trap that deletes the parent directories
|
87
|
+
delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
|
88
|
+
FileUtils.rm_rf(delete_list.compact)
|
89
|
+
end
|
90
|
+
end
|
84
91
|
end
|
85
92
|
end
|
86
93
|
|
@@ -42,7 +42,7 @@ module Capistrano
|
|
42
42
|
run "cp -RPp #{repository_cache} #{configuration[:release_path]} && #{mark}"
|
43
43
|
else
|
44
44
|
exclusions = copy_exclude.map { |e| "--exclude=\"#{e}\"" }.join(' ')
|
45
|
-
run "rsync -
|
45
|
+
run "rsync -lrp #{exclusions} #{repository_cache}/* #{configuration[:release_path]} && #{mark}"
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
data/lib/capistrano/version.rb
CHANGED
data/test/cli/help_test.rb
CHANGED
@@ -33,7 +33,7 @@ class CLIHelpTest < Test::Unit::TestCase
|
|
33
33
|
|
34
34
|
def test_execute_requested_actions_with_tasks_should_call_task_list
|
35
35
|
@cli.options[:tasks] = true
|
36
|
-
@cli.expects(:task_list).with(:config)
|
36
|
+
@cli.expects(:task_list).with(:config, true)
|
37
37
|
@cli.expects(:explain_task).never
|
38
38
|
@cli.execute_requested_actions(:config)
|
39
39
|
assert !@cli.called_original
|
@@ -57,13 +57,38 @@ class CLIHelpTest < Test::Unit::TestCase
|
|
57
57
|
expected_max_len = 80 - 3 - MockCLI::LINE_PADDING
|
58
58
|
task_list = [task("c"), task("g", "c:g"), task("b", "c:b"), task("a")]
|
59
59
|
task_list.each { |t| t.expects(:brief_description).with(expected_max_len).returns(t.fully_qualified_name) }
|
60
|
-
|
60
|
+
|
61
61
|
config = mock("config")
|
62
62
|
config.expects(:task_list).with(:all).returns(task_list)
|
63
63
|
@cli.stubs(:puts)
|
64
64
|
@cli.task_list(config)
|
65
65
|
end
|
66
66
|
|
67
|
+
def test_task_list_should_query_tasks_with_pattern
|
68
|
+
expected_max_len = 80 - 3 - MockCLI::LINE_PADDING
|
69
|
+
task_list = [task("g", "c:g"), task("b", "c:b")]
|
70
|
+
task_list.each { |t| t.expects(:brief_description).with(expected_max_len).returns(t.fully_qualified_name)}
|
71
|
+
|
72
|
+
config = mock("config")
|
73
|
+
config.expects(:task_list).with(:all).once.returns(task_list)
|
74
|
+
|
75
|
+
@cli.stubs(:puts)
|
76
|
+
@cli.task_list(config, "c")
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_task_list_should_query_for_all_tasks_when_pattern_doesnt_match
|
80
|
+
expected_max_len = 80 - 3 - MockCLI::LINE_PADDING
|
81
|
+
task_list = [task("g", "c:g"), task("b", "c:b")]
|
82
|
+
task_list.each { |t| t.expects(:brief_description).with(expected_max_len).returns(t.fully_qualified_name) }
|
83
|
+
|
84
|
+
config = mock("config")
|
85
|
+
config.expects(:task_list).with(:all).times(2).returns(task_list)
|
86
|
+
|
87
|
+
@cli.stubs(:warn)
|
88
|
+
@cli.stubs(:puts)
|
89
|
+
@cli.task_list(config, "z")
|
90
|
+
end
|
91
|
+
|
67
92
|
def test_task_list_should_never_use_less_than_MIN_MAX_LEN_chars_for_descriptions
|
68
93
|
@ui.stubs(:output_cols).returns(20)
|
69
94
|
t = task("c")
|
@@ -133,7 +158,8 @@ class CLIHelpTest < Test::Unit::TestCase
|
|
133
158
|
|
134
159
|
private
|
135
160
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
161
|
+
def task(name, fqn=name, desc="a description")
|
162
|
+
stub("task", :name => name, :fully_qualified_name => fqn, :description => desc)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
data/test/cli/options_test.rb
CHANGED
@@ -261,7 +261,8 @@ class CLIOptionsTest < Test::Unit::TestCase
|
|
261
261
|
assert_equal "world", ENV["HELLO"]
|
262
262
|
assert_equal "value", ENV["ANOTHER"]
|
263
263
|
ensure
|
264
|
-
ENV
|
264
|
+
ENV.delete("HELLO")
|
265
|
+
ENV.delete("ANOTHER")
|
265
266
|
end
|
266
267
|
|
267
268
|
def test_remaining_args_should_be_added_to_actions_list
|
@@ -269,7 +270,7 @@ class CLIOptionsTest < Test::Unit::TestCase
|
|
269
270
|
@cli.parse_options!
|
270
271
|
assert_equal %w(something else), @cli.args
|
271
272
|
ensure
|
272
|
-
ENV
|
273
|
+
ENV.delete("HELLO")
|
273
274
|
end
|
274
275
|
|
275
276
|
def test_search_for_default_recipe_file_should_look_for_Capfile
|
@@ -114,6 +114,12 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
114
114
|
@config.sudo "ls", :foo => "bar"
|
115
115
|
end
|
116
116
|
|
117
|
+
def test_sudo_should_avoid_minus_p_when_sudo_prompt_is_empty
|
118
|
+
@config.set :sudo_prompt, ""
|
119
|
+
@config.expects(:run).with("sudo ls", {})
|
120
|
+
@config.sudo "ls"
|
121
|
+
end
|
122
|
+
|
117
123
|
def test_sudo_should_interpret_sudo_prompt_variable_as_custom_prompt
|
118
124
|
@config.set :sudo_prompt, "give it to me: "
|
119
125
|
@config.expects(:run).with("sudo -p 'give it to me: ' ls", {})
|
@@ -23,7 +23,7 @@ class ConfigurationLoadingTest < Test::Unit::TestCase
|
|
23
23
|
|
24
24
|
def teardown
|
25
25
|
MockConfig.instance = nil
|
26
|
-
$
|
26
|
+
$LOADED_FEATURES.delete_if { |a| a =~ /fixtures\/custom\.rb$/ }
|
27
27
|
end
|
28
28
|
|
29
29
|
def test_initialize_should_init_collections
|
@@ -108,9 +108,9 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def test_defining_ask_should_add_task_as_method
|
111
|
-
assert !@config.methods.
|
111
|
+
assert !@config.methods.any? { |m| m.to_sym == :original }
|
112
112
|
@config.task(:original) { puts "foo" }
|
113
|
-
assert @config.methods.
|
113
|
+
assert @config.methods.any? { |m| m.to_sym == :original }
|
114
114
|
end
|
115
115
|
|
116
116
|
def test_calling_defined_task_should_delegate_to_execute_task
|
@@ -59,7 +59,7 @@ class ConfigurationServersTest < Test::Unit::TestCase
|
|
59
59
|
task = new_task(:testing)
|
60
60
|
assert_equal %w(app1 app2 app3 file).sort, @config.find_servers_for_task(task).map { |s| s.host }.sort
|
61
61
|
ensure
|
62
|
-
ENV
|
62
|
+
ENV.delete('ROLES')
|
63
63
|
end
|
64
64
|
|
65
65
|
def test_task_with_hosts_as_environment_variable_should_apply_only_to_those_hosts
|
@@ -67,7 +67,7 @@ class ConfigurationServersTest < Test::Unit::TestCase
|
|
67
67
|
task = new_task(:testing)
|
68
68
|
assert_equal %w(foo bar).sort, @config.find_servers_for_task(task).map { |s| s.host }.sort
|
69
69
|
ensure
|
70
|
-
ENV
|
70
|
+
ENV.delete('HOSTS')
|
71
71
|
end
|
72
72
|
|
73
73
|
def test_task_with_hosts_as_environment_variable_should_not_inspect_roles_at_all
|
@@ -75,7 +75,23 @@ class ConfigurationServersTest < Test::Unit::TestCase
|
|
75
75
|
task = new_task(:testing, @config, :roles => :bogus)
|
76
76
|
assert_equal %w(foo bar).sort, @config.find_servers_for_task(task).map { |s| s.host }.sort
|
77
77
|
ensure
|
78
|
-
ENV
|
78
|
+
ENV.delete('HOSTS')
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_task_with_onlyhosts_environment_variable_should_apply_only_to_those_hosts
|
82
|
+
ENV['HOSTFILTER'] = "app1,web1"
|
83
|
+
task = new_task(:testing)
|
84
|
+
assert_equal %w(app1 web1).sort, @config.find_servers_for_task(task).map { |s| s.host }.sort
|
85
|
+
ensure
|
86
|
+
ENV.delete('HOSTFILTER')
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_task_with_onlyhosts_environment_variable_should_filter_hosts_option
|
90
|
+
ENV['HOSTFILTER'] = "foo"
|
91
|
+
task = new_task(:testing, @config, :hosts => %w(foo bar))
|
92
|
+
assert_equal %w(foo).sort, @config.find_servers_for_task(task).map { |s| s.host }.sort
|
93
|
+
ensure
|
94
|
+
ENV.delete('HOSTFILTER')
|
79
95
|
end
|
80
96
|
|
81
97
|
def test_task_with_only_should_apply_only_to_matching_tasks
|
@@ -96,7 +96,7 @@ class RemoteDependencyTest < Test::Unit::TestCase
|
|
96
96
|
private
|
97
97
|
|
98
98
|
def setup_for_a_configuration_run(command, passing)
|
99
|
-
expectation = @config.expects(:
|
99
|
+
expectation = @config.expects(:invoke_command).with(command, {})
|
100
100
|
if passing
|
101
101
|
expectation.returns(true)
|
102
102
|
else
|
data/test/deploy/scm/git_test.rb
CHANGED
@@ -59,7 +59,7 @@ class DeploySCMGitTest < Test::Unit::TestCase
|
|
59
59
|
|
60
60
|
def test_query_revision
|
61
61
|
revision = @source.query_revision('HEAD') do |o|
|
62
|
-
assert_equal "git ls-remote . HEAD", o
|
62
|
+
assert_equal "git ls-remote -h -t . HEAD", o
|
63
63
|
"d11006102c07c94e5d54dd0ee63dca825c93ed61\tHEAD"
|
64
64
|
end
|
65
65
|
assert_equal "d11006102c07c94e5d54dd0ee63dca825c93ed61", revision
|
@@ -29,9 +29,9 @@ class DeployStrategyCopyTest < Test::Unit::TestCase
|
|
29
29
|
Dir.expects(:tmpdir).returns("/temp/dir")
|
30
30
|
@source.expects(:checkout).with("154", "/temp/dir/1234567890").returns(:local_checkout)
|
31
31
|
@strategy.expects(:system).with(:local_checkout)
|
32
|
-
Dir.expects(:glob).with("/temp/dir/1234567890/.git", File::FNM_DOTMATCH).returns(
|
32
|
+
Dir.expects(:glob).with("/temp/dir/1234567890/.git", File::FNM_DOTMATCH).returns(%w(/temp/dir/1234567890/.git))
|
33
33
|
|
34
|
-
FileUtils.expects(:rm_rf).with(
|
34
|
+
FileUtils.expects(:rm_rf).with(%w(/temp/dir/1234567890/.git))
|
35
35
|
prepare_standard_compress_and_copy!
|
36
36
|
@strategy.deploy!
|
37
37
|
end
|
@@ -41,9 +41,9 @@ class DeployStrategyCopyTest < Test::Unit::TestCase
|
|
41
41
|
Dir.expects(:tmpdir).returns("/temp/dir")
|
42
42
|
@source.expects(:checkout).with("154", "/temp/dir/1234567890").returns(:local_checkout)
|
43
43
|
@strategy.expects(:system).with(:local_checkout)
|
44
|
-
Dir.expects(:glob).with("/temp/dir/1234567890/.gi*", File::FNM_DOTMATCH).returns(
|
44
|
+
Dir.expects(:glob).with("/temp/dir/1234567890/.gi*", File::FNM_DOTMATCH).returns(%w(/temp/dir/1234567890/.git))
|
45
45
|
|
46
|
-
FileUtils.expects(:rm_rf).with(
|
46
|
+
FileUtils.expects(:rm_rf).with(%w(/temp/dir/1234567890/.git))
|
47
47
|
prepare_standard_compress_and_copy!
|
48
48
|
@strategy.deploy!
|
49
49
|
end
|
data/test/role_test.rb
CHANGED
@@ -3,7 +3,7 @@ require 'capistrano/role'
|
|
3
3
|
|
4
4
|
class RoleTest < Test::Unit::TestCase
|
5
5
|
def test_clearing_a_populated_role_should_yield_no_servers
|
6
|
-
role = Capistrano::Role.new("app1.capistrano.test", lambda { "app2.capistrano.test" })
|
6
|
+
role = Capistrano::Role.new("app1.capistrano.test", lambda { |o| "app2.capistrano.test" })
|
7
7
|
assert_equal 2, role.servers.size
|
8
8
|
role.clear
|
9
9
|
assert role.servers.empty?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamis Buck
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-11-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|