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.
- 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
|