capistrano 3.2.1 → 3.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -3
- data/CHANGELOG.md +92 -2
- data/Gemfile +1 -5
- data/README.md +84 -3
- data/Rakefile +5 -1
- data/capistrano.gemspec +5 -1
- data/features/configuration.feature +9 -7
- data/features/deploy.feature +9 -8
- data/features/step_definitions/assertions.rb +15 -17
- data/features/step_definitions/cap_commands.rb +1 -1
- data/features/step_definitions/setup.rb +11 -7
- data/features/support/env.rb +8 -9
- data/features/support/remote_command_helpers.rb +2 -3
- data/features/support/vagrant_helpers.rb +35 -0
- data/lib/capistrano/all.rb +2 -1
- data/lib/capistrano/application.rb +52 -7
- data/lib/capistrano/configuration.rb +39 -10
- data/lib/capistrano/configuration/filter.rb +56 -0
- data/lib/capistrano/configuration/question.rb +23 -11
- data/lib/capistrano/configuration/server.rb +14 -5
- data/lib/capistrano/configuration/servers.rb +12 -29
- data/lib/capistrano/defaults.rb +11 -9
- data/lib/capistrano/deploy.rb +1 -0
- data/lib/capistrano/dsl.rb +13 -2
- data/lib/capistrano/dsl/env.rb +6 -2
- data/lib/capistrano/dsl/task_enhancements.rb +5 -3
- data/lib/capistrano/git.rb +8 -2
- data/lib/capistrano/hg.rb +7 -1
- data/lib/capistrano/svn.rb +2 -2
- data/lib/capistrano/tasks/deploy.rake +12 -10
- data/lib/capistrano/tasks/git.rake +1 -1
- data/lib/capistrano/tasks/install.rake +17 -14
- data/lib/capistrano/templates/Capfile +6 -4
- data/lib/capistrano/templates/deploy.rb.erb +5 -15
- data/lib/capistrano/upload_task.rb +9 -0
- data/lib/capistrano/version.rb +1 -1
- data/spec/integration/dsl_spec.rb +129 -10
- data/spec/lib/capistrano/application_spec.rb +24 -6
- data/spec/lib/capistrano/configuration/filter_spec.rb +105 -0
- data/spec/lib/capistrano/configuration/question_spec.rb +18 -12
- data/spec/lib/capistrano/configuration/server_spec.rb +19 -19
- data/spec/lib/capistrano/configuration/servers_spec.rb +101 -20
- data/spec/lib/capistrano/configuration_spec.rb +24 -3
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +88 -0
- data/spec/lib/capistrano/dsl_spec.rb +2 -13
- data/spec/lib/capistrano/git_spec.rb +15 -4
- data/spec/lib/capistrano/hg_spec.rb +13 -2
- data/spec/lib/capistrano/scm_spec.rb +3 -3
- data/spec/lib/capistrano/svn_spec.rb +11 -1
- data/spec/lib/capistrano/upload_task_spec.rb +19 -0
- data/spec/lib/capistrano/version_validator_spec.rb +4 -4
- data/spec/spec_helper.rb +2 -1
- data/spec/support/Vagrantfile +1 -1
- data/spec/support/test_app.rb +2 -0
- metadata +45 -26
- data/lib/capistrano/configuration/servers/host_filter.rb +0 -82
- data/lib/capistrano/configuration/servers/role_filter.rb +0 -86
- data/spec/lib/capistrano/configuration/servers/host_filter_spec.rb +0 -84
- 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.
|
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.
|
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.
|
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 '
|
199
|
-
let(:roles) { [:all] }
|
243
|
+
context 'with the ROLES environment variable set' do
|
200
244
|
|
201
|
-
|
202
|
-
|
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
|
-
|
207
|
-
|
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
|
-
|
210
|
-
|
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 '
|
215
|
-
|
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
|
-
|
218
|
-
|
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
|
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(
|
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 {
|
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 {
|
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(:
|
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).
|
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).
|
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.
|
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.
|
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.
|
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
|