paratrooper 2.4.1 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/CHANGELOG.md +9 -2
- data/README.md +3 -4
- data/lib/paratrooper.rb +3 -0
- data/lib/paratrooper/callbacks.rb +2 -2
- data/lib/paratrooper/configuration.rb +94 -0
- data/lib/paratrooper/deploy.rb +42 -105
- data/lib/paratrooper/error.rb +3 -0
- data/lib/paratrooper/heroku_wrapper.rb +16 -22
- data/lib/paratrooper/local_api_key_extractor.rb +2 -1
- data/lib/paratrooper/notifiers/screen_notifier.rb +6 -5
- data/lib/paratrooper/pending_migration_check.rb +7 -6
- data/lib/paratrooper/source_control.rb +49 -0
- data/lib/paratrooper/system_caller.rb +19 -6
- data/lib/paratrooper/version.rb +1 -1
- data/paratrooper.gemspec +2 -2
- data/spec/paratrooper/configuration_spec.rb +352 -0
- data/spec/paratrooper/deploy_spec.rb +77 -232
- data/spec/paratrooper/heroku_wrapper_spec.rb +8 -38
- data/spec/paratrooper/local_api_key_extractor_spec.rb +2 -3
- data/spec/paratrooper/notifier_spec.rb +1 -1
- data/spec/paratrooper/pending_migration_check_spec.rb +14 -7
- data/spec/paratrooper/source_control_spec.rb +233 -0
- metadata +32 -28
- data/.bundle/config +0 -2
- data/.rspec +0 -2
- data/.ruby-version +0 -1
@@ -19,7 +19,6 @@ describe Paratrooper::Deploy do
|
|
19
19
|
let(:options) { Hash.new }
|
20
20
|
let(:heroku) do
|
21
21
|
double(:heroku,
|
22
|
-
app_url: 'application_url',
|
23
22
|
app_restart: true,
|
24
23
|
app_maintenance_on: true,
|
25
24
|
app_maintenance_off: true,
|
@@ -36,93 +35,26 @@ describe Paratrooper::Deploy do
|
|
36
35
|
end
|
37
36
|
let(:http_client) { double(:http_client).as_null_object }
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
deployer.tag = "tag_name"
|
42
|
-
expect(deployer.tag_name).to eq("tag_name")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "match_tag_to=" do
|
47
|
-
specify "match_tag is set and @match_tag_name holds value" do
|
48
|
-
deployer.match_tag = "staging"
|
49
|
-
expect(deployer.match_tag_name).to eq("staging")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe "branch=" do
|
54
|
-
specify "branch is set and @branch_name holds value" do
|
55
|
-
deployer.branch = "branch_name"
|
56
|
-
expect(deployer.branch_name).to eq("branch_name")
|
57
|
-
end
|
38
|
+
before do
|
39
|
+
allow(screen_notifier).to receive(:notify)
|
58
40
|
end
|
59
41
|
|
60
42
|
describe "passing a block to initialize" do
|
61
43
|
it "sets attributes on self" do
|
62
44
|
deployer = described_class.new(app_name, default_options) do |p|
|
63
|
-
p.match_tag = "staging"
|
64
|
-
p.tag = "production"
|
65
|
-
p.debug = true
|
66
45
|
p.deployment_host = "HOST"
|
67
|
-
p.protocol
|
68
|
-
end
|
69
|
-
expect(deployer.match_tag_name).to eq("staging")
|
70
|
-
expect(deployer.tag_name).to eq("production")
|
71
|
-
expect(deployer.debug).to be_true
|
72
|
-
expect(deployer.deployment_host).to eq("HOST")
|
73
|
-
expect(deployer.protocol).to eq("MOM")
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
describe "options" do
|
78
|
-
context "accepts :tag" do
|
79
|
-
let(:options) { { tag: 'tag_name' } }
|
80
|
-
|
81
|
-
it "and responds to #tag_name" do
|
82
|
-
expect(deployer.tag_name).to eq('tag_name')
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
context "accepts :heroku_auth" do
|
87
|
-
let(:options) { { heroku_auth: heroku } }
|
88
|
-
let(:heroku) { double(:heroku) }
|
89
|
-
|
90
|
-
it "and responds to #heroku" do
|
91
|
-
expect(deployer.heroku).to eq(heroku)
|
46
|
+
p.protocol = "MOM"
|
92
47
|
end
|
48
|
+
expect(deployer.config.deployment_host).to eq("HOST")
|
49
|
+
expect(deployer.config.protocol).to eq("MOM")
|
93
50
|
end
|
94
51
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
it "and responds to #notifiers" do
|
100
|
-
expect(deployer.notifiers).to eq([notifiers])
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "protocol" do
|
105
|
-
context "accepts :protocol" do
|
106
|
-
let(:options) { { protocol: 'https' } }
|
107
|
-
|
108
|
-
it "and responds to #protocol" do
|
109
|
-
expect(deployer.protocol).to eq('https')
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context "no value passed" do
|
114
|
-
it "and responds to #protocol with default value" do
|
115
|
-
expect(deployer.protocol).to eq('http')
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context "accepts :deployment_host" do
|
121
|
-
let(:options) { { deployment_host: 'host_name' } }
|
122
|
-
|
123
|
-
it "and responds to #notifiers" do
|
124
|
-
expect(deployer.deployment_host).to eq('host_name')
|
52
|
+
it "lazy loads dependent options" do
|
53
|
+
deployer = described_class.new(app_name, api_key: 'API_KEY') do |p|
|
54
|
+
p.force_push = false
|
125
55
|
end
|
56
|
+
expect(deployer.config.api_key).to eq('API_KEY')
|
57
|
+
expect(deployer.config.force_push).to eq(false)
|
126
58
|
end
|
127
59
|
end
|
128
60
|
|
@@ -132,32 +64,32 @@ describe Paratrooper::Deploy do
|
|
132
64
|
|
133
65
|
context "with pending migrations" do
|
134
66
|
before do
|
135
|
-
migration_check.
|
67
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(true)
|
136
68
|
end
|
137
69
|
|
138
70
|
it 'sends notification' do
|
139
|
-
deployer.
|
71
|
+
expect(deployer).to receive(:notify).with(:activate_maintenance_mode).once
|
140
72
|
deployer.activate_maintenance_mode
|
141
73
|
end
|
142
74
|
|
143
75
|
it "makes call to heroku to turn on maintenance mode" do
|
144
|
-
heroku.
|
76
|
+
expect(heroku).to receive(:app_maintenance_on)
|
145
77
|
deployer.activate_maintenance_mode
|
146
78
|
end
|
147
79
|
end
|
148
80
|
|
149
81
|
context "without pending migrations" do
|
150
82
|
before do
|
151
|
-
migration_check.
|
83
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(false)
|
152
84
|
end
|
153
85
|
|
154
86
|
it 'does not send notification' do
|
155
|
-
deployer.
|
87
|
+
expect(deployer).to_not receive(:notify).with(:activate_maintenance_mode)
|
156
88
|
deployer.activate_maintenance_mode
|
157
89
|
end
|
158
90
|
|
159
91
|
it "does not make a call to heroku to turn on maintenance mode" do
|
160
|
-
heroku.
|
92
|
+
expect(heroku).to_not receive(:app_maintenance_on)
|
161
93
|
deployer.activate_maintenance_mode
|
162
94
|
end
|
163
95
|
end
|
@@ -167,16 +99,16 @@ describe Paratrooper::Deploy do
|
|
167
99
|
let(:options) { { maintenance: false } }
|
168
100
|
|
169
101
|
before do
|
170
|
-
migration_check.
|
102
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(true)
|
171
103
|
end
|
172
104
|
|
173
105
|
it 'does not send notification' do
|
174
|
-
deployer.
|
106
|
+
expect(deployer).to_not receive(:notify).with(:activate_maintenance_mode)
|
175
107
|
deployer.activate_maintenance_mode
|
176
108
|
end
|
177
109
|
|
178
110
|
it "does not make a call to heroku to turn on maintenance mode" do
|
179
|
-
heroku.
|
111
|
+
expect(heroku).to_not receive(:app_maintenance_on)
|
180
112
|
deployer.activate_maintenance_mode
|
181
113
|
end
|
182
114
|
end
|
@@ -185,16 +117,16 @@ describe Paratrooper::Deploy do
|
|
185
117
|
let(:options) { { } }
|
186
118
|
|
187
119
|
before do
|
188
|
-
migration_check.
|
120
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(true)
|
189
121
|
end
|
190
122
|
|
191
123
|
it 'does not send notification' do
|
192
|
-
deployer.
|
124
|
+
expect(deployer).to_not receive(:notify).with(:activate_maintenance_mode)
|
193
125
|
deployer.activate_maintenance_mode
|
194
126
|
end
|
195
127
|
|
196
128
|
it "does not make a call to heroku to turn on maintenance mode" do
|
197
|
-
heroku.
|
129
|
+
expect(heroku).to_not receive(:app_maintenance_on)
|
198
130
|
deployer.activate_maintenance_mode
|
199
131
|
end
|
200
132
|
end
|
@@ -202,163 +134,103 @@ describe Paratrooper::Deploy do
|
|
202
134
|
|
203
135
|
describe "#deactivate_maintenance_mode" do
|
204
136
|
context "when maintenance_mode option is 'true'" do
|
205
|
-
let(:options) { {
|
137
|
+
let(:options) { { maintenance: true } }
|
206
138
|
|
207
139
|
context "with pending migrations" do
|
208
140
|
before do
|
209
|
-
migration_check.
|
141
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(true)
|
210
142
|
end
|
211
143
|
|
212
144
|
it 'sends notification' do
|
213
|
-
deployer.
|
145
|
+
expect(deployer).to receive(:notify).with(:deactivate_maintenance_mode).once
|
214
146
|
deployer.deactivate_maintenance_mode
|
215
147
|
end
|
216
148
|
|
217
149
|
it "makes call to heroku to turn on maintenance mode" do
|
218
|
-
heroku.
|
150
|
+
expect(heroku).to receive(:app_maintenance_off)
|
219
151
|
deployer.deactivate_maintenance_mode
|
220
152
|
end
|
221
153
|
end
|
222
154
|
|
223
155
|
context "without pending migrations" do
|
224
156
|
before do
|
225
|
-
migration_check.
|
157
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(false)
|
226
158
|
end
|
227
159
|
|
228
160
|
it 'does not send notification' do
|
229
|
-
deployer.
|
161
|
+
expect(deployer).to_not receive(:notify).with(:deactivate_maintenance_mode)
|
230
162
|
deployer.deactivate_maintenance_mode
|
231
163
|
end
|
232
164
|
|
233
165
|
it "does not make a call to heroku to turn on maintenance mode" do
|
234
|
-
heroku.
|
166
|
+
expect(heroku).to_not receive(:app_maintenance_off)
|
235
167
|
deployer.deactivate_maintenance_mode
|
236
168
|
end
|
237
169
|
end
|
238
170
|
end
|
239
171
|
end
|
240
172
|
|
241
|
-
describe "#
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
it 'sends notification' do
|
250
|
-
deployer.should_receive(:notify).with(:update_repo_tag).once
|
251
|
-
deployer.update_repo_tag
|
252
|
-
end
|
253
|
-
|
254
|
-
context "when deploy_tag is available" do
|
255
|
-
before do
|
256
|
-
options.merge!(match_tag: 'deploy_this')
|
257
|
-
end
|
258
|
-
|
259
|
-
it 'creates a git tag at deploy_tag reference point' do
|
260
|
-
system_caller.should_receive(:execute).with('git tag awesome deploy_this -f')
|
261
|
-
deployer.update_repo_tag
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
context "when no deploy_tag is available" do
|
266
|
-
it 'creates a git tag at HEAD' do
|
267
|
-
system_caller.should_receive(:execute).with('git tag awesome master -f')
|
268
|
-
deployer.update_repo_tag
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
it 'pushes git tag' do
|
273
|
-
expected = 'git push -f origin awesome'
|
274
|
-
system_caller.should_receive(:execute).with(expected)
|
275
|
-
deployer.update_repo_tag
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
context "when a tag_name is unavailable" do
|
280
|
-
let(:options) { Hash.new }
|
281
|
-
|
282
|
-
it 'no repo tags are created' do
|
283
|
-
system_caller.should_not_receive(:execute)
|
284
|
-
deployer.update_repo_tag
|
173
|
+
describe "#push_repo" do
|
174
|
+
let(:notifier) { double(:notifier) }
|
175
|
+
let(:source_control) { double(:source_control) }
|
176
|
+
let(:deployer) do
|
177
|
+
described_class.new('APP') do |d|
|
178
|
+
d.notifiers = notifier
|
179
|
+
d.source_control = source_control
|
285
180
|
end
|
286
181
|
end
|
287
|
-
end
|
288
182
|
|
289
|
-
describe "#push_repo" do
|
290
183
|
before do
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
deployer.should_receive(:notify)
|
296
|
-
.with(:push_repo, reference_point: 'master').once
|
297
|
-
deployer.push_repo
|
184
|
+
allow(source_control).to receive(:reference_point)
|
185
|
+
allow(source_control).to receive(:remote)
|
186
|
+
allow(source_control).to receive(:push_to_deploy)
|
187
|
+
allow(notifier).to receive(:notify)
|
298
188
|
end
|
299
189
|
|
300
|
-
|
301
|
-
|
302
|
-
|
190
|
+
it "sends notification" do
|
191
|
+
allow(notifier).to receive(:notify) do |step, options|
|
192
|
+
expect(step).to eq(:push_repo)
|
303
193
|
end
|
194
|
+
deployer.push_repo
|
304
195
|
|
305
|
-
|
306
|
-
expected_call = 'git push -f git@heroku.com:app.git refs/heads/BRANCH_NAME:refs/heads/master'
|
307
|
-
system_caller.should_receive(:execute).with(expected_call)
|
308
|
-
deployer.push_repo
|
309
|
-
end
|
196
|
+
expect(notifier).to have_received(:notify).once
|
310
197
|
end
|
311
198
|
|
312
|
-
|
313
|
-
|
314
|
-
deployer.tag_name = "TAG_NAME"
|
315
|
-
end
|
199
|
+
it "pushes repo to remote" do
|
200
|
+
deployer.push_repo
|
316
201
|
|
317
|
-
|
318
|
-
expected_call = 'git push -f git@heroku.com:app.git refs/tags/TAG_NAME:refs/heads/master'
|
319
|
-
system_caller.should_receive(:execute).with(expected_call)
|
320
|
-
deployer.push_repo
|
321
|
-
end
|
202
|
+
expect(source_control).to have_received(:push_to_deploy)
|
322
203
|
end
|
323
|
-
|
324
|
-
context "when no branch_name or tag_name" do
|
325
|
-
it 'pushes master repo to heroku' do
|
326
|
-
expected_call = 'git push -f git@heroku.com:app.git master:refs/heads/master'
|
327
|
-
system_caller.should_receive(:execute).with(expected_call)
|
328
|
-
deployer.push_repo
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
204
|
end
|
333
205
|
|
334
206
|
describe "#run_migrations" do
|
335
207
|
before do
|
336
|
-
system_caller.
|
208
|
+
allow(system_caller).to receive(:execute)
|
337
209
|
end
|
338
210
|
|
339
211
|
context "when new migrations are waiting to be run" do
|
340
212
|
before do
|
341
|
-
migration_check.
|
213
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(true)
|
342
214
|
end
|
343
215
|
|
344
216
|
it 'sends notification' do
|
345
|
-
deployer.
|
217
|
+
expect(deployer).to receive(:notify).with(:run_migrations).once
|
346
218
|
deployer.run_migrations
|
347
219
|
end
|
348
220
|
|
349
221
|
it 'pushes repo to heroku' do
|
350
|
-
heroku.
|
222
|
+
expect(heroku).to receive(:run_migrations)
|
351
223
|
deployer.run_migrations
|
352
224
|
end
|
353
225
|
end
|
354
226
|
|
355
227
|
context "when no migrations are available to be run" do
|
356
228
|
before do
|
357
|
-
migration_check.
|
229
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(false)
|
358
230
|
end
|
359
231
|
|
360
232
|
specify "heroku is not notified to run migrations" do
|
361
|
-
heroku.
|
233
|
+
expect(heroku).to_not receive(:run_migrations)
|
362
234
|
deployer.run_migrations
|
363
235
|
end
|
364
236
|
end
|
@@ -367,7 +239,7 @@ describe Paratrooper::Deploy do
|
|
367
239
|
describe "#app_restart" do
|
368
240
|
context 'when a restart is required due to pending migrations' do
|
369
241
|
before do
|
370
|
-
migration_check.
|
242
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(true)
|
371
243
|
end
|
372
244
|
|
373
245
|
it 'sends notification' do
|
@@ -383,7 +255,7 @@ describe Paratrooper::Deploy do
|
|
383
255
|
|
384
256
|
context 'when a restart is not required' do
|
385
257
|
before do
|
386
|
-
migration_check.
|
258
|
+
allow(migration_check).to receive(:migrations_waiting?).and_return(false)
|
387
259
|
end
|
388
260
|
|
389
261
|
it 'does not send notification' do
|
@@ -398,68 +270,41 @@ describe Paratrooper::Deploy do
|
|
398
270
|
end
|
399
271
|
end
|
400
272
|
|
401
|
-
describe "#
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
it 'sends notification' do
|
407
|
-
deployer.should_receive(:notify).with(:warm_instance).once
|
408
|
-
deployer.warm_instance(0)
|
409
|
-
end
|
410
|
-
|
411
|
-
it 'pings application url' do
|
412
|
-
expected_url = 'http://application_url'
|
413
|
-
expect(http_client).to receive(:get).with(expected_url)
|
414
|
-
deployer.warm_instance(0)
|
415
|
-
end
|
416
|
-
|
417
|
-
context 'with optional protocol' do
|
418
|
-
let(:options) { { protocol: 'https' } }
|
273
|
+
describe "#add_callback" do
|
274
|
+
it "adds callback" do
|
275
|
+
callback = proc do |output|
|
276
|
+
system("touch spec/fixtures/test.txt")
|
277
|
+
end
|
419
278
|
|
420
|
-
|
421
|
-
|
422
|
-
expect(http_client).to receive(:get).with(expected_url)
|
423
|
-
deployer.warm_instance(0)
|
279
|
+
deployer = described_class.new(app_name, default_options) do |p|
|
280
|
+
p.add_callback(:before_setup, &callback)
|
424
281
|
end
|
282
|
+
|
283
|
+
expect(deployer.config.callbacks[:before_setup]).to eq([callback])
|
425
284
|
end
|
426
285
|
|
427
|
-
|
428
|
-
it "
|
286
|
+
context "when messaging is added to callback" do
|
287
|
+
it "is called" do
|
429
288
|
callback = proc do |output|
|
430
|
-
|
289
|
+
output.display("Whoo Hoo!")
|
431
290
|
end
|
432
291
|
|
292
|
+
allow(screen_notifier).to receive(:display).with("Whoo Hoo!")
|
293
|
+
|
433
294
|
deployer = described_class.new(app_name, default_options) do |p|
|
434
295
|
p.add_callback(:before_setup, &callback)
|
435
296
|
end
|
297
|
+
deployer.setup
|
436
298
|
|
437
|
-
expect(
|
438
|
-
end
|
439
|
-
|
440
|
-
context "when messaging is added to callback" do
|
441
|
-
it "is called" do
|
442
|
-
callback = proc do |output|
|
443
|
-
output.display("Whoo Hoo!")
|
444
|
-
end
|
445
|
-
|
446
|
-
screen_notifier.stub(:display).with("Whoo Hoo!")
|
447
|
-
|
448
|
-
deployer = described_class.new(app_name, default_options) do |p|
|
449
|
-
p.add_callback(:before_setup, &callback)
|
450
|
-
end
|
451
|
-
deployer.setup
|
452
|
-
|
453
|
-
expect(screen_notifier).to have_received(:display).with("Whoo Hoo!")
|
454
|
-
end
|
299
|
+
expect(screen_notifier).to have_received(:display).with("Whoo Hoo!")
|
455
300
|
end
|
456
301
|
end
|
302
|
+
end
|
457
303
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
end
|
304
|
+
describe "#add_remote_task" do
|
305
|
+
it "makes call to heroku to run task" do
|
306
|
+
expect(heroku).to receive(:run_task).with("rake some:task:to:run")
|
307
|
+
deployer.add_remote_task("rake some:task:to:run")
|
463
308
|
end
|
464
309
|
end
|
465
310
|
end
|