capistrano 2.5.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/CHANGELOG.rdoc +29 -0
  2. data/capistrano.gemspec +3 -3
  3. data/lib/capistrano/cli/help.rb +28 -14
  4. data/lib/capistrano/cli/help.txt +5 -2
  5. data/lib/capistrano/cli/options.rb +16 -5
  6. data/lib/capistrano/configuration/actions/invocation.rb +2 -1
  7. data/lib/capistrano/configuration/connections.rb +6 -1
  8. data/lib/capistrano/configuration/namespaces.rb +2 -2
  9. data/lib/capistrano/configuration/servers.rb +11 -2
  10. data/lib/capistrano/extensions.rb +1 -1
  11. data/lib/capistrano/logger.rb +1 -1
  12. data/lib/capistrano/recipes/deploy.rb +8 -1
  13. data/lib/capistrano/recipes/deploy/remote_dependency.rb +3 -2
  14. data/lib/capistrano/recipes/deploy/scm/base.rb +12 -8
  15. data/lib/capistrano/recipes/deploy/scm/cvs.rb +2 -2
  16. data/lib/capistrano/recipes/deploy/scm/git.rb +10 -3
  17. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +3 -3
  18. data/lib/capistrano/recipes/deploy/scm/subversion.rb +3 -3
  19. data/lib/capistrano/recipes/deploy/strategy/base.rb +12 -3
  20. data/lib/capistrano/recipes/deploy/strategy/copy.rb +8 -1
  21. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +1 -1
  22. data/lib/capistrano/version.rb +1 -1
  23. data/test/cli/help_test.rb +32 -6
  24. data/test/cli/options_test.rb +3 -2
  25. data/test/configuration/actions/invocation_test.rb +6 -0
  26. data/test/configuration/loading_test.rb +1 -1
  27. data/test/configuration/namespace_dsl_test.rb +2 -2
  28. data/test/configuration/servers_test.rb +19 -3
  29. data/test/deploy/remote_dependency_test.rb +1 -1
  30. data/test/deploy/scm/git_test.rb +1 -1
  31. data/test/deploy/strategy/copy_test.rb +4 -4
  32. data/test/role_test.rb +1 -1
  33. metadata +2 -2
@@ -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]
@@ -1,14 +1,14 @@
1
1
 
2
- # Gem::Specification for Capistrano-2.5.0
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.0"
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-08-28}
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"]
@@ -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
- tasks = config.task_list(:all)
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
- puts "cap %-#{longest}s # %s" % [task.fully_qualified_name, task.brief_description(max_length)]
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
- if all_tasks_length > tasks.length
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 "Some tasks were not listed, either because they have no description,"
47
- puts "or because they are only used internally by other tasks. To see all"
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
@@ -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] = true
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
- ) { options[:verbose] ||= 0; options[:verbose] += 1 }
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
- sudo_command = [fetch(:sudo, "sudo"), "-p '#{sudo_prompt}'", user].compact.join(" ")
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
- raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
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.include?(name.to_s) && !namespace_already_defined
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.include?(name.to_s) && !task_already_defined
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.include?(name.to_s)
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
 
@@ -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") { `#{cmd}` } } }
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 && @hosts.any?
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.run(command, options) do |ch,stream,out|
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("\t")
216
- newrev = revdata[0]
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: nil
123
- when false: "--quiet"
124
- else "--verbose"
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
- logger.trace "executing locally: #{args.join(' ')}"
52
- super
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.each { |pattern| FileUtils.rm_rf(Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)) }
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 -rp #{exclusions} #{repository_cache}/* #{configuration[:release_path]} && #{mark}"
45
+ run "rsync -lrp #{exclusions} #{repository_cache}/* #{configuration[:release_path]} && #{mark}"
46
46
  end
47
47
  end
48
48
 
@@ -6,7 +6,7 @@ module Capistrano
6
6
  class Version < Net::SSH::Version
7
7
  MAJOR = 2
8
8
  MINOR = 5
9
- TINY = 0
9
+ TINY = 1
10
10
 
11
11
  # The current version, as a Version instance
12
12
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -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
- def task(name, fqn=name, desc="a description")
137
- stub("task", :name => name, :fully_qualified_name => fqn, :description => desc)
138
- end
139
- end
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
@@ -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["HELLO"] = ENV["ANOTHER"] = nil
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["HELLO"] = nil
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
- $".delete "#{File.dirname(__FILE__)}/../fixtures/custom.rb"
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.include?("original")
111
+ assert !@config.methods.any? { |m| m.to_sym == :original }
112
112
  @config.task(:original) { puts "foo" }
113
- assert @config.methods.include?("original")
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['ROLES'] = nil
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['HOSTS'] = nil
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['HOSTS'] = nil
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(:run).with(command, {})
99
+ expectation = @config.expects(:invoke_command).with(command, {})
100
100
  if passing
101
101
  expectation.returns(true)
102
102
  else
@@ -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("/temp/dir/1234567890/.git")
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("/temp/dir/1234567890/.git")
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("/temp/dir/1234567890/.git")
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("/temp/dir/1234567890/.git")
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
@@ -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.0
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-08-28 00:00:00 -06:00
12
+ date: 2008-11-07 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency