capistrano 3.2.1 → 3.3.3

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -3
  3. data/CHANGELOG.md +92 -2
  4. data/Gemfile +1 -5
  5. data/README.md +84 -3
  6. data/Rakefile +5 -1
  7. data/capistrano.gemspec +5 -1
  8. data/features/configuration.feature +9 -7
  9. data/features/deploy.feature +9 -8
  10. data/features/step_definitions/assertions.rb +15 -17
  11. data/features/step_definitions/cap_commands.rb +1 -1
  12. data/features/step_definitions/setup.rb +11 -7
  13. data/features/support/env.rb +8 -9
  14. data/features/support/remote_command_helpers.rb +2 -3
  15. data/features/support/vagrant_helpers.rb +35 -0
  16. data/lib/capistrano/all.rb +2 -1
  17. data/lib/capistrano/application.rb +52 -7
  18. data/lib/capistrano/configuration.rb +39 -10
  19. data/lib/capistrano/configuration/filter.rb +56 -0
  20. data/lib/capistrano/configuration/question.rb +23 -11
  21. data/lib/capistrano/configuration/server.rb +14 -5
  22. data/lib/capistrano/configuration/servers.rb +12 -29
  23. data/lib/capistrano/defaults.rb +11 -9
  24. data/lib/capistrano/deploy.rb +1 -0
  25. data/lib/capistrano/dsl.rb +13 -2
  26. data/lib/capistrano/dsl/env.rb +6 -2
  27. data/lib/capistrano/dsl/task_enhancements.rb +5 -3
  28. data/lib/capistrano/git.rb +8 -2
  29. data/lib/capistrano/hg.rb +7 -1
  30. data/lib/capistrano/svn.rb +2 -2
  31. data/lib/capistrano/tasks/deploy.rake +12 -10
  32. data/lib/capistrano/tasks/git.rake +1 -1
  33. data/lib/capistrano/tasks/install.rake +17 -14
  34. data/lib/capistrano/templates/Capfile +6 -4
  35. data/lib/capistrano/templates/deploy.rb.erb +5 -15
  36. data/lib/capistrano/upload_task.rb +9 -0
  37. data/lib/capistrano/version.rb +1 -1
  38. data/spec/integration/dsl_spec.rb +129 -10
  39. data/spec/lib/capistrano/application_spec.rb +24 -6
  40. data/spec/lib/capistrano/configuration/filter_spec.rb +105 -0
  41. data/spec/lib/capistrano/configuration/question_spec.rb +18 -12
  42. data/spec/lib/capistrano/configuration/server_spec.rb +19 -19
  43. data/spec/lib/capistrano/configuration/servers_spec.rb +101 -20
  44. data/spec/lib/capistrano/configuration_spec.rb +24 -3
  45. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +88 -0
  46. data/spec/lib/capistrano/dsl_spec.rb +2 -13
  47. data/spec/lib/capistrano/git_spec.rb +15 -4
  48. data/spec/lib/capistrano/hg_spec.rb +13 -2
  49. data/spec/lib/capistrano/scm_spec.rb +3 -3
  50. data/spec/lib/capistrano/svn_spec.rb +11 -1
  51. data/spec/lib/capistrano/upload_task_spec.rb +19 -0
  52. data/spec/lib/capistrano/version_validator_spec.rb +4 -4
  53. data/spec/spec_helper.rb +2 -1
  54. data/spec/support/Vagrantfile +1 -1
  55. data/spec/support/test_app.rb +2 -0
  56. metadata +45 -26
  57. data/lib/capistrano/configuration/servers/host_filter.rb +0 -82
  58. data/lib/capistrano/configuration/servers/role_filter.rb +0 -86
  59. data/spec/lib/capistrano/configuration/servers/host_filter_spec.rb +0 -84
  60. data/spec/lib/capistrano/configuration/servers/role_filter_spec.rb +0 -140
@@ -28,6 +28,15 @@ module Capistrano
28
28
  expect(servers.roles_for([:app]).count).to eq 1
29
29
  end
30
30
 
31
+ it 'creates distinct server properties' do
32
+ servers.add_role(:db, %w{1 2}, db: { port: 1234 } )
33
+ servers.add_host('1', db: { master: true })
34
+ expect(servers.count).to eq(2)
35
+ expect(servers.roles_for([:db]).count).to eq 2
36
+ expect(servers.find(){|s| s.hostname == '1'}.properties.db).to eq({ port: 1234, master: true })
37
+ expect(servers.find(){|s| s.hostname == '2'}.properties.db).to eq({ port: 1234 })
38
+ end
39
+
31
40
  end
32
41
 
33
42
  describe 'adding a role to an existing server' do
@@ -59,15 +68,25 @@ module Capistrano
59
68
  end
60
69
 
61
70
  describe 'finding the primary server' do
71
+ after do
72
+ Configuration.reset!
73
+ end
62
74
  it 'takes the first server if none have the primary property' do
63
75
  servers.add_role(:app, %w{1 2})
64
- servers.fetch_primary(:app).hostname.should == '1'
76
+ expect(servers.fetch_primary(:app).hostname).to eq('1')
65
77
  end
66
78
 
67
79
  it 'takes the first server with the primary have the primary flag' do
68
80
  servers.add_role(:app, %w{1 2})
69
81
  servers.add_host('2', primary: true)
70
- servers.fetch_primary(:app).hostname.should == '2'
82
+ expect(servers.fetch_primary(:app).hostname).to eq('2')
83
+ end
84
+
85
+ it 'ignores any on_filters' do
86
+ Configuration.env.set :filter, { host: '1'}
87
+ servers.add_role(:app, %w{1 2})
88
+ servers.add_host('2', primary: true)
89
+ expect(servers.fetch_primary(:app).hostname).to eq('2')
71
90
  end
72
91
  end
73
92
 
@@ -115,8 +134,36 @@ module Capistrano
115
134
  servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'root', port: 34)
116
135
  servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 34)
117
136
  servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 56)
118
- servers.should have(8).items
137
+ expect(servers.count).to eq(8)
138
+ end
139
+
140
+ it 'overwrites the value of a previously defined scalar property' do
141
+ servers.add_host('1', roles: [:app, 'web'], test: :volatile)
142
+ expect(servers.count).to eq(1)
143
+ expect(servers.roles_for([:all]).first.properties.test).to eq :volatile
144
+ end
145
+
146
+ it 'merges previously defined hash properties' do
147
+ servers.add_host('1', roles: [:b], db: { port: 1234 })
148
+ servers.add_host('1', roles: [:b], db: { master: true })
149
+ expect(servers.count).to eq(1)
150
+ expect(servers.roles_for([:b]).first.properties.db).to eq({ port: 1234, master: true })
151
+ end
152
+
153
+ it 'concatenates previously defined array properties' do
154
+ servers.add_host('1', roles: [:b], steps: [1,3,5])
155
+ servers.add_host('1', roles: [:b], steps: [1,9])
156
+ expect(servers.count).to eq(1)
157
+ expect(servers.roles_for([:b]).first.properties.steps).to eq([1,3,5,1,9])
158
+ end
159
+
160
+ it 'merges previously defined set properties' do
161
+ servers.add_host('1', roles: [:b], endpoints: Set[123,333])
162
+ servers.add_host('1', roles: [:b], endpoints: Set[222,333])
163
+ expect(servers.count).to eq(1)
164
+ expect(servers.roles_for([:b]).first.properties.endpoints).to eq(Set[123,222,333])
119
165
  end
166
+
120
167
  end
121
168
 
122
169
  describe 'selecting roles' do
@@ -181,11 +228,9 @@ module Capistrano
181
228
 
182
229
  end
183
230
 
184
- describe 'filtering roles' do
231
+ describe 'filtering roles internally' do
185
232
 
186
233
  before do
187
- ENV.stubs(:[]).with('ROLES').returns('web,db')
188
- ENV.stubs(:[]).with('HOSTS').returns(nil)
189
234
  servers.add_host('1', roles: :app, active: true)
190
235
  servers.add_host('2', roles: :app)
191
236
  servers.add_host('3', roles: :web)
@@ -195,31 +240,67 @@ module Capistrano
195
240
 
196
241
  subject { servers.roles_for(roles).map(&:hostname) }
197
242
 
198
- context 'when selecting all roles' do
199
- let(:roles) { [:all] }
243
+ context 'with the ROLES environment variable set' do
200
244
 
201
- it 'returns the roles specified by ROLE' do
202
- expect(subject).to eq %w{3 4 5}
245
+ before do
246
+ ENV.stubs(:[]).with('ROLES').returns('web,db')
247
+ ENV.stubs(:[]).with('HOSTS').returns(nil)
248
+ end
249
+
250
+ context 'when selecting all roles' do
251
+ let(:roles) { [:all] }
252
+ it 'ignores it' do
253
+ expect(subject).to eq %w{1 2 3 4 5}
254
+ end
203
255
  end
204
- end
205
256
 
206
- context 'when selecting roles included in ROLE' do
207
- let(:roles) { [:app, :web] }
257
+ context 'when selecting specific roles' do
258
+ let(:roles) { [:app, :web] }
259
+ it 'ignores it' do
260
+ expect(subject).to eq %w{1 2 3 4}
261
+ end
262
+ end
208
263
 
209
- it 'returns only roles that match ROLE' do
210
- expect(subject).to eq %w{3 4}
264
+ context 'when selecting roles not included in ROLE' do
265
+ let(:roles) { [:app] }
266
+ it 'ignores it' do
267
+ expect(subject).to eq %w{1 2}
268
+ end
211
269
  end
270
+
212
271
  end
213
272
 
214
- context 'when selecting roles not included in ROLE' do
215
- let(:roles) { [:app] }
273
+ context 'with the HOSTS environment variable set' do
274
+
275
+ before do
276
+ ENV.stubs(:[]).with('ROLES').returns(nil)
277
+ ENV.stubs(:[]).with('HOSTS').returns('3,5')
278
+ end
216
279
 
217
- it 'is empty' do
218
- expect(subject).to be_empty
280
+ context 'when selecting all roles' do
281
+ let(:roles) { [:all] }
282
+ it 'ignores it' do
283
+ expect(subject).to eq %w{1 2 3 4 5}
284
+ end
219
285
  end
286
+
287
+ context 'when selecting specific roles' do
288
+ let(:roles) { [:app, :web] }
289
+ it 'ignores it' do
290
+ expect(subject).to eq %w{1 2 3 4}
291
+ end
292
+ end
293
+
294
+ context 'when selecting no roles' do
295
+ let(:roles) { [] }
296
+ it 'ignores it' do
297
+ expect(subject).to be_empty
298
+ end
299
+ end
300
+
220
301
  end
221
- end
222
302
 
303
+ end
223
304
  end
224
305
  end
225
306
  end
@@ -5,10 +5,17 @@ module Capistrano
5
5
  let(:config) { Configuration.new }
6
6
  let(:servers) { stub }
7
7
 
8
+ describe '.new' do
9
+ it 'accepts initial hash' do
10
+ configuration = described_class.new(custom: 'value')
11
+ expect(configuration.fetch(:custom)).to eq('value')
12
+ end
13
+ end
14
+
8
15
  describe '.env' do
9
16
  it 'is a global accessor to a single instance' do
10
17
  Configuration.env.set(:test, true)
11
- expect(Configuration.env.fetch(:test)).to be_true
18
+ expect(Configuration.env.fetch(:test)).to be_truthy
12
19
  end
13
20
  end
14
21
 
@@ -48,6 +55,19 @@ module Capistrano
48
55
  end
49
56
  end
50
57
 
58
+ context 'set_if_empty' do
59
+ it 'sets the value when none is present' do
60
+ config.set_if_empty(:key, :value)
61
+ expect(subject).to eq :value
62
+ end
63
+
64
+ it 'does not overwrite the value' do
65
+ config.set(:key, :value)
66
+ config.set_if_empty(:key, :update)
67
+ expect(subject).to eq :value
68
+ end
69
+ end
70
+
51
71
  context 'value is not set' do
52
72
  it 'returns the default value' do
53
73
  expect(subject).to eq :default
@@ -138,14 +158,15 @@ module Capistrano
138
158
 
139
159
  describe 'asking' do
140
160
  let(:question) { stub }
161
+ let(:options) { Hash.new }
141
162
 
142
163
  before do
143
- Configuration::Question.expects(:new).with(config, :branch, :default).
164
+ Configuration::Question.expects(:new).with(:branch, :default, options).
144
165
  returns(question)
145
166
  end
146
167
 
147
168
  it 'prompts for the value when fetching' do
148
- config.ask(:branch, :default)
169
+ config.ask(:branch, :default, options)
149
170
  expect(config.fetch(:branch)).to eq question
150
171
  end
151
172
  end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ module Capistrano
4
+ class DummyTaskEnhancements
5
+ include TaskEnhancements
6
+ end
7
+
8
+ describe TaskEnhancements do
9
+ let(:task_enhancements) { DummyTaskEnhancements.new }
10
+
11
+ describe 'ordering' do
12
+
13
+ after do
14
+ task.clear
15
+ before_task.clear
16
+ after_task.clear
17
+ Rake::Task.clear
18
+ end
19
+
20
+ let(:order) { [] }
21
+ let!(:task) do
22
+ Rake::Task.define_task('task', [:order]) do |t, args|
23
+ args['order'].push 'task'
24
+ end
25
+ end
26
+
27
+ let!(:before_task) do
28
+ Rake::Task.define_task('before_task') do
29
+ order.push 'before_task'
30
+ end
31
+ end
32
+
33
+ let!(:after_task) do
34
+ Rake::Task.define_task('after_task') do
35
+ order.push 'after_task'
36
+ end
37
+ end
38
+
39
+ it 'invokes in proper order if define after than before' do
40
+ task_enhancements.after('task', 'after_task')
41
+ task_enhancements.before('task', 'before_task')
42
+
43
+ Rake::Task['task'].invoke order
44
+
45
+ expect(order).to eq(['before_task', 'task', 'after_task'])
46
+ end
47
+
48
+ it 'invokes in proper order if define before than after' do
49
+ task_enhancements.before('task', 'before_task')
50
+ task_enhancements.after('task', 'after_task')
51
+
52
+ Rake::Task['task'].invoke order
53
+
54
+ expect(order).to eq(['before_task', 'task', 'after_task'])
55
+ end
56
+
57
+ it 'invokes in proper order and with arguments and block' do
58
+ task_enhancements.after('task', 'after_task_custom', :order) do |t, args|
59
+ order.push 'after_task'
60
+ end
61
+
62
+ task_enhancements.before('task', 'before_task_custom', :order) do |t, args|
63
+ order.push 'before_task'
64
+ end
65
+
66
+ Rake::Task['task'].invoke(order)
67
+
68
+ expect(order).to eq(['before_task', 'task', 'after_task'])
69
+ end
70
+
71
+ end
72
+
73
+ describe 'remote_file' do
74
+ subject(:remote_file) { task_enhancements.remote_file('source' => 'destination') }
75
+
76
+ it { expect(remote_file.name).to eq('source') }
77
+ it { is_expected.to be_a(Capistrano::UploadTask) }
78
+
79
+ describe 'namespaced' do
80
+ let(:app) { Rake.application }
81
+ around { |ex| app.in_namespace('namespace', &ex) }
82
+
83
+ it { expect(remote_file.name).to eq('source') }
84
+ it { is_expected.to be_a(Capistrano::UploadTask) }
85
+ end
86
+ end
87
+ end
88
+ end
@@ -27,14 +27,14 @@ module Capistrano
27
27
  before do
28
28
  dsl.set(:stage, :sandbox)
29
29
  end
30
- it { should be_true }
30
+ it { expect(subject).to be_truthy }
31
31
  end
32
32
 
33
33
  context 'stage is not set' do
34
34
  before do
35
35
  dsl.set(:stage, nil)
36
36
  end
37
- it { should be_false }
37
+ it { expect(subject).to be_falsey }
38
38
  end
39
39
  end
40
40
 
@@ -48,16 +48,5 @@ module Capistrano
48
48
  dsl.sudo(:my, :command)
49
49
  end
50
50
  end
51
-
52
- describe '#local_user' do
53
-
54
- before do
55
- Etc.expects(:getlogin)
56
- end
57
-
58
- it 'delegates to Etc#getlogin' do
59
- dsl.local_user
60
- end
61
- end
62
51
  end
63
52
  end
@@ -31,7 +31,7 @@ module Capistrano
31
31
  describe "#check" do
32
32
  it "should test the repo url" do
33
33
  context.expects(:repo_url).returns(:url)
34
- context.expects(:test).with(:git, :'ls-remote -h', :url).returns(true)
34
+ context.expects(:execute).with(:git, :'ls-remote -h', :url).returns(true)
35
35
 
36
36
  subject.check
37
37
  end
@@ -57,11 +57,22 @@ module Capistrano
57
57
  end
58
58
 
59
59
  describe "#release" do
60
- it "should run git archive" do
61
- context.expects(:fetch).returns(:branch)
60
+ it "should run git archive without a subtree" do
61
+ context.expects(:fetch).with(:repo_tree).returns(nil)
62
+ context.expects(:fetch).with(:branch).returns(:branch)
62
63
  context.expects(:release_path).returns(:path)
63
64
 
64
- context.expects(:execute).with(:git, :archive, :branch, '| tar -x -C', :path)
65
+ context.expects(:execute).with(:git, :archive, :branch, '| tar -x -f - -C', :path)
66
+
67
+ subject.release
68
+ end
69
+
70
+ it "should run git archive with a subtree" do
71
+ context.expects(:fetch).with(:repo_tree).returns('tree')
72
+ context.expects(:fetch).with(:branch).returns(:branch)
73
+ context.expects(:release_path).returns(:path)
74
+
75
+ context.expects(:execute).with(:git, :archive, :branch, 'tree', '| tar -x --strip-components 1 -f - -C', :path)
65
76
 
66
77
  subject.release
67
78
  end
@@ -57,14 +57,25 @@ module Capistrano
57
57
  end
58
58
 
59
59
  describe "#release" do
60
- it "should run hg archive" do
61
- context.expects(:fetch).returns(:branch)
60
+ it "should run hg archive without a subtree" do
61
+ context.expects(:fetch).with(:repo_tree).returns(nil)
62
+ context.expects(:fetch).with(:branch).returns(:branch)
62
63
  context.expects(:release_path).returns(:path)
63
64
 
64
65
  context.expects(:execute).with(:hg, "archive", :path, "--rev", :branch)
65
66
 
66
67
  subject.release
67
68
  end
69
+
70
+ it "should run hg archive with a subtree" do
71
+ context.expects(:fetch).with(:repo_tree).returns('tree')
72
+ context.expects(:fetch).with(:branch).returns(:branch)
73
+ context.expects(:release_path).returns(:path)
74
+
75
+ context.expects(:execute).with(:hg, "archive --type tgz -p . -I", 'tree', "--rev", :branch, '| tar -x --strip-components 1 -f - -C', :path)
76
+
77
+ subject.release
78
+ end
68
79
  end
69
80
  end
70
81
  end
@@ -50,21 +50,21 @@ module Capistrano
50
50
  describe "#repo_url" do
51
51
  it "should return the repo url according to the context" do
52
52
  context.expects(:repo_url).returns(:url)
53
- subject.repo_url.should == :url
53
+ expect(subject.repo_url).to eq(:url)
54
54
  end
55
55
  end
56
56
 
57
57
  describe "#repo_path" do
58
58
  it "should return the repo path according to the context" do
59
59
  context.expects(:repo_path).returns(:path)
60
- subject.repo_path.should == :path
60
+ expect(subject.repo_path).to eq(:path)
61
61
  end
62
62
  end
63
63
 
64
64
  describe "#release_path" do
65
65
  it "should return the release path according to the context" do
66
66
  context.expects(:release_path).returns('/path/to/nowhere')
67
- subject.release_path.should == '/path/to/nowhere'
67
+ expect(subject.release_path).to eq('/path/to/nowhere')
68
68
  end
69
69
  end
70
70
 
@@ -60,10 +60,20 @@ module Capistrano
60
60
  it "should run svn export" do
61
61
  context.expects(:release_path).returns(:path)
62
62
 
63
- context.expects(:execute).with(:svn, :export, '.', :path)
63
+ context.expects(:execute).with(:svn, :export, '--force', '.', :path)
64
64
 
65
65
  subject.release
66
66
  end
67
67
  end
68
+
69
+ describe "#fetch_revision" do
70
+ it "should run fetch revision" do
71
+ context.expects(:repo_path).returns(:path)
72
+
73
+ context.expects(:capture).with(:svnversion, :path)
74
+
75
+ subject.fetch_revision
76
+ end
77
+ end
68
78
  end
69
79
  end