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