git_reflow 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,522 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe GitReflow do
4
- let(:git_server) { GitReflow::GitServer::GitHub.new {} }
5
- let(:github) { Github.new basic_auth: "#{user}:#{password}" }
6
- let(:user) { 'reenhanced' }
7
- let(:password) { 'shazam' }
8
- let(:oauth_token_hash) { Hashie::Mash.new({ token: 'a1b2c3d4e5f6g7h8i9j0', note: 'hostname.local git-reflow'}) }
9
- let(:repo) { 'repo' }
10
- let(:base_branch) { 'master' }
11
- let(:feature_branch) { 'new-feature' }
12
- let(:enterprise_site) { 'https://github.reenhanced.com' }
13
- let(:enterprise_api) { 'https://github.reenhanced.com' }
14
- let(:hostname) { 'hostname.local' }
15
-
16
- let(:github_authorizations) { Github::Client::Authorizations.new }
17
- let(:existing_pull_requests) { Fixture.new('pull_requests/pull_requests.json').to_json_hashie }
18
- let(:existing_pull_request) { GitReflow::GitServer::GitHub::PullRequest.new existing_pull_requests.first }
19
-
20
- before do
21
-
22
- # Stubbing out minimum_approvals value to test 2 LGTM reviewers in gitconfig file
23
- allow(GitReflow::Config).to receive(:get).with("constants.minimumApprovals").and_return("2")
24
- allow(GitReflow::Config).to receive(:get).and_call_original
25
-
26
- allow_any_instance_of(HighLine).to receive(:ask) do |terminal, question|
27
- values = {
28
- "Please enter your GitHub username: " => user,
29
- "Please enter your GitHub password (we do NOT store this): " => password,
30
- "Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
31
- "Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api,
32
- "Would you like to push this branch to your remote repo and cleanup your feature branch? " => 'yes',
33
- "Would you like to open it in your browser?" => 'n',
34
- "This is the current status of your Pull Request. Are you sure you want to deliver? " => 'y',
35
- "Please enter your delivery commit title: (leaving blank will use default)" => 'title',
36
- "Please enter your delivery commit message: (leaving blank will use default)" => 'message'
37
- }
38
- return_value = values[question] || values[terminal]
39
- question = ""
40
- return_value
41
- end
42
- end
43
-
44
- context :deliver do
45
- let(:branch) { 'new-feature' }
46
- let(:inputs) {
47
- { :title => "new-feature",
48
- :message => "message",
49
- :head => "reenhanced:new-feature"
50
- }
51
- }
52
- let(:merge_response) { {} }
53
- let!(:github) do
54
- allow_any_instance_of(GitReflow::GitServer::GitHub::PullRequest).to receive(:build).and_return(Struct.new(:state, :description, :url).new)
55
- stub_github_with({
56
- :user => user,
57
- :password => password,
58
- :repo => repo,
59
- :branch => branch,
60
- :pull => existing_pull_request
61
- })
62
- end
63
-
64
-
65
- before do
66
- allow(GitReflow::GitServer::GitHub).to receive_message_chain(:connection, :pull_requests, :merge).and_return(merge_response)
67
- allow(merge_response).to receive(:success?).and_return(true)
68
-
69
- # Stubs out the http response to github api
70
- allow(GitReflow::GitServer::GitHub).to receive_message_chain(:connection, :pull_requests, :merge).and_return(merge_response)
71
- allow(merge_response).to receive(:success?).and_return(true);
72
-
73
- module Kernel
74
- def system(cmd)
75
- "call #{cmd}"
76
- end
77
- end
78
- end
79
-
80
- subject { GitReflow.deliver inputs }
81
-
82
- it "looks for a pull request matching the feature branch and destination branch" do
83
- expect(github).to receive(:find_open_pull_request).with(from: branch, to: 'master')
84
- subject
85
- end
86
-
87
- context "and pull request exists for the feature branch to the destination branch" do
88
- before do
89
- allow(github).to receive(:build_status).and_return(build_status)
90
- expect(github).to receive(:find_open_pull_request).and_return(existing_pull_request)
91
- allow(existing_pull_request).to receive(:has_comments?).and_return(true)
92
- allow(github).to receive(:reviewers).and_return(['codenamev'])
93
- allow(existing_pull_request).to receive(:approvals).and_return(["Simon", "John"])
94
- allow(existing_pull_request).to receive_message_chain(:last_comment, :match).and_return(true)
95
- allow(GitReflow::Config).to receive(:get).with("reflow.always-deliver").and_return("true")
96
- allow(GitReflow).to receive(:status)
97
- end
98
-
99
- context 'and build status is not "success"' do
100
- let(:build_status) { Hashie::Mash.new({ state: 'failure', description: 'Build resulted in failed test(s)' }) }
101
-
102
- before do
103
- allow(existing_pull_request).to receive(:build).and_return(build_status)
104
- allow(existing_pull_request).to receive(:has_comments?).and_return(true)
105
- end
106
-
107
- it "halts delivery and notifies user of a failed build" do
108
- expect { subject }.to have_said "#{build_status.description}: #{build_status.target_url}", :deliver_halted
109
- end
110
-
111
- context 'forces a merge' do
112
- before do
113
- inputs[:skip_lgtm] = true
114
- allow(existing_pull_request).to receive(:has_comments?).and_return(true)
115
- allow(existing_pull_request).to receive(:reviewers).and_return([])
116
- allow(existing_pull_request).to receive(:reviewers_pending_response).and_return([])
117
- allow(existing_pull_request).to receive(:approvals).and_return(['simonzhu24'])
118
- allow(GitReflow).to receive(:append_to_squashed_commit_message)
119
- allow(GitReflow::Config).to receive(:get).with("reflow.always-cleanup").and_return("true")
120
- end
121
-
122
- it "checks out the base branch" do
123
- expect { subject }.to have_run_command("git checkout master")
124
- end
125
-
126
- it "pulls changes from remote repo to local branch" do
127
- expect { subject }.to have_run_command("git pull origin master")
128
- end
129
-
130
- it "deletes the remote feature branch" do
131
- expect { subject }.to have_run_command("git push origin :new-feature")
132
- end
133
-
134
- it "deletes the local feature branch" do
135
- expect { subject }.to have_run_command("git branch -D new-feature")
136
- end
137
-
138
- it "forces a merge" do
139
- expect { subject }.to have_said "Merging pull request ##{existing_pull_request.number}: '#{existing_pull_request.title}', from '#{existing_pull_request.head.label}' into '#{existing_pull_request.base.label}'", :notice
140
- expect { subject }.to have_said "Pull request ##{existing_pull_request.number} successfully merged.", :success
141
- end
142
- end
143
- end
144
-
145
- context 'and build status is nil' do
146
- let(:build_status) { nil }
147
-
148
- before do
149
- # stubbing unrelated results so we can just test that it made it insdide the conditional block
150
- inputs[:skip_lgtm] = false
151
- allow(existing_pull_request).to receive(:has_comments?).and_return(true)
152
- allow(existing_pull_request).to receive(:reviewers).and_return([])
153
- allow(existing_pull_request).to receive(:reviewers_pending_response).and_return([])
154
- allow(existing_pull_request).to receive(:approvals).and_return(['simonzhu24'])
155
- end
156
-
157
- it "ignores build status when not setup" do
158
- expect { subject }.to have_said "Pull request ##{existing_pull_request.number} successfully merged.", :success
159
- end
160
- end
161
-
162
- context 'and build status is "success"' do
163
- let(:build_status) { Hashie::Mash.new({ state: 'success' }) }
164
-
165
- context 'and has comments' do
166
- before do
167
- inputs[:skip_lgtm] = false
168
- allow(existing_pull_request).to receive(:has_comments?).and_return(true)
169
- end
170
-
171
- context 'but there are 2 LGTMs and irrelevant last comment' do
172
- let(:lgtm_comment_authors) { ['nhance', 'Simon'] }
173
- before do
174
- allow(existing_pull_request).to receive(:build).and_return(build_status)
175
- allow(existing_pull_request).to receive(:approvals).and_return(lgtm_comment_authors)
176
- allow(GitReflow::GitServer::PullRequest).to receive(:minimum_approvals).and_return("2")
177
- allow(existing_pull_request).to receive(:reviewers_pending_response).and_return([])
178
- allow(existing_pull_request).to receive_message_chain(:last_comment, :match).and_return(nil)
179
- end
180
-
181
- context "and the pull request has no body" do
182
- let(:first_commit_message) { "We'll do it live." }
183
-
184
- before do
185
- existing_pull_request.description = ''
186
- allow(github).to receive(:find_open_pull_request).and_return(existing_pull_request)
187
- allow(GitReflow).to receive(:get_first_commit_message).and_return(first_commit_message)
188
- allow(existing_pull_request).to receive(:reviewers).and_return(lgtm_comment_authors)
189
- end
190
- end
191
-
192
- it "doesn't notify user of the merge and performs it" do
193
- expect { subject }.to_not have_said "Merging pull request ##{existing_pull_request.number}: '#{existing_pull_request.title}', from '#{existing_pull_request.head.label}' into '#{existing_pull_request.base.label}'"
194
- end
195
-
196
- it "doesn't update the destination branch" do
197
- expect(GitReflow).to receive(:update_destination).with('master').never
198
- subject
199
- end
200
-
201
- context "and doesn't clean up feature branch" do
202
- before do
203
- allow_any_instance_of(HighLine).to receive(:ask) do |terminal, question|
204
- values = {
205
- "Please enter your GitHub username: " => user,
206
- "Please enter your GitHub password (we do NOT store this): " => password,
207
- "Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
208
- "Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api,
209
- "Would you like to push this branch to your remote repo and cleanup your feature branch?" => 'yes',
210
- "Would you like to open it in your browser?" => 'no',
211
- "This is the current status of your Pull Request. Are you sure you want to deliver? " => 'y',
212
- "Please enter your delivery commit title: (leaving blank will use default)" => 'title',
213
- "Please enter your delivery commit message: (leaving blank will use default)" => 'message'
214
- }
215
- return_value = values[question] || values[terminal]
216
- question = ""
217
- return_value
218
- end
219
- end
220
-
221
- context "not always" do
222
- before do
223
- allow(GitReflow::Config).to receive(:get) { "false" }
224
- end
225
-
226
- it "doesn't checkout the base branch" do
227
- expect { subject }.to_not have_run_command("git checkout master")
228
- end
229
-
230
- it "doesn't push local squash merged base branch to remote repo" do
231
- expect { subject }.to_not have_run_command("git pull origin master")
232
- end
233
-
234
- it "doesn't delete the remote feature branch" do
235
- expect { subject }.to_not have_run_command("git push origin :new-feature")
236
- end
237
-
238
- it "doesn't delete the local feature branch" do
239
- expect { subject }.to_not have_run_command("git branch -D new-feature")
240
- end
241
- end
242
-
243
- context "always" do
244
- before do
245
- allow(GitReflow::Config).to receive(:get) { "true" }
246
- end
247
-
248
- it "doesn't checkout the base branch" do
249
- expect { subject }.to_not have_run_command("git checkout master")
250
- end
251
-
252
- it "doesn't push local squash merged base branch to remote repo" do
253
- expect { subject }.to_not have_run_command("git pull origin master")
254
- end
255
-
256
- it "doesn't delete the remote feature branch" do
257
- expect { subject }.to_not have_run_command("git push origin :new-feature")
258
- end
259
-
260
- it "doesn't delete the local feature branch" do
261
- expect { subject }.to_not have_run_command("git branch -D new-feature")
262
- end
263
- end
264
-
265
- end
266
-
267
- context "and not cleaning up feature branch" do
268
- before do
269
- allow_any_instance_of(HighLine).to receive(:ask) do |terminal, question|
270
- values = {
271
- "Please enter your GitHub username: " => user,
272
- "Please enter your GitHub password (we do NOT store this): " => password,
273
- "Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
274
- "Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api,
275
- "Would you like to push this branch to your remote repo and cleanup your feature branch? " => 'no',
276
- "Would you like to open it in your browser?" => 'no',
277
- "This is the current status of your Pull Request. Are you sure you want to deliver? " => 'y',
278
- "Please enter your delivery commit title: (leaving blank will use default)" => 'title',
279
- "Please enter your delivery commit message: (leaving blank will use default)" => 'message'
280
- }
281
- return_value = values[question] || values[terminal]
282
- question = ""
283
- return_value
284
- end
285
- end
286
-
287
- it "doesn't checkout the base branch" do
288
- expect { subject }.to_not have_run_command('git checkout master')
289
- end
290
-
291
- it "doesn't pull changes from remote repo to local branch" do
292
- expect { subject }.to_not have_run_command('git pull origin master')
293
- end
294
-
295
- it "doesn't delete the feature branch on the remote repo" do
296
- expect { subject }.to_not have_run_command('git push origin :new-feature')
297
- end
298
-
299
- it "doesn't delete the local feature branch" do
300
- expect { subject }.to_not have_run_command('git branch -D new-feature')
301
- end
302
-
303
- it "doesn't provide instructions to undo the steps taken" do
304
- expect { subject }.to_not have_output("To reset and go back to your branch run \`git reset --hard origin/master && git checkout new-feature\`")
305
- end
306
- end
307
-
308
- context "and there were issues commiting the squash merge to the base branch" do
309
- before { stub_with_fallback(GitReflow, :run_command_with_label).with('git commit', {with_system: true}).and_return false }
310
- it "doesn't notifies user of issues commiting the squash merge of the feature branch" do
311
- expect { subject }.to_not have_said("There were problems commiting your feature... please check the errors above and try again.", :error)
312
- end
313
- end
314
- end
315
-
316
- context 'but there are 2 LGTMs and LGTM last comment' do
317
- let(:lgtm_comment_authors) { ['nhance', 'Simon'] }
318
- before do
319
- allow(existing_pull_request).to receive(:approvals).and_return(lgtm_comment_authors)
320
- allow(existing_pull_request).to receive(:reviewers_pending_response).and_return([])
321
- allow(existing_pull_request).to receive_message_chain(:last_comment, :match).and_return(true)
322
- end
323
-
324
- context "build status failure, testing description and target_url" do
325
- let(:build_status) { Hashie::Mash.new({ state: 'failure', description: 'Build resulted in failed test(s)', target_url: "www.error.com" }) }
326
-
327
- before do
328
- allow(existing_pull_request).to receive(:build).and_return(build_status)
329
- allow(existing_pull_request).to receive(:reviewers).and_return(lgtm_comment_authors)
330
- allow(existing_pull_request).to receive(:has_comments?).and_return(true)
331
- end
332
-
333
- it "halts delivery and notifies user of a failed build" do
334
- expect { subject }.to have_said "#{build_status.description}: #{build_status.url}", :deliver_halted
335
- end
336
- end
337
-
338
- context "build status nil" do
339
- let(:build_status) { nil }
340
-
341
- before do
342
- allow(github).to receive(:build).and_return(build_status)
343
- allow(existing_pull_request).to receive(:reviewers_pending_response).and_return([])
344
- allow(existing_pull_request).to receive(:has_comments_or_approvals).and_return(true)
345
- end
346
-
347
- it "commits the changes if the build status is nil but has comments/approvals and no pending response" do
348
- expect{ subject }.to have_said "Pull request ##{existing_pull_request.number} successfully merged.", :success
349
- end
350
- end
351
-
352
- context "and the pull request has no body" do
353
- let(:first_commit_message) { "We'll do it live." }
354
-
355
- before do
356
- existing_pull_request.description = ''
357
- allow(github).to receive(:find_open_pull_request).and_return(existing_pull_request)
358
- allow(GitReflow).to receive(:get_first_commit_message).and_return(first_commit_message)
359
- allow(existing_pull_request).to receive(:reviewers).and_return(lgtm_comment_authors)
360
- end
361
- end
362
-
363
- it "doesn't always deliver" do
364
- expect(GitReflow::Config).to receive(:get).with("reflow.always-deliver").and_return("false")
365
- expect { subject }.to have_said "Merge aborted", :deliver_halted
366
- end
367
-
368
- it "notifies user of the merge and performs it" do
369
- expect { subject }.to have_said "Merging pull request ##{existing_pull_request.number}: '#{existing_pull_request.title}', from '#{existing_pull_request.head.label}' into '#{existing_pull_request.base.label}'", :notice
370
- end
371
-
372
- it "commits the changes for the squash merge" do
373
- expect{ subject }.to have_said "Pull request ##{existing_pull_request.number} successfully merged.", :success
374
- end
375
-
376
- context "and cleaning up feature branch" do
377
- before do
378
- allow_any_instance_of(HighLine).to receive(:ask) do |terminal, question|
379
- values = {
380
- "Please enter your GitHub username: " => user,
381
- "Please enter your GitHub password (we do NOT store this): " => password,
382
- "Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
383
- "Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api,
384
- "Would you like to push this branch to your remote repo and cleanup your feature branch? " => 'yes',
385
- "Would you like to open it in your browser?" => 'no',
386
- "This is the current status of your Pull Request. Are you sure you want to deliver? " => 'y',
387
- "Please enter your delivery commit title: (leaving blank will use default)" => 'title',
388
- "Please enter your delivery commit message: (leaving blank will use default)" => 'message'
389
- }
390
- return_value = values[question] || values[terminal]
391
- question = ""
392
- return_value
393
- end
394
- end
395
-
396
- context "not always" do
397
- before do
398
- allow(GitReflow::Config).to receive(:get).with("reflow.always-cleanup").and_return("false")
399
- end
400
-
401
- it "pulls changes from remote repo to local branch" do
402
- expect { subject }.to have_run_command("git pull origin master")
403
- end
404
-
405
- it "deletes the remote feature branch" do
406
- expect { subject }.to have_run_command("git push origin :new-feature")
407
- end
408
-
409
- it "deletes the local feature branch" do
410
- expect { subject }.to have_run_command("git branch -D new-feature")
411
- end
412
- end
413
-
414
- context "always" do
415
- before do
416
- allow(GitReflow::Config).to receive(:get).with("reflow.always-cleanup").and_return("true")
417
- end
418
-
419
- it "checks out the base branch" do
420
- expect { subject }.to have_run_command("git checkout master")
421
- end
422
-
423
- it "pulls changes from remote repo to local branch" do
424
- expect { subject }.to have_run_command("git pull origin master")
425
- end
426
-
427
- it "deletes the remote feature branch" do
428
- expect { subject }.to have_run_command("git push origin :new-feature")
429
- end
430
-
431
- it "deletes the local feature branch" do
432
- expect { subject }.to have_run_command("git branch -D new-feature")
433
- end
434
- end
435
- end
436
-
437
- context "and not cleaning up feature branch" do
438
- before do
439
- allow_any_instance_of(HighLine).to receive(:ask) do |terminal, question|
440
- values = {
441
- "Please enter your GitHub username: " => user,
442
- "Please enter your GitHub password (we do NOT store this): " => password,
443
- "Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
444
- "Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api,
445
- "Would you like to push this branch to your remote repo and cleanup your feature branch? " => 'no',
446
- "Would you like to open it in your browser?" => 'no',
447
- "This is the current status of your Pull Request. Are you sure you want to deliver? " => 'y',
448
- "Please enter your delivery commit title: (leaving blank will use default)" => 'title',
449
- "Please enter your delivery commit message: (leaving blank will use default)" => 'message'
450
- }
451
- return_value = values[question] || values[terminal]
452
- question = ""
453
- return_value
454
- end
455
- end
456
-
457
- it "does update the local repo with the new squash merge" do
458
- expect { subject }.to have_run_command('git pull origin master')
459
- end
460
-
461
- it "doesn't delete the feature branch on the remote repo" do
462
- expect { subject }.to_not have_run_command('git push origin :new-feature')
463
- end
464
-
465
- it "doesn't delete the local feature branch" do
466
- expect { subject }.to_not have_run_command('git branch -D new-feature')
467
- end
468
-
469
- it "provides instructions to undo the steps taken" do
470
- expect { subject }.to have_said("To reset and go back to your branch run \`git reset --hard origin/master && git checkout new-feature\`")
471
- end
472
- end
473
- end
474
-
475
- context 'but there are still unaddressed comments' do
476
- let(:open_comment_authors) { ['nhance', 'codenamev'] }
477
- before { allow(existing_pull_request).to receive(:reviewers_pending_response).and_return(open_comment_authors) }
478
- it "notifies the user to get their code reviewed" do
479
- expect { subject }.to have_said "You still need a LGTM from: #{open_comment_authors.join(', ')}", :deliver_halted
480
- end
481
- end
482
- end
483
-
484
- context 'but has no comments' do
485
- before do
486
- allow(existing_pull_request).to receive(:has_comments?).and_return(false)
487
- allow(existing_pull_request).to receive(:approvals).and_return(['John', 'Simon'])
488
- allow(existing_pull_request).to receive(:reviewers_pending_response).and_return([])
489
- allow(existing_pull_request).to receive(:build).and_return(build_status)
490
- end
491
-
492
- it "notifies the user to get their code reviewed" do
493
- expect { subject }.to have_said "Pull request ##{existing_pull_request.number} successfully merged.", :success
494
- end
495
- end
496
-
497
- it "successfully finds a pull request for the current feature branch" do
498
- allow(existing_pull_request).to receive(:good_to_merge?).and_return(true)
499
- allow(existing_pull_request).to receive(:approvals).and_return(["Simon"])
500
- allow(existing_pull_request).to receive(:title).and_return(inputs[:title])
501
- expect { subject }.to have_said "Merging pull request #1: 'new-feature', from 'new-feature' into 'master'", :notice
502
- end
503
-
504
- it "merges and squashes the feature branch into the master branch" do
505
- allow(existing_pull_request).to receive(:good_to_merge?).and_return(true)
506
- allow(existing_pull_request).to receive(:approvals).and_return(["Simon"])
507
- allow(existing_pull_request).to receive(:title).and_return(inputs[:title])
508
- expect(existing_pull_request).to receive(:merge!).and_return(true)
509
- subject
510
- end
511
- end
512
- end
513
-
514
- context "and no pull request exists for the feature branch to the destination branch" do
515
- before { allow(github).to receive(:find_open_pull_request).and_return(nil) }
516
-
517
- it "notifies the user of a missing pull request" do
518
- expect { subject }.to have_said "No pull request exists for #{user}:#{branch}\nPlease submit your branch for review first with \`git reflow review\`", :deliver_halted
519
- end
520
- end
521
- end
522
- end