capistrano 2.5.0 → 2.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|