git_reflow 0.7.5 → 0.8.0

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