capistrano 3.2.1 → 3.3.3

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