capistrano 1.4.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/CHANGELOG +140 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README +22 -14
  4. data/bin/cap +1 -8
  5. data/bin/capify +77 -0
  6. data/examples/sample.rb +10 -109
  7. data/lib/capistrano.rb +1 -0
  8. data/lib/capistrano/callback.rb +41 -0
  9. data/lib/capistrano/cli.rb +17 -317
  10. data/lib/capistrano/cli/execute.rb +82 -0
  11. data/lib/capistrano/cli/help.rb +102 -0
  12. data/lib/capistrano/cli/help.txt +53 -0
  13. data/lib/capistrano/cli/options.rb +183 -0
  14. data/lib/capistrano/cli/ui.rb +28 -0
  15. data/lib/capistrano/command.rb +62 -29
  16. data/lib/capistrano/configuration.rb +25 -226
  17. data/lib/capistrano/configuration/actions/file_transfer.rb +35 -0
  18. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  19. data/lib/capistrano/configuration/actions/invocation.rb +127 -0
  20. data/lib/capistrano/configuration/callbacks.rb +148 -0
  21. data/lib/capistrano/configuration/connections.rb +159 -0
  22. data/lib/capistrano/configuration/execution.rb +126 -0
  23. data/lib/capistrano/configuration/loading.rb +112 -0
  24. data/lib/capistrano/configuration/namespaces.rb +190 -0
  25. data/lib/capistrano/configuration/roles.rb +51 -0
  26. data/lib/capistrano/configuration/servers.rb +75 -0
  27. data/lib/capistrano/configuration/variables.rb +127 -0
  28. data/lib/capistrano/errors.rb +15 -0
  29. data/lib/capistrano/extensions.rb +27 -8
  30. data/lib/capistrano/gateway.rb +54 -29
  31. data/lib/capistrano/logger.rb +11 -11
  32. data/lib/capistrano/recipes/compat.rb +32 -0
  33. data/lib/capistrano/recipes/deploy.rb +483 -0
  34. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  35. data/lib/capistrano/recipes/deploy/local_dependency.rb +46 -0
  36. data/lib/capistrano/recipes/deploy/remote_dependency.rb +65 -0
  37. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  38. data/lib/capistrano/recipes/deploy/scm/base.rb +180 -0
  39. data/lib/capistrano/recipes/deploy/scm/bzr.rb +86 -0
  40. data/lib/capistrano/recipes/deploy/scm/cvs.rb +151 -0
  41. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  42. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +129 -0
  43. data/lib/capistrano/recipes/deploy/scm/perforce.rb +126 -0
  44. data/lib/capistrano/recipes/deploy/scm/subversion.rb +103 -0
  45. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  46. data/lib/capistrano/recipes/deploy/strategy/base.rb +64 -0
  47. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  48. data/lib/capistrano/recipes/deploy/strategy/copy.rb +143 -0
  49. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  50. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  51. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +47 -0
  52. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  53. data/lib/capistrano/recipes/standard.rb +26 -276
  54. data/lib/capistrano/recipes/templates/maintenance.rhtml +1 -1
  55. data/lib/capistrano/recipes/upgrade.rb +33 -0
  56. data/lib/capistrano/server_definition.rb +51 -0
  57. data/lib/capistrano/shell.rb +125 -81
  58. data/lib/capistrano/ssh.rb +80 -36
  59. data/lib/capistrano/task_definition.rb +69 -0
  60. data/lib/capistrano/upload.rb +146 -0
  61. data/lib/capistrano/version.rb +13 -17
  62. data/test/cli/execute_test.rb +132 -0
  63. data/test/cli/help_test.rb +139 -0
  64. data/test/cli/options_test.rb +226 -0
  65. data/test/cli/ui_test.rb +28 -0
  66. data/test/cli_test.rb +17 -0
  67. data/test/command_test.rb +284 -25
  68. data/test/configuration/actions/file_transfer_test.rb +40 -0
  69. data/test/configuration/actions/inspect_test.rb +62 -0
  70. data/test/configuration/actions/invocation_test.rb +195 -0
  71. data/test/configuration/callbacks_test.rb +206 -0
  72. data/test/configuration/connections_test.rb +288 -0
  73. data/test/configuration/execution_test.rb +159 -0
  74. data/test/configuration/loading_test.rb +119 -0
  75. data/test/configuration/namespace_dsl_test.rb +283 -0
  76. data/test/configuration/roles_test.rb +47 -0
  77. data/test/configuration/servers_test.rb +90 -0
  78. data/test/configuration/variables_test.rb +180 -0
  79. data/test/configuration_test.rb +60 -212
  80. data/test/deploy/scm/base_test.rb +55 -0
  81. data/test/deploy/strategy/copy_test.rb +146 -0
  82. data/test/extensions_test.rb +69 -0
  83. data/test/fixtures/cli_integration.rb +5 -0
  84. data/test/fixtures/custom.rb +2 -2
  85. data/test/gateway_test.rb +167 -0
  86. data/test/logger_test.rb +123 -0
  87. data/test/server_definition_test.rb +108 -0
  88. data/test/shell_test.rb +64 -0
  89. data/test/ssh_test.rb +67 -154
  90. data/test/task_definition_test.rb +101 -0
  91. data/test/upload_test.rb +131 -0
  92. data/test/utils.rb +31 -39
  93. data/test/version_test.rb +24 -0
  94. metadata +145 -98
  95. data/THANKS +0 -4
  96. data/lib/capistrano/actor.rb +0 -567
  97. data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +0 -25
  98. data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +0 -49
  99. data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +0 -122
  100. data/lib/capistrano/generators/rails/loader.rb +0 -20
  101. data/lib/capistrano/scm/base.rb +0 -61
  102. data/lib/capistrano/scm/baz.rb +0 -118
  103. data/lib/capistrano/scm/bzr.rb +0 -70
  104. data/lib/capistrano/scm/cvs.rb +0 -129
  105. data/lib/capistrano/scm/darcs.rb +0 -27
  106. data/lib/capistrano/scm/mercurial.rb +0 -83
  107. data/lib/capistrano/scm/perforce.rb +0 -139
  108. data/lib/capistrano/scm/subversion.rb +0 -128
  109. data/lib/capistrano/transfer.rb +0 -97
  110. data/lib/capistrano/utils.rb +0 -26
  111. data/test/actor_test.rb +0 -402
  112. data/test/scm/cvs_test.rb +0 -196
  113. data/test/scm/subversion_test.rb +0 -145
@@ -1,97 +0,0 @@
1
- begin
2
- require 'capistrano/version'
3
-
4
- begin
5
- require 'rubygems'
6
- gem 'net-sftp', '< 1.99.0'
7
- rescue LoadError, NameError
8
- end
9
-
10
- require 'net/sftp'
11
- require 'net/sftp/version'
12
-
13
- sftp_version = [Net::SFTP::Version::MAJOR, Net::SFTP::Version::MINOR, Net::SFTP::Version::TINY]
14
- if !Capistrano::Version.check(sftp_version, Capistrano::Version::MINIMUM_SFTP_REQUIRED, Capistrano::Version::MAXIMUM_SFTP_REQUIRED)
15
- warn "You have Net::SFTP #{sftp_version.join(".")}, but you need between #{Capistrano::Version::MINIMUM_SFTP_REQUIRED.join('.')}...#{Capistrano::Version::MAXIMUM_SFTP_REQUIRED.join('.')}. Net::SFTP will not be used."
16
- Capistrano::SFTP = false
17
- else
18
- Capistrano::SFTP = true
19
- end
20
- rescue LoadError
21
- Capistrano::SFTP = false
22
- end
23
-
24
- module Capistrano
25
-
26
- # This class encapsulates a single file transfer to be performed in parallel
27
- # across multiple machines, using the SFTP protocol.
28
- class Transfer
29
- def initialize(servers, actor, filename, params={}) #:nodoc:
30
- @servers = servers
31
- @actor = actor
32
- @filename = filename
33
- @params = params
34
- @completed = 0
35
- @failed = 0
36
- @sftps = setup_transfer
37
- end
38
-
39
- def logger #:nodoc:
40
- @actor.logger
41
- end
42
-
43
- # Uploads to all specified servers in parallel.
44
- def process!
45
- logger.debug "uploading #{@filename}"
46
-
47
- loop do
48
- @sftps.each { |sftp| sftp.channel.connection.process(true) }
49
- break if @completed == @servers.length
50
- end
51
-
52
- logger.trace "upload finished"
53
-
54
- if @failed > 0
55
- raise "upload of #{@filename} failed on one or more hosts"
56
- end
57
-
58
- self
59
- end
60
-
61
- private
62
-
63
- def setup_transfer
64
- @servers.map do |server|
65
- sftp = @actor.sessions[server].sftp
66
- sftp.connect unless sftp.state == :open
67
-
68
- sftp.open(@filename, IO::WRONLY | IO::CREAT | IO::TRUNC, @params[:mode] || 0660) do |status, handle|
69
- break unless check_status("open #{@filename}", server, status)
70
-
71
- logger.info "uploading data to #{server}:#{@filename}"
72
- sftp.write(handle, @params[:data] || "") do |status|
73
- break unless check_status("write to #{server}:#{@filename}", server, status)
74
- sftp.close_handle(handle) do
75
- logger.debug "done uploading data to #{server}:#{@filename}"
76
- @completed += 1
77
- end
78
- end
79
- end
80
-
81
- sftp
82
- end
83
- end
84
-
85
- def check_status(action, server, status)
86
- if status.code != Net::SFTP::Session::FX_OK
87
- logger.error "could not #{action} on #{server} (#{status.message})"
88
- @failed += 1
89
- @completed += 1
90
- return false
91
- end
92
-
93
- true
94
- end
95
- end
96
-
97
- end
@@ -1,26 +0,0 @@
1
- module Capistrano
2
- # A helper method for converting a comma-delimited string into an array of
3
- # roles.
4
- def self.str2roles(string)
5
- list = string.split(/,/).map { |s| s.strip.to_sym }
6
- list.empty? ? nil : list
7
- end
8
-
9
- # Used by third-party task bundles to identify the capistrano configuration
10
- # that is loading them. It's return value is not reliable in other contexts.
11
- # If +require_config+ is not false, an exception will be raised if the current
12
- # configuration is not set.
13
- def self.configuration(require_config=false)
14
- config = Thread.current[:capistrano_configuration]
15
- if require_config && config.nil?
16
- raise "Please require this file from within a Capistrano recipe"
17
- end
18
- config
19
- end
20
-
21
- # Used internally by Capistrano to specify the current configuration before
22
- # loading a third-party task bundle.
23
- def self.configuration=(config)
24
- Thread.current[:capistrano_configuration] = config
25
- end
26
- end
@@ -1,402 +0,0 @@
1
- $:.unshift File.dirname(__FILE__) + "/../lib"
2
-
3
- require 'stringio'
4
- require 'test/unit'
5
- require 'capistrano/actor'
6
- require 'capistrano/logger'
7
- require 'capistrano/configuration'
8
-
9
- class ActorTest < Test::Unit::TestCase
10
-
11
- class TestingConnectionFactory
12
- def initialize(config)
13
- end
14
-
15
- def connect_to(server)
16
- server
17
- end
18
- end
19
-
20
- class GatewayConnectionFactory
21
- def connect_to(server)
22
- server
23
- end
24
- end
25
-
26
- class TestingCommand
27
- def self.invoked!
28
- @invoked = true
29
- end
30
-
31
- def self.invoked?
32
- @invoked
33
- end
34
-
35
- def self.reset!
36
- @invoked = nil
37
- end
38
-
39
- def initialize(*args)
40
- end
41
-
42
- def process!
43
- self.class.invoked!
44
- end
45
- end
46
-
47
- class TestActor < Capistrano::Actor
48
- attr_reader :factory
49
-
50
- self.connection_factory = TestingConnectionFactory
51
- self.command_factory = TestingCommand
52
-
53
- def establish_gateway
54
- GatewayConnectionFactory.new
55
- end
56
- end
57
-
58
- class MockConfiguration < Capistrano::Configuration
59
- Role = Struct.new(:host, :options)
60
-
61
- attr_accessor :gateway, :pretend
62
-
63
- def initialize(*args)
64
- super
65
- @logger = Capistrano::Logger.new(:output => StringIO.new)
66
- end
67
-
68
- def delegated_method
69
- "result of method"
70
- end
71
-
72
- ROLES = { :db => [ Role.new("01.example.com", :primary => true),
73
- Role.new("02.example.com", {}),
74
- Role.new("all.example.com", {})],
75
- :web => [ Role.new("03.example.com", {}),
76
- Role.new("04.example.com", {}),
77
- Role.new("all.example.com", {})],
78
- :app => [ Role.new("05.example.com", {}),
79
- Role.new("06.example.com", {}),
80
- Role.new("07.example.com", {}),
81
- Role.new("all.example.com", {})] }
82
-
83
- def roles
84
- ROLES
85
- end
86
- end
87
-
88
- module CustomExtension
89
- def do_something_extra(a, b, c)
90
- run "echo '#{a} :: #{b} :: #{c}'"
91
- end
92
- end
93
-
94
- def setup
95
- TestingCommand.reset!
96
- @actor = TestActor.new(MockConfiguration.new)
97
- ENV["ROLES"] = nil
98
- ENV["HOSTS"] = nil
99
- end
100
-
101
- def test_previous_release_returns_nil_with_one_release
102
- class << @actor
103
- def releases
104
- ["1234567890"]
105
- end
106
- end
107
- assert_equal @actor.previous_release, nil
108
- end
109
-
110
- def test_define_task_creates_method
111
- @actor.define_task :hello do
112
- "result"
113
- end
114
- assert @actor.respond_to?(:hello)
115
- assert_equal "result", @actor.hello
116
- end
117
-
118
- def test_define_task_with_successful_transaction
119
- class << @actor
120
- attr_reader :rolled_back
121
- attr_reader :history
122
- end
123
-
124
- @actor.define_task :hello do
125
- (@history ||= []) << :hello
126
- on_rollback { @rolled_back = true }
127
- "hello"
128
- end
129
-
130
- @actor.define_task :goodbye do
131
- (@history ||= []) << :goodbye
132
- transaction do
133
- hello
134
- end
135
- "goodbye"
136
- end
137
-
138
- assert_nothing_raised { @actor.goodbye }
139
- assert !@actor.rolled_back
140
- assert_equal [:goodbye, :hello], @actor.history
141
- end
142
-
143
- def test_define_task_with_failed_transaction
144
- class << @actor
145
- attr_reader :rolled_back
146
- attr_reader :history
147
- end
148
-
149
- @actor.define_task :hello do
150
- (@history ||= []) << :hello
151
- on_rollback { @rolled_back = true }
152
- "hello"
153
- end
154
-
155
- @actor.define_task :goodbye do
156
- (@history ||= []) << :goodbye
157
- transaction do
158
- hello
159
- raise "ouch"
160
- end
161
- "goodbye"
162
- end
163
-
164
- assert_raise(RuntimeError) do
165
- @actor.goodbye
166
- end
167
-
168
- assert @actor.rolled_back
169
- assert_equal [:goodbye, :hello], @actor.history
170
- end
171
-
172
- def test_rollback_uses_roles_for_associated_task
173
- @actor.define_task :inner, :roles => :db do
174
- on_rollback { run "error" }
175
- run "go"
176
- raise "fail"
177
- end
178
-
179
- @actor.define_task :outer do
180
- transaction do
181
- inner
182
- end
183
- run "done"
184
- end
185
-
186
- assert_raise(RuntimeError) { @actor.outer }
187
-
188
- assert TestingCommand.invoked?
189
- assert_equal %w(01.example.com 02.example.com all.example.com), @actor.sessions.keys.sort
190
- end
191
-
192
- def test_delegates_to_configuration
193
- @actor.define_task :hello do
194
- delegated_method
195
- end
196
- assert_equal "result of method", @actor.hello
197
- end
198
-
199
- def test_task_servers_with_duplicates
200
- @actor.define_task :foo do
201
- run "do this"
202
- end
203
-
204
- assert_equal %w(01.example.com 02.example.com 03.example.com 04.example.com 05.example.com 06.example.com 07.example.com all.example.com), @actor.tasks[:foo].servers.sort
205
- end
206
-
207
- def test_run_in_task_without_explicit_roles_selects_all_roles
208
- @actor.define_task :foo do
209
- run "do this"
210
- end
211
-
212
- @actor.foo
213
- assert_equal %w(01.example.com 02.example.com 03.example.com 04.example.com 05.example.com 06.example.com 07.example.com all.example.com), @actor.sessions.keys.sort
214
- end
215
-
216
- def test_run_in_task_with_single_role_selects_that_role
217
- @actor.define_task :foo, :roles => :db do
218
- run "do this"
219
- end
220
-
221
- @actor.foo
222
- assert_equal %w(01.example.com 02.example.com all.example.com), @actor.sessions.keys.sort
223
- end
224
-
225
- def test_run_in_task_with_single_role_selects_that_role_from_environment
226
- ENV["ROLES"] = "app"
227
- @actor.define_task :foo, :roles => :db do
228
- run "do this"
229
- end
230
-
231
- @actor.foo
232
- assert_equal %w(05.example.com 06.example.com 07.example.com all.example.com), @actor.sessions.keys.sort
233
- end
234
-
235
- def test_run_in_task_with_multiple_roles_selects_those_roles
236
- @actor.define_task :foo, :roles => [:db, :web] do
237
- run "do this"
238
- end
239
-
240
- @actor.foo
241
- assert_equal %w(01.example.com 02.example.com 03.example.com 04.example.com all.example.com), @actor.sessions.keys.sort
242
- end
243
-
244
- def test_run_in_task_with_multiple_roles_selects_those_roles_from_environment
245
- ENV["ROLES"] = "app,db"
246
- @actor.define_task :foo, :roles => [:db, :web] do
247
- run "do this"
248
- end
249
-
250
- @actor.foo
251
- assert_equal %w(01.example.com 02.example.com 05.example.com 06.example.com 07.example.com all.example.com), @actor.sessions.keys.sort
252
- end
253
-
254
- def test_run_in_task_with_only_restricts_selected_roles
255
- @actor.define_task :foo, :roles => :db, :only => { :primary => true } do
256
- run "do this"
257
- end
258
-
259
- @actor.foo
260
- assert_equal %w(01.example.com), @actor.sessions.keys.sort
261
- end
262
-
263
- def test_run_in_task_with_except_restricts_selected_roles
264
- @actor.define_task :foo, :roles => :db, :except => { :primary => true } do
265
- run "do this"
266
- end
267
-
268
- @actor.foo
269
- assert_equal %w(02.example.com all.example.com), @actor.sessions.keys.sort
270
- end
271
-
272
- def test_run_in_task_with_single_host_selected
273
- @actor.define_task :foo, :hosts => "01.example.com" do
274
- run "do this"
275
- end
276
-
277
- @actor.foo
278
- assert_equal %w(01.example.com), @actor.sessions.keys.sort
279
- end
280
-
281
- def test_run_in_task_with_single_host_selected_from_environment
282
- ENV["HOSTS"] = "02.example.com"
283
- @actor.define_task :foo, :hosts => "01.example.com" do
284
- run "do this"
285
- end
286
-
287
- @actor.foo
288
- assert_equal %w(02.example.com), @actor.sessions.keys.sort
289
- end
290
-
291
- def test_run_in_task_with_multiple_hosts_selected
292
- @actor.define_task :foo, :hosts => [ "01.example.com", "07.example.com" ] do
293
- run "do this"
294
- end
295
-
296
- @actor.foo
297
- assert_equal %w(01.example.com 07.example.com), @actor.sessions.keys.sort
298
- end
299
-
300
- def test_run_in_task_with_multiple_hosts_selected_from_environment
301
- ENV["HOSTS"] = "02.example.com,06.example.com"
302
- @actor.define_task :foo, :hosts => [ "01.example.com", "07.example.com" ] do
303
- run "do this"
304
- end
305
-
306
- @actor.foo
307
- assert_equal %w(02.example.com 06.example.com), @actor.sessions.keys.sort
308
- end
309
-
310
- def test_establish_connection_uses_gateway_if_specified
311
- @actor.configuration.gateway = "10.example.com"
312
- @actor.define_task :foo, :roles => :db do
313
- run "do this"
314
- end
315
-
316
- @actor.foo
317
- assert_instance_of GatewayConnectionFactory, @actor.factory
318
- end
319
-
320
- def test_establish_connection_uses_gateway_if_specified_with_username_and_port
321
- @actor.configuration.gateway = "demo@10.example.com:8088"
322
- @actor.define_task :foo, :roles => :db do
323
- run "do this"
324
- end
325
- @actor.foo
326
- assert_instance_of GatewayConnectionFactory, @actor.factory
327
- end
328
-
329
- def test_run_when_not_pretend
330
- @actor.define_task :foo do
331
- run "do this"
332
- end
333
-
334
- @actor.configuration.pretend = false
335
- @actor.foo
336
- assert TestingCommand.invoked?
337
- end
338
-
339
- def test_run_when_pretend
340
- @actor.define_task :foo do
341
- run "do this"
342
- end
343
-
344
- @actor.configuration.pretend = true
345
- @actor.foo
346
- assert !TestingCommand.invoked?
347
- end
348
-
349
- def test_task_before_hook
350
- history = []
351
- @actor.define_task :foo do
352
- history << "foo"
353
- end
354
-
355
- @actor.define_task :before_foo do
356
- history << "before_foo"
357
- end
358
-
359
- @actor.foo
360
- assert_equal %w(before_foo foo), history
361
- end
362
-
363
- def test_task_after_hook
364
- history = []
365
- @actor.define_task :foo do
366
- history << "foo"
367
- end
368
-
369
- @actor.define_task :after_foo do
370
- history << "after_foo"
371
- end
372
-
373
- @actor.foo
374
- assert_equal %w(foo after_foo), history
375
- end
376
-
377
- def test_uppercase_variables
378
- config = Capistrano::Configuration.new(TestActor)
379
- config.set :HELLO, "world"
380
- assert_equal "world", config.actor.instance_eval("HELLO")
381
- config.set :HELLO, "test"
382
- assert_equal "test", config.actor.instance_eval("HELLO")
383
- end
384
-
385
- def test_connect_when_no_matching_servers
386
- @actor.define_task :foo, :roles => :db, :only => { :fnoofy => true } do
387
- run "do this"
388
- end
389
-
390
- assert_raises(RuntimeError) { @actor.foo }
391
- end
392
-
393
- def test_custom_extension
394
- assert Capistrano.plugin(:custom, CustomExtension)
395
- @actor.define_task :foo, :roles => :db do
396
- custom.do_something_extra(1, 2, 3)
397
- end
398
- assert_nothing_raised { @actor.foo }
399
- assert TestingCommand.invoked?
400
- assert Capistrano.remove_plugin(:custom)
401
- end
402
- end