git_reflow 0.7.5 → 0.8.0

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