capistrano 2.3.0 → 2.4.0
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 +50 -2
- data/lib/capistrano/cli/execute.rb +1 -0
- data/lib/capistrano/cli/options.rb +4 -0
- data/lib/capistrano/cli/ui.rb +13 -0
- data/lib/capistrano/command.rb +2 -2
- data/lib/capistrano/configuration.rb +2 -1
- data/lib/capistrano/configuration/actions/file_transfer.rb +5 -1
- data/lib/capistrano/configuration/actions/invocation.rb +45 -18
- data/lib/capistrano/configuration/callbacks.rb +3 -3
- data/lib/capistrano/configuration/execution.rb +8 -3
- data/lib/capistrano/configuration/loading.rb +20 -21
- data/lib/capistrano/recipes/deploy.rb +56 -27
- data/lib/capistrano/recipes/deploy/local_dependency.rb +6 -2
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +2 -0
- data/lib/capistrano/recipes/deploy/scm/git.rb +21 -12
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +2 -1
- data/lib/capistrano/recipes/deploy/scm/subversion.rb +2 -1
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +22 -34
- data/lib/capistrano/recipes/deploy/strategy/remote.rb +1 -1
- data/lib/capistrano/version.rb +1 -14
- data/test/cli/execute_test.rb +1 -1
- data/test/cli/options_test.rb +7 -1
- data/test/configuration/actions/file_transfer_test.rb +20 -1
- data/test/configuration/actions/invocation_test.rb +16 -10
- data/test/configuration/callbacks_test.rb +16 -2
- data/test/configuration/loading_test.rb +6 -1
- data/test/deploy/local_dependency_test.rb +73 -0
- data/test/deploy/remote_dependency_test.rb +114 -0
- data/test/deploy/scm/git_test.rb +22 -8
- data/test/deploy/scm/mercurial_test.rb +10 -4
- data/test/deploy/strategy/copy_test.rb +16 -11
- data/test/role_test.rb +11 -0
- data/test/server_definition_test.rb +14 -1
- metadata +5 -3
- data/test/version_test.rb +0 -24
@@ -30,7 +30,7 @@ module Capistrano
|
|
30
30
|
# file is found that matches the parameter, this returns true.
|
31
31
|
def find_in_path(utility)
|
32
32
|
path = (ENV['PATH'] || "").split(File::PATH_SEPARATOR)
|
33
|
-
suffixes =
|
33
|
+
suffixes = self.class.on_windows? ? %w(.bat .exe .com .cmd) : [""]
|
34
34
|
|
35
35
|
path.each do |dir|
|
36
36
|
suffixes.each do |sfx|
|
@@ -41,6 +41,10 @@ module Capistrano
|
|
41
41
|
|
42
42
|
false
|
43
43
|
end
|
44
|
+
|
45
|
+
def self.on_windows?
|
46
|
+
RUBY_PLATFORM =~ /mswin/
|
47
|
+
end
|
44
48
|
end
|
45
49
|
end
|
46
|
-
end
|
50
|
+
end
|
@@ -141,17 +141,17 @@ module Capistrano
|
|
141
141
|
|
142
142
|
execute = []
|
143
143
|
if args.empty?
|
144
|
-
execute << "#{git} clone #{configuration[:repository]} #{destination}"
|
144
|
+
execute << "#{git} clone #{verbose} #{configuration[:repository]} #{destination}"
|
145
145
|
else
|
146
|
-
execute << "#{git} clone #{args.join(' ')} #{configuration[:repository]} #{destination}"
|
146
|
+
execute << "#{git} clone #{verbose} #{args.join(' ')} #{configuration[:repository]} #{destination}"
|
147
147
|
end
|
148
148
|
|
149
149
|
# checkout into a local branch rather than a detached HEAD
|
150
|
-
execute << "cd #{destination} && #{git} checkout -b deploy #{revision}"
|
150
|
+
execute << "cd #{destination} && #{git} checkout #{verbose} -b deploy #{revision}"
|
151
151
|
|
152
152
|
if configuration[:git_enable_submodules]
|
153
|
-
execute << "#{git} submodule init"
|
154
|
-
execute << "#{git} submodule update"
|
153
|
+
execute << "#{git} submodule #{verbose} init"
|
154
|
+
execute << "#{git} submodule #{verbose} update"
|
155
155
|
end
|
156
156
|
|
157
157
|
execute.join(" && ")
|
@@ -184,11 +184,11 @@ module Capistrano
|
|
184
184
|
end
|
185
185
|
|
186
186
|
# since we're in a local branch already, just reset to specified revision rather than merge
|
187
|
-
execute << "#{git} fetch
|
187
|
+
execute << "#{git} fetch #{verbose} #{remote} && #{git} reset #{verbose} --hard #{revision}"
|
188
188
|
|
189
189
|
if configuration[:git_enable_submodules]
|
190
|
-
execute << "#{git} submodule init"
|
191
|
-
execute << "#{git} submodule update"
|
190
|
+
execute << "#{git} submodule #{verbose} init"
|
191
|
+
execute << "#{git} submodule #{verbose} update"
|
192
192
|
end
|
193
193
|
|
194
194
|
execute.join(" && ")
|
@@ -202,19 +202,19 @@ module Capistrano
|
|
202
202
|
|
203
203
|
# Returns a log of changes between the two revisions (inclusive).
|
204
204
|
def log(from, to=nil)
|
205
|
-
|
206
|
-
scm :log, from
|
205
|
+
scm :log, "#{from}..#{to}"
|
207
206
|
end
|
208
207
|
|
209
208
|
# Getting the actual commit id, in case we were passed a tag
|
210
209
|
# or partial sha or something - it will return the sha if you pass a sha, too
|
211
210
|
def query_revision(revision)
|
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
213
|
command = scm('ls-remote', repository, revision)
|
214
214
|
result = yield(command)
|
215
215
|
revdata = result.split("\t")
|
216
216
|
newrev = revdata[0]
|
217
|
-
raise "Unable to resolve revision for #{revision}" unless newrev =~ /^[0-9a-f]{40}$/
|
217
|
+
raise "Unable to resolve revision for '#{revision}' on repository '#{repository}'." unless newrev =~ /^[0-9a-f]{40}$/
|
218
218
|
return newrev
|
219
219
|
end
|
220
220
|
|
@@ -227,7 +227,8 @@ module Capistrano
|
|
227
227
|
# from the SCM. Password prompts, connection requests, passphrases,
|
228
228
|
# etc. are handled here.
|
229
229
|
def handle_data(state, stream, text)
|
230
|
-
|
230
|
+
host = state[:channel][:host]
|
231
|
+
logger.info "[#{host} :: #{stream}] #{text}"
|
231
232
|
case text
|
232
233
|
when /\bpassword.*:/i
|
233
234
|
# git is prompting for a password
|
@@ -249,6 +250,14 @@ module Capistrano
|
|
249
250
|
"t\n"
|
250
251
|
end
|
251
252
|
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
# If verbose output is requested, return nil, otherwise return the
|
257
|
+
# command-line switch for "quiet" ("-q").
|
258
|
+
def verbose
|
259
|
+
variable(:scm_verbose) ? nil : "-q"
|
260
|
+
end
|
252
261
|
end
|
253
262
|
end
|
254
263
|
end
|
@@ -67,7 +67,8 @@ module Capistrano
|
|
67
67
|
# user/pass can come from ssh and http distribution methods
|
68
68
|
# yes/no is for when ssh asks you about fingerprints
|
69
69
|
def handle_data(state, stream, text)
|
70
|
-
|
70
|
+
host = state[:channel][:host]
|
71
|
+
logger.info "[#{host} :: #{stream}] #{text}"
|
71
72
|
case text
|
72
73
|
when /^user:/mi
|
73
74
|
# support :scm_user for backwards compatibility of this module
|
@@ -68,7 +68,8 @@ module Capistrano
|
|
68
68
|
# from the SCM. Password prompts, connection requests, passphrases,
|
69
69
|
# etc. are handled here.
|
70
70
|
def handle_data(state, stream, text)
|
71
|
-
|
71
|
+
host = state[:channel][:host]
|
72
|
+
logger.info "[#{host} :: #{stream}] #{text}"
|
72
73
|
case text
|
73
74
|
when /\bpassword.*:/i
|
74
75
|
# subversion is prompting for a password
|
@@ -64,7 +64,9 @@ module Capistrano
|
|
64
64
|
next if name == "." || name == ".."
|
65
65
|
next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }
|
66
66
|
|
67
|
-
if File.
|
67
|
+
if File.symlink?(item)
|
68
|
+
FileUtils.ln_s(File.readlink(File.join(copy_cache, item)), File.join(destination, item))
|
69
|
+
elsif File.directory?(item)
|
68
70
|
queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
|
69
71
|
FileUtils.mkdir(File.join(destination, item))
|
70
72
|
else
|
@@ -87,8 +89,7 @@ module Capistrano
|
|
87
89
|
logger.trace "compressing #{destination} to #{filename}"
|
88
90
|
Dir.chdir(tmpdir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
|
89
91
|
|
90
|
-
|
91
|
-
put content, remote_filename
|
92
|
+
upload(filename, remote_filename)
|
92
93
|
run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
|
93
94
|
ensure
|
94
95
|
FileUtils.rm filename rescue nil
|
@@ -97,7 +98,7 @@ module Capistrano
|
|
97
98
|
|
98
99
|
def check!
|
99
100
|
super.check do |d|
|
100
|
-
d.local.command(source.local.command)
|
101
|
+
d.local.command(source.local.command) if source.local.command
|
101
102
|
d.local.command(compress(nil, nil).first)
|
102
103
|
d.remote.command(decompress(nil).first)
|
103
104
|
end
|
@@ -147,7 +148,7 @@ module Capistrano
|
|
147
148
|
# Returns the name of the file that the source code will be
|
148
149
|
# compressed to.
|
149
150
|
def filename
|
150
|
-
@filename ||= File.join(tmpdir, "#{File.basename(destination)}.#{
|
151
|
+
@filename ||= File.join(tmpdir, "#{File.basename(destination)}.#{compression.extension}")
|
151
152
|
end
|
152
153
|
|
153
154
|
# The directory to which the copy should be checked out
|
@@ -167,46 +168,33 @@ module Capistrano
|
|
167
168
|
@remote_filename ||= File.join(remote_dir, File.basename(filename))
|
168
169
|
end
|
169
170
|
|
171
|
+
# A struct for representing the specifics of a compression type.
|
172
|
+
# Commands are arrays, where the first element is the utility to be
|
173
|
+
# used to perform the compression or decompression.
|
174
|
+
Compression = Struct.new(:extension, :compress_command, :decompress_command)
|
175
|
+
|
170
176
|
# The compression method to use, defaults to :gzip.
|
171
177
|
def compression
|
172
|
-
configuration[:copy_compression] || :gzip
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
case compression
|
179
|
-
when :gzip, :gz then "tar.gz"
|
180
|
-
when :bzip2, :bz2 then "tar.bz2"
|
181
|
-
when :zip then "zip"
|
182
|
-
else raise ArgumentError, "invalid compression type #{compression.inspect}"
|
178
|
+
type = configuration[:copy_compression] || :gzip
|
179
|
+
case type
|
180
|
+
when :gzip, :gz then Compression.new("tar.gz", %w(tar czf), %w(tar xzf))
|
181
|
+
when :bzip2, :bz2 then Compression.new("tar.bz2", %w(tar cjf), %w(tar xjf))
|
182
|
+
when :zip then Compression.new("zip", %w(zip -qr), %w(unzip -q))
|
183
|
+
else raise ArgumentError, "invalid compression type #{type.inspect}"
|
183
184
|
end
|
184
185
|
end
|
185
|
-
|
186
|
+
|
186
187
|
# Returns the command necessary to compress the given directory
|
187
|
-
# into the given file.
|
188
|
-
# the first element is the utility to be used to perform the compression.
|
188
|
+
# into the given file.
|
189
189
|
def compress(directory, file)
|
190
|
-
|
191
|
-
when :gzip, :gz then ["tar", "czf", file, directory]
|
192
|
-
when :bzip2, :bz2 then ["tar", "cjf", file, directory]
|
193
|
-
when :zip then ["zip", "-qr", file, directory]
|
194
|
-
else raise ArgumentError, "invalid compression type #{compression.inspect}"
|
195
|
-
end
|
190
|
+
compression.compress_command + [file, directory]
|
196
191
|
end
|
197
192
|
|
198
193
|
# Returns the command necessary to decompress the given file,
|
199
194
|
# relative to the current working directory. It must also
|
200
|
-
# preserve the directory structure in the file.
|
201
|
-
# as an array, where the first element is the utility to be used to
|
202
|
-
# perform the decompression.
|
195
|
+
# preserve the directory structure in the file.
|
203
196
|
def decompress(file)
|
204
|
-
|
205
|
-
when :gzip, :gz then ["tar", "xzf", file]
|
206
|
-
when :bzip2, :bz2 then ["tar", "xjf", file]
|
207
|
-
when :zip then ["unzip", "-q", file]
|
208
|
-
else raise ArgumentError, "invalid compression type #{compression.inspect}"
|
209
|
-
end
|
197
|
+
compression.decompress_command + [file]
|
210
198
|
end
|
211
199
|
end
|
212
200
|
|
@@ -27,7 +27,7 @@ module Capistrano
|
|
27
27
|
# #handle_data filter of the SCM implementation.
|
28
28
|
def scm_run(command)
|
29
29
|
run(command) do |ch,stream,text|
|
30
|
-
ch[:state] ||= {}
|
30
|
+
ch[:state] ||= { :channel => ch }
|
31
31
|
output = source.handle_data(ch[:state], stream, text)
|
32
32
|
ch.send_data(output) if output
|
33
33
|
end
|
data/lib/capistrano/version.rb
CHANGED
@@ -1,22 +1,9 @@
|
|
1
1
|
module Capistrano
|
2
2
|
module Version #:nodoc:
|
3
|
-
# A method for comparing versions of required modules. It expects two
|
4
|
-
# arrays of integers as parameters, the first being the minimum version
|
5
|
-
# required, and the second being the actual version available. It returns
|
6
|
-
# true if the actual version is at least equal to the required version.
|
7
|
-
def self.check(required, actual) #:nodoc:
|
8
|
-
required = required.map { |v| "%06d" % v }.join(".")
|
9
|
-
actual = actual.map { |v| "%06d" % v }.join(".")
|
10
|
-
return actual >= required
|
11
|
-
end
|
12
|
-
|
13
3
|
MAJOR = 2
|
14
|
-
MINOR =
|
4
|
+
MINOR = 4
|
15
5
|
TINY = 0
|
16
6
|
|
17
7
|
STRING = [MAJOR, MINOR, TINY].join(".")
|
18
|
-
|
19
|
-
SSH_REQUIRED = [1,0,10]
|
20
|
-
SFTP_REQUIRED = [1,1,0]
|
21
8
|
end
|
22
9
|
end
|
data/test/cli/execute_test.rb
CHANGED
@@ -15,7 +15,7 @@ class CLIExecuteTest < Test::Unit::TestCase
|
|
15
15
|
def setup
|
16
16
|
@cli = MockCLI.new
|
17
17
|
@logger = stub_everything
|
18
|
-
@config = stub(:logger => @logger)
|
18
|
+
@config = stub(:logger => @logger, :debug= => nil)
|
19
19
|
@config.stubs(:set)
|
20
20
|
@config.stubs(:load)
|
21
21
|
@config.stubs(:trigger)
|
data/test/cli/options_test.rb
CHANGED
@@ -24,6 +24,12 @@ class CLIOptionsTest < Test::Unit::TestCase
|
|
24
24
|
assert_raises(ExitException) { @cli.parse_options! }
|
25
25
|
end
|
26
26
|
|
27
|
+
def test_parse_options_with_d_should_set_debug_option
|
28
|
+
@cli.args << "-d"
|
29
|
+
@cli.parse_options!
|
30
|
+
assert @cli.options[:debug]
|
31
|
+
end
|
32
|
+
|
27
33
|
def test_parse_options_with_e_should_set_explain_option
|
28
34
|
@cli.args << "-e" << "sample"
|
29
35
|
@cli.parse_options!
|
@@ -223,4 +229,4 @@ class CLIOptionsTest < Test::Unit::TestCase
|
|
223
229
|
MockCLI.expects(:new).with(%w(a b c)).returns(cli)
|
224
230
|
assert_equal cli, MockCLI.parse(%w(a b c))
|
225
231
|
end
|
226
|
-
end
|
232
|
+
end
|
@@ -14,7 +14,8 @@ class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
|
|
14
14
|
|
15
15
|
def test_put_should_delegate_to_upload
|
16
16
|
@config.expects(:upload).with { |from, to, opts|
|
17
|
-
from.string == "some data" && to == "test.txt" && opts == { :
|
17
|
+
from.string == "some data" && to == "test.txt" && opts == { :mode => 0777 } }
|
18
|
+
@config.expects(:run).never
|
18
19
|
@config.put("some data", "test.txt", :mode => 0777)
|
19
20
|
end
|
20
21
|
|
@@ -28,6 +29,24 @@ class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
|
|
28
29
|
@config.upload("testl.txt", "testr.txt", :foo => "bar")
|
29
30
|
end
|
30
31
|
|
32
|
+
def test_upload_without_mode_should_not_try_to_chmod
|
33
|
+
@config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
|
34
|
+
@config.expects(:run).never
|
35
|
+
@config.upload("testl.txt", "testr.txt", :foo => "bar")
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_upload_with_mode_should_try_to_chmod
|
39
|
+
@config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
|
40
|
+
@config.expects(:run).with("chmod 775 testr.txt")
|
41
|
+
@config.upload("testl.txt", "testr.txt", :mode => 0775, :foo => "bar")
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_upload_with_symbolic_mode_should_try_to_chmod
|
45
|
+
@config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
|
46
|
+
@config.expects(:run).with("chmod g+w testr.txt")
|
47
|
+
@config.upload("testl.txt", "testr.txt", :mode => "g+w", :foo => "bar")
|
48
|
+
end
|
49
|
+
|
31
50
|
def test_download_should_delegate_to_transfer
|
32
51
|
@config.expects(:transfer).with(:down, "testr.txt", "testl.txt", :foo => "bar")
|
33
52
|
@config.download("testr.txt", "testl.txt", :foo => "bar")
|
@@ -4,6 +4,7 @@ require 'capistrano/configuration/actions/invocation'
|
|
4
4
|
class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
5
5
|
class MockConfig
|
6
6
|
attr_reader :options
|
7
|
+
attr_accessor :debug
|
7
8
|
|
8
9
|
def initialize
|
9
10
|
@options = {}
|
@@ -75,6 +76,11 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
75
76
|
assert_equal({:foo => "bar", :shell => "/bin/bash"}, @config.add_default_command_options(:foo => "bar"))
|
76
77
|
end
|
77
78
|
|
79
|
+
def test_add_default_command_options_should_use_default_shell_of_false_if_present
|
80
|
+
@config.set :default_shell, false
|
81
|
+
assert_equal({:foo => "bar", :shell => false}, @config.add_default_command_options(:foo => "bar"))
|
82
|
+
end
|
83
|
+
|
78
84
|
def test_add_default_command_options_should_use_shell_in_preference_of_default_shell
|
79
85
|
@config.set :default_shell, "/bin/bash"
|
80
86
|
assert_equal({:foo => "bar", :shell => "/bin/sh"}, @config.add_default_command_options(:foo => "bar", :shell => "/bin/sh"))
|
@@ -97,29 +103,29 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
97
103
|
end
|
98
104
|
|
99
105
|
def test_sudo_should_default_to_sudo
|
100
|
-
@config.expects(:run).with("
|
106
|
+
@config.expects(:run).with("sudo -p 'sudo password: ' ls", {})
|
101
107
|
@config.sudo "ls"
|
102
108
|
end
|
103
109
|
|
104
110
|
def test_sudo_should_use_sudo_variable_definition
|
105
|
-
@config.expects(:run).with("
|
111
|
+
@config.expects(:run).with("/opt/local/bin/sudo -p 'sudo password: ' ls", {})
|
106
112
|
@config.options[:sudo] = "/opt/local/bin/sudo"
|
107
113
|
@config.sudo "ls"
|
108
114
|
end
|
109
115
|
|
110
116
|
def test_sudo_should_interpret_as_option_as_user
|
111
|
-
@config.expects(:run).with("
|
117
|
+
@config.expects(:run).with("sudo -p 'sudo password: ' -u app ls", {})
|
112
118
|
@config.sudo "ls", :as => "app"
|
113
119
|
end
|
114
120
|
|
115
121
|
def test_sudo_should_pass_options_through_to_run
|
116
|
-
@config.expects(:run).with("
|
122
|
+
@config.expects(:run).with("sudo -p 'sudo password: ' ls", :foo => "bar")
|
117
123
|
@config.sudo "ls", :foo => "bar"
|
118
124
|
end
|
119
125
|
|
120
126
|
def test_sudo_should_interpret_sudo_prompt_variable_as_custom_prompt
|
121
127
|
@config.set :sudo_prompt, "give it to me: "
|
122
|
-
@config.expects(:run).with("
|
128
|
+
@config.expects(:run).with("sudo -p 'give it to me: ' ls", {})
|
123
129
|
@config.sudo "ls"
|
124
130
|
end
|
125
131
|
|
@@ -143,7 +149,7 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
143
149
|
ch.stubs(:[]).with(:host).returns("capistrano")
|
144
150
|
ch.stubs(:[]).with(:server).returns(server("capistrano"))
|
145
151
|
@config.expects(:reset!).with(:password)
|
146
|
-
@config.sudo_behavior_callback(nil)[ch, nil, "
|
152
|
+
@config.sudo_behavior_callback(nil)[ch, nil, "Sorry, try again."]
|
147
153
|
end
|
148
154
|
|
149
155
|
def test_sudo_behavior_callback_with_incorrect_password_on_subsequent_prompts
|
@@ -158,9 +164,9 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
158
164
|
|
159
165
|
@config.expects(:reset!).with(:password).times(2)
|
160
166
|
|
161
|
-
callback[ch, nil, "
|
162
|
-
callback[ch2, nil, "
|
163
|
-
callback[ch, nil, "
|
167
|
+
callback[ch, nil, "Sorry, try again."]
|
168
|
+
callback[ch2, nil, "Sorry, try again."] # shouldn't call reset!
|
169
|
+
callback[ch, nil, "Sorry, try again."]
|
164
170
|
end
|
165
171
|
|
166
172
|
def test_sudo_behavior_callback_should_defer_to_fallback_for_other_output
|
@@ -199,4 +205,4 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|
199
205
|
c = mock("data", :called => true)
|
200
206
|
Capistrano::Command.expects(:process).with(command, sessions, options).yields(a, b, c)
|
201
207
|
end
|
202
|
-
end
|
208
|
+
end
|
@@ -12,9 +12,15 @@ class ConfigurationCallbacksTest < Test::Unit::TestCase
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def execute_task(task)
|
15
|
-
|
15
|
+
invoke_task_directly(task)
|
16
16
|
end
|
17
17
|
|
18
|
+
protected
|
19
|
+
|
20
|
+
def invoke_task_directly(task)
|
21
|
+
@called << task
|
22
|
+
end
|
23
|
+
|
18
24
|
include Capistrano::Configuration::Callbacks
|
19
25
|
end
|
20
26
|
|
@@ -96,6 +102,14 @@ class ConfigurationCallbacksTest < Test::Unit::TestCase
|
|
96
102
|
assert_equal 1, @config.callbacks[:before].length
|
97
103
|
assert_equal %w(primary), @config.callbacks[:before].first.except
|
98
104
|
end
|
105
|
+
|
106
|
+
def test_on_without_tasks_or_block_should_raise_error
|
107
|
+
assert_raises(ArgumentError) { @config.on(:before) }
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_on_with_both_tasks_and_block_should_raise_error
|
111
|
+
assert_raises(ArgumentError) { @config.on(:before, :first) { blah } }
|
112
|
+
end
|
99
113
|
|
100
114
|
def test_trigger_without_constraints_should_invoke_all_callbacks
|
101
115
|
task = stub(:fully_qualified_name => "any:old:thing")
|
@@ -203,4 +217,4 @@ class ConfigurationCallbacksTest < Test::Unit::TestCase
|
|
203
217
|
|
204
218
|
@config.execute_task(task)
|
205
219
|
end
|
206
|
-
end
|
220
|
+
end
|