git_reflow 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +348 -348
- data/Gemfile.lock +13 -15
- data/LICENSE +20 -20
- data/README.rdoc +461 -461
- data/Rakefile +8 -8
- data/bin/console +7 -7
- data/bin/setup +6 -6
- data/circle.yml +5 -5
- data/exe/git-reflow +36 -36
- data/git_reflow.gemspec +1 -1
- data/lib/git_reflow/commands/deliver.rb +10 -10
- data/lib/git_reflow/commands/refresh.rb +20 -20
- data/lib/git_reflow/commands/review.rb +13 -13
- data/lib/git_reflow/commands/setup.rb +11 -11
- data/lib/git_reflow/commands/stage.rb +9 -9
- data/lib/git_reflow/commands/start.rb +22 -22
- data/lib/git_reflow/commands/status.rb +7 -7
- data/lib/git_reflow/config.rb +9 -9
- data/lib/git_reflow/git_server/base.rb +68 -68
- data/lib/git_reflow/git_server/bit_bucket/pull_request.rb +84 -84
- data/lib/git_reflow/git_server/bit_bucket.rb +101 -101
- data/lib/git_reflow/git_server/git_hub/pull_request.rb +4 -1
- data/lib/git_reflow/git_server/pull_request.rb +11 -2
- data/lib/git_reflow/git_server.rb +63 -63
- data/lib/git_reflow/logger.rb +49 -0
- data/lib/git_reflow/merge_error.rb +9 -9
- data/lib/git_reflow/os_detector.rb +23 -23
- data/lib/git_reflow/rspec/command_line_helpers.rb +12 -8
- data/lib/git_reflow/rspec/stub_helpers.rb +13 -13
- data/lib/git_reflow/rspec.rb +2 -2
- data/lib/git_reflow/sandbox.rb +11 -6
- data/lib/git_reflow/version.rb +1 -1
- data/lib/git_reflow/workflow.rb +59 -59
- data/lib/git_reflow/workflows/core.rb +238 -238
- data/lib/git_reflow/workflows/flat_merge.rb +10 -10
- data/lib/git_reflow.rb +11 -0
- data/spec/fixtures/awesome_workflow.rb +7 -0
- data/spec/fixtures/git/git_config +7 -0
- data/spec/fixtures/issues/comment.json.erb +27 -0
- data/spec/fixtures/issues/comments.json +29 -0
- data/spec/fixtures/issues/comments.json.erb +15 -0
- data/spec/fixtures/pull_requests/comment.json.erb +45 -0
- data/spec/fixtures/pull_requests/comments.json +47 -0
- data/spec/fixtures/pull_requests/comments.json.erb +15 -0
- data/spec/fixtures/pull_requests/commits.json +29 -0
- data/spec/fixtures/pull_requests/external_pull_request.json +145 -0
- data/spec/fixtures/pull_requests/pull_request.json +142 -0
- data/spec/fixtures/pull_requests/pull_request.json.erb +142 -0
- data/spec/fixtures/pull_requests/pull_request_exists_error.json +32 -0
- data/spec/fixtures/pull_requests/pull_requests.json +136 -0
- data/spec/fixtures/repositories/commit.json +53 -0
- data/spec/fixtures/repositories/commit.json.erb +53 -0
- data/spec/fixtures/repositories/commits.json.erb +13 -0
- data/spec/fixtures/repositories/statuses.json +31 -0
- data/spec/fixtures/workflow_with_super.rb +8 -0
- data/spec/lib/git_reflow/config_spec.rb +74 -0
- data/spec/lib/git_reflow/git_helpers_spec.rb +182 -0
- data/spec/lib/git_reflow/git_server/bit_bucket_spec.rb +81 -0
- data/spec/lib/git_reflow/git_server/git_hub/pull_request_spec.rb +587 -0
- data/spec/lib/git_reflow/git_server/git_hub_spec.rb +221 -0
- data/spec/lib/git_reflow/git_server/pull_request_spec.rb +524 -0
- data/spec/lib/git_reflow/git_server_spec.rb +101 -0
- data/spec/lib/git_reflow/logger_spec.rb +18 -0
- data/spec/lib/git_reflow/sandbox_spec.rb +15 -0
- data/spec/lib/git_reflow/workflow_spec.rb +59 -0
- data/spec/lib/git_reflow/workflows/core_spec.rb +665 -0
- data/spec/lib/git_reflow/workflows/flat_merge_spec.rb +59 -0
- data/spec/lib/git_reflow_spec.rb +75 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/fake_github.rb +128 -0
- data/spec/support/fixtures.rb +54 -0
- data/spec/support/github_helpers.rb +109 -0
- data/spec/support/mock_pull_request.rb +17 -0
- data/spec/support/web_mocks.rb +39 -0
- metadata +83 -6
@@ -0,0 +1,665 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GitReflow::Workflows::Core do
|
4
|
+
let(:feature_branch) { 'new-feature' }
|
5
|
+
let(:existing_pull_requests) { Fixture.new('pull_requests/pull_requests.json').to_json_hashie }
|
6
|
+
let(:existing_gh_pull_request) { GitReflow::GitServer::GitHub::PullRequest.new existing_pull_requests.first }
|
7
|
+
let(:pull_request_message_file) { "#{GitReflow.git_root_dir}/.git/GIT_REFLOW_PR_MSG" }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(GitReflow).to receive(:current_branch).and_return(feature_branch)
|
11
|
+
allow_any_instance_of(HighLine).to receive(:choose)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ".setup" do
|
15
|
+
subject { GitReflow::Workflows::Core.setup }
|
16
|
+
|
17
|
+
before do
|
18
|
+
allow(File).to receive(:exist?).and_return(false)
|
19
|
+
stub_command_line_inputs({
|
20
|
+
'Set the minimum number of approvals (leaving blank will require approval from all commenters): ' => ''
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
specify { expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all core.editor \"#{GitReflow.default_editor}\"", blocking: false }
|
25
|
+
specify { expect { subject }.to have_said "Updated git's editor (via git config key 'core.editor') to: #{GitReflow.default_editor}.", :notice }
|
26
|
+
|
27
|
+
context "core.editor git config has already been set" do
|
28
|
+
before do
|
29
|
+
allow(GitReflow::Config).to receive(:get) { "" }
|
30
|
+
allow(GitReflow::Config).to receive(:get).with('core.editor').and_return('emacs')
|
31
|
+
end
|
32
|
+
|
33
|
+
specify { expect { subject }.to_not have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all core.editor \"#{GitReflow.default_editor}\"", blocking: false }
|
34
|
+
end
|
35
|
+
|
36
|
+
context "git-reflow has not been setup before" do
|
37
|
+
it "notifies the user of global setup" do
|
38
|
+
expect { subject }.to have_said "We'll walk you through setting up git-reflow's defaults for all your projects.", :notice
|
39
|
+
expect { subject }.to have_said "In the future, you can run \`git-reflow setup\` from the root of any project you want to setup differently.", :notice
|
40
|
+
expect { subject }.to have_said "To adjust these settings globally, you can run \`git-reflow setup --global\`.", :notice
|
41
|
+
end
|
42
|
+
|
43
|
+
it "creates a .gitconfig.reflow file and includes it in the user's global git config" do
|
44
|
+
expect { subject }.to have_run_command "touch #{GitReflow::Config::CONFIG_FILE_PATH}"
|
45
|
+
expect { subject }.to have_run_command_silently "git config --global --add include.path \"#{GitReflow::Config::CONFIG_FILE_PATH}\"", blocking: false
|
46
|
+
|
47
|
+
expect { subject }.to have_said "Created #{GitReflow::Config::CONFIG_FILE_PATH} for git-reflow specific configurations.", :notice
|
48
|
+
expect { subject }.to have_said "Added #{GitReflow::Config::CONFIG_FILE_PATH} to include.path in $HOME/.gitconfig.", :notice
|
49
|
+
end
|
50
|
+
|
51
|
+
it "sets the default approval minimum and regex" do
|
52
|
+
expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all constants.minimumApprovals \"\"", blocking: false
|
53
|
+
expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all constants.approvalRegex \"#{GitReflow::GitServer::PullRequest::DEFAULT_APPROVAL_REGEX}\"", blocking: false
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when setting a custom approval minimum" do
|
57
|
+
before do
|
58
|
+
stub_command_line_inputs({
|
59
|
+
'Set the minimum number of approvals (leaving blank will require approval from all commenters): ' => '3'
|
60
|
+
})
|
61
|
+
end
|
62
|
+
|
63
|
+
specify { expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all constants.minimumApprovals \"3\"", blocking: false }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "git-reflow has been setup before" do
|
68
|
+
before do
|
69
|
+
allow(File).to receive(:exist?).and_return(true)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "doesn't create another .gitconfig.reflow file" do
|
73
|
+
expect { subject }.to_not have_run_command "touch #{GitReflow::Config::CONFIG_FILE_PATH}"
|
74
|
+
expect { subject }.to_not have_said "Created #{GitReflow::Config::CONFIG_FILE_PATH} for git-reflow specific configurations.", :notice
|
75
|
+
end
|
76
|
+
|
77
|
+
it "doesn't add the .gitconfig.reflow file to the git-config include path" do
|
78
|
+
expect { subject }.to_not have_run_command_silently "git config --global --add include.path \"#{GitReflow::Config::CONFIG_FILE_PATH}\"", blocking: false
|
79
|
+
|
80
|
+
expect { subject }.to_not have_said "Added #{GitReflow::Config::CONFIG_FILE_PATH} to include.path in $HOME/.gitconfig.", :notice
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe ".start" do
|
86
|
+
let(:feature_branch) { 'new_feature' }
|
87
|
+
subject { GitReflow::Workflows::Core.start feature_branch: feature_branch }
|
88
|
+
|
89
|
+
it "updates the local repo and starts creates a new branch" do
|
90
|
+
expect { subject }.to have_run_commands_in_order [
|
91
|
+
"git checkout master",
|
92
|
+
"git pull origin master",
|
93
|
+
"git push origin master:refs/heads/#{feature_branch}",
|
94
|
+
"git checkout --track -b #{feature_branch} origin/#{feature_branch}"
|
95
|
+
]
|
96
|
+
end
|
97
|
+
|
98
|
+
context "but no branch name is provided" do
|
99
|
+
let(:feature_branch) { "" }
|
100
|
+
|
101
|
+
it "doesn't run any commands and returns usage" do
|
102
|
+
expect { subject }.to_not have_run_command "git checkout master"
|
103
|
+
expect { subject }.to_not have_run_command "git pull origin master"
|
104
|
+
expect { subject }.to_not have_run_command "git push origin master:refs/heads/#{feature_branch}"
|
105
|
+
expect { subject }.to_not have_run_command "git checkout --track -b #{feature_branch} origin/#{feature_branch}"
|
106
|
+
expect { subject }.to have_said "usage: git-reflow start [new-branch-name]", :error
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "starts from a different base branch when one is supplied" do
|
111
|
+
expect { GitReflow::Workflows::Core.start feature_branch: feature_branch, base: 'development' }.to have_run_commands_in_order [
|
112
|
+
"git checkout development",
|
113
|
+
"git pull origin development",
|
114
|
+
"git push origin development:refs/heads/#{feature_branch}",
|
115
|
+
"git checkout --track -b #{feature_branch} origin/#{feature_branch}"
|
116
|
+
]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe ".review" do
|
121
|
+
let(:feature_branch) { 'new-feature' }
|
122
|
+
let(:user) { 'reenhanced' }
|
123
|
+
let(:password) { 'shazam' }
|
124
|
+
let(:repo) { 'repo' }
|
125
|
+
let(:inputs) { {} }
|
126
|
+
|
127
|
+
before do
|
128
|
+
allow(GitReflow).to receive(:remote_user).and_return(user)
|
129
|
+
allow(GitReflow).to receive(:git_server).and_return(GitReflow::GitServer)
|
130
|
+
allow(GitReflow.git_server).to receive(:get_build_status).and_return(Struct.new(:state, :description, :url, :target_url).new)
|
131
|
+
allow(GitReflow.git_server).to receive(:find_open_pull_request).and_return(nil)
|
132
|
+
allow(GitReflow.git_server).to receive(:create_pull_request).and_return(existing_gh_pull_request)
|
133
|
+
allow(File).to receive(:open).with(pull_request_message_file, 'w')
|
134
|
+
allow(File).to receive(:read).with(pull_request_message_file).and_return("bingo")
|
135
|
+
allow(File).to receive(:delete)
|
136
|
+
|
137
|
+
stub_command_line_inputs({
|
138
|
+
"Submit pull request? (Y)" => ""
|
139
|
+
})
|
140
|
+
end
|
141
|
+
|
142
|
+
subject { GitReflow::Workflows::Core.review inputs }
|
143
|
+
|
144
|
+
it "fetches updates to the base branch" do
|
145
|
+
expect { subject }.to have_run_command "git fetch origin master"
|
146
|
+
end
|
147
|
+
|
148
|
+
it "pushes the current branch to the remote repo" do
|
149
|
+
expect { subject }.to have_run_command "git push origin #{feature_branch}"
|
150
|
+
end
|
151
|
+
|
152
|
+
it "uses the current branch name as the text for the PR" do
|
153
|
+
fake_file = double
|
154
|
+
expect(File).to receive(:open).with(pull_request_message_file, "w").and_yield(fake_file)
|
155
|
+
expect(fake_file).to receive(:write).with(GitReflow.current_branch)
|
156
|
+
subject
|
157
|
+
end
|
158
|
+
|
159
|
+
it "opens the pull request file for modification" do
|
160
|
+
allow(File).to receive(:open).with(pull_request_message_file, 'w')
|
161
|
+
expect { subject }.to have_run_command "#{GitReflow.git_editor_command} #{pull_request_message_file}"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "reads the file then cleans up the temporary pull request message file" do
|
165
|
+
expect(File).to receive(:read).with(pull_request_message_file)
|
166
|
+
expect(File).to receive(:delete).with(pull_request_message_file)
|
167
|
+
subject
|
168
|
+
end
|
169
|
+
|
170
|
+
it "displays a review of the PR before submitting it" do
|
171
|
+
expect { subject }.to have_said "\nReview your PR:\n"
|
172
|
+
expect { subject }.to have_said "Title:\nbingo\n\n"
|
173
|
+
expect { subject }.to have_said "Body:\n\n\n"
|
174
|
+
end
|
175
|
+
|
176
|
+
context "and a PR template exists" do
|
177
|
+
let(:template_content) { "hey now" }
|
178
|
+
before do
|
179
|
+
allow(GitReflow).to receive(:pull_request_template).and_return(template_content)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "uses the template's content for the PR" do
|
183
|
+
fake_file = double
|
184
|
+
expect(File).to receive(:open).with(pull_request_message_file, "w").and_yield(fake_file)
|
185
|
+
expect(fake_file).to receive(:write).with(template_content)
|
186
|
+
subject
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
context "providing a base branch" do
|
192
|
+
let(:inputs) {{ base: "development" }}
|
193
|
+
|
194
|
+
before do
|
195
|
+
stub_command_line_inputs({
|
196
|
+
'Submit pull request? (Y)' => 'yes'
|
197
|
+
})
|
198
|
+
end
|
199
|
+
|
200
|
+
it "creates a pull request using the custom base branch" do
|
201
|
+
expect(GitReflow.git_server).to receive(:create_pull_request).with({
|
202
|
+
title: 'bingo',
|
203
|
+
body: "\n",
|
204
|
+
head: "#{user}:#{feature_branch}",
|
205
|
+
base: inputs[:base]
|
206
|
+
})
|
207
|
+
subject
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context "providing only a title" do
|
212
|
+
let(:inputs) {{ title: "Amazing new feature" }}
|
213
|
+
|
214
|
+
before do
|
215
|
+
stub_command_line_inputs({
|
216
|
+
'Submit pull request? (Y)' => 'yes'
|
217
|
+
})
|
218
|
+
end
|
219
|
+
|
220
|
+
it "creates a pull request with only the given title" do
|
221
|
+
expect(GitReflow.git_server).to receive(:create_pull_request).with({
|
222
|
+
title: inputs[:title],
|
223
|
+
body: nil,
|
224
|
+
head: "#{user}:#{feature_branch}",
|
225
|
+
base: 'master'
|
226
|
+
})
|
227
|
+
subject
|
228
|
+
end
|
229
|
+
|
230
|
+
it "does not bother opening any template file" do
|
231
|
+
expect(File).to_not receive(:open)
|
232
|
+
expect(File).to_not receive(:read)
|
233
|
+
expect(File).to_not receive(:delete)
|
234
|
+
subject
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context "providing only a body" do
|
239
|
+
let(:inputs) {{ body: "Please pull this in!" }}
|
240
|
+
|
241
|
+
before do
|
242
|
+
stub_command_line_inputs({
|
243
|
+
'Submit pull request? (Y)' => 'yes'
|
244
|
+
})
|
245
|
+
end
|
246
|
+
|
247
|
+
it "creates a pull request with the body as both title and body" do
|
248
|
+
expect(GitReflow.git_server).to receive(:create_pull_request).with({
|
249
|
+
title: inputs[:body],
|
250
|
+
body: inputs[:body],
|
251
|
+
head: "#{user}:#{feature_branch}",
|
252
|
+
base: 'master'
|
253
|
+
})
|
254
|
+
subject
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
context "providing both title and body" do
|
259
|
+
let(:inputs) {{ title: "Amazing new feature", body: "Please pull this in!" }}
|
260
|
+
|
261
|
+
before do
|
262
|
+
stub_command_line_inputs({
|
263
|
+
'Submit pull request? (Y)' => 'yes'
|
264
|
+
})
|
265
|
+
end
|
266
|
+
|
267
|
+
it "creates a pull request with only the given title" do
|
268
|
+
expect(GitReflow.git_server).to receive(:create_pull_request).with({
|
269
|
+
title: inputs[:title],
|
270
|
+
body: inputs[:body],
|
271
|
+
head: "#{user}:#{feature_branch}",
|
272
|
+
base: 'master'
|
273
|
+
})
|
274
|
+
subject
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context "with existing pull request" do
|
279
|
+
before do
|
280
|
+
expect(GitReflow.git_server).to receive(:find_open_pull_request).and_return(existing_gh_pull_request)
|
281
|
+
allow(existing_gh_pull_request).to receive(:display_pull_request_summary)
|
282
|
+
end
|
283
|
+
|
284
|
+
specify { expect{subject}.to have_said "A pull request already exists for these branches:", :notice }
|
285
|
+
|
286
|
+
it "displays a notice that an existing PR exists" do
|
287
|
+
expect(existing_gh_pull_request).to receive(:display_pull_request_summary)
|
288
|
+
subject
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context "approving PR submission" do
|
293
|
+
before do
|
294
|
+
stub_command_line_inputs({
|
295
|
+
'Submit pull request? (Y)' => 'yes'
|
296
|
+
})
|
297
|
+
end
|
298
|
+
|
299
|
+
it "creates a pull request" do
|
300
|
+
expect(GitReflow.git_server).to receive(:create_pull_request).with({
|
301
|
+
title: 'bingo',
|
302
|
+
body: "\n",
|
303
|
+
head: "#{user}:#{feature_branch}",
|
304
|
+
base: 'master'
|
305
|
+
})
|
306
|
+
subject
|
307
|
+
end
|
308
|
+
|
309
|
+
it "notifies the user that the pull request was created" do
|
310
|
+
expect(GitReflow.git_server).to receive(:create_pull_request).and_return(existing_gh_pull_request)
|
311
|
+
expect{ subject }.to have_said "Successfully created pull request ##{existing_gh_pull_request.number}: #{existing_gh_pull_request.title}\nPull Request URL: #{existing_gh_pull_request.html_url}\n", :success
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
context "aborting during PR template review" do
|
316
|
+
before do
|
317
|
+
stub_command_line_inputs({
|
318
|
+
'Submit pull request? (Y)' => 'no'
|
319
|
+
})
|
320
|
+
end
|
321
|
+
|
322
|
+
it "does not create a pull request" do
|
323
|
+
expect(GitReflow.git_server).to_not receive(:create_pull_request)
|
324
|
+
subject
|
325
|
+
end
|
326
|
+
|
327
|
+
it "notifies the user that the review was aborted" do
|
328
|
+
expect { subject }.to have_said "Review aborted. No pull request has been created.", :review_halted
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
describe ".status" do
|
334
|
+
let(:feature_branch) { 'new-feature' }
|
335
|
+
let(:destination_branch) { nil }
|
336
|
+
|
337
|
+
subject { GitReflow::Workflows::Core.status destination_branch: destination_branch }
|
338
|
+
|
339
|
+
before do
|
340
|
+
allow(GitReflow).to receive(:git_server).and_return(GitReflow::GitServer)
|
341
|
+
allow(GitReflow.git_server).to receive(:get_build_status).and_return(Struct.new(:state, :description, :url, :target_url).new)
|
342
|
+
allow(GitReflow).to receive(:current_branch).and_return(feature_branch)
|
343
|
+
allow(existing_gh_pull_request).to receive(:display_pull_request_summary)
|
344
|
+
end
|
345
|
+
|
346
|
+
context "with no existing pull request" do
|
347
|
+
before { allow(GitReflow.git_server).to receive(:find_open_pull_request).with({from: feature_branch, to: 'master'}).and_return(nil) }
|
348
|
+
it { expect{ subject }.to have_said "No pull request exists for #{feature_branch} -> master", :notice }
|
349
|
+
it { expect{ subject }.to have_said "Run 'git reflow review master' to start the review process", :notice }
|
350
|
+
end
|
351
|
+
|
352
|
+
context "with an existing pull request" do
|
353
|
+
let(:destination_branch) { 'master' }
|
354
|
+
before do
|
355
|
+
allow(GitReflow.git_server).to receive(:find_open_pull_request).and_return(existing_gh_pull_request)
|
356
|
+
end
|
357
|
+
|
358
|
+
it "displays a summary of the pull request" do
|
359
|
+
expect(existing_gh_pull_request).to receive(:display_pull_request_summary)
|
360
|
+
expect{ subject }.to have_said "Here's the status of your review:"
|
361
|
+
end
|
362
|
+
|
363
|
+
context "with custom destination branch" do
|
364
|
+
let(:destination_branch) { 'develop' }
|
365
|
+
|
366
|
+
it "uses the custom destination branch to lookup the pull request" do
|
367
|
+
expect(GitReflow.git_server).to receive(:find_open_pull_request).with({from: feature_branch, to: destination_branch}).and_return(existing_gh_pull_request)
|
368
|
+
subject
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
describe ".deploy" do
|
375
|
+
let(:deploy_command) { "bundle exec cap #{destination} deploy" }
|
376
|
+
let(:destination) { nil }
|
377
|
+
subject { GitReflow::Workflows::Core.deploy(destination_server: destination) }
|
378
|
+
|
379
|
+
before do
|
380
|
+
stub_command_line_inputs({
|
381
|
+
"Enter the command you use to deploy to default (leaving blank will skip deployment)" => "bundle exec cap deploy",
|
382
|
+
"Enter the command you use to deploy to #{destination} (leaving blank will skip deployment)" => "bundle exec cap #{destination} deploy"
|
383
|
+
})
|
384
|
+
end
|
385
|
+
|
386
|
+
it "sets the local git-config for reflow.deploy-to-default-command" do
|
387
|
+
expect(GitReflow::Config).to receive(:set).with('reflow.deploy-to-default-command', deploy_command.squeeze, local: true)
|
388
|
+
subject
|
389
|
+
end
|
390
|
+
|
391
|
+
it "runs the staging deploy command" do
|
392
|
+
expect { subject }.to have_run_command(deploy_command.squeeze)
|
393
|
+
end
|
394
|
+
|
395
|
+
context "staging" do
|
396
|
+
let(:destination) { "staging" }
|
397
|
+
|
398
|
+
it "sets the local git-config for reflow.deploy-to-staging-command" do
|
399
|
+
expect(GitReflow::Config).to receive(:set).with('reflow.deploy-to-staging-command', deploy_command, local: true)
|
400
|
+
subject
|
401
|
+
end
|
402
|
+
|
403
|
+
it "runs the staging deploy command" do
|
404
|
+
expect { subject }.to have_run_command(deploy_command)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
describe ".stage" do
|
410
|
+
let(:feature_branch) { 'new-feature' }
|
411
|
+
|
412
|
+
subject { GitReflow::Workflows::Core.stage }
|
413
|
+
|
414
|
+
before do
|
415
|
+
allow(GitReflow).to receive(:current_branch).and_return(feature_branch)
|
416
|
+
allow(GitReflow::Config).to receive(:get).and_call_original
|
417
|
+
allow(GitReflow::Workflows::Core).to receive(:deploy)
|
418
|
+
end
|
419
|
+
|
420
|
+
it "checks out and updates the staging branch" do
|
421
|
+
expect(GitReflow::Config).to receive(:get).with('reflow.staging-branch', local: true).and_return('staging')
|
422
|
+
expect { subject }.to have_run_commands_in_order([
|
423
|
+
"git checkout staging",
|
424
|
+
"git pull origin staging",
|
425
|
+
"git merge #{feature_branch}",
|
426
|
+
"git push origin staging"
|
427
|
+
])
|
428
|
+
end
|
429
|
+
|
430
|
+
context "merge is not successful" do
|
431
|
+
before do
|
432
|
+
allow(GitReflow::Config).to receive(:get).with('reflow.staging-branch', local: true).and_return('staging')
|
433
|
+
allow(GitReflow).to receive(:run_command_with_label).and_call_original
|
434
|
+
expect(GitReflow).to receive(:run_command_with_label).with("git merge #{feature_branch}", with_system: true).and_return(false)
|
435
|
+
end
|
436
|
+
|
437
|
+
it "notifies the user of unsuccessful merge" do
|
438
|
+
expect { subject }.to have_said "There were issues merging your feature branch to staging.", :error
|
439
|
+
end
|
440
|
+
|
441
|
+
it "does not push any changes to the remote repo" do
|
442
|
+
expect { subject }.to_not have_run_command "git push origin staging"
|
443
|
+
end
|
444
|
+
|
445
|
+
it "does not deploy to staging" do
|
446
|
+
expect(GitReflow::Workflows::Core).to_not receive(:deploy)
|
447
|
+
subject
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
context "merge is successful" do
|
452
|
+
before do
|
453
|
+
allow(GitReflow::Config).to receive(:get).with('reflow.staging-branch', local: true).and_return('staging')
|
454
|
+
allow(GitReflow).to receive(:run_command_with_label).and_call_original
|
455
|
+
expect(GitReflow).to receive(:run_command_with_label).with("git merge #{feature_branch}", with_system: true).and_return(true).and_call_original
|
456
|
+
end
|
457
|
+
|
458
|
+
specify { expect{ subject }.to have_run_command "git push origin staging" }
|
459
|
+
|
460
|
+
context "and deployment is successful" do
|
461
|
+
before { expect(GitReflow::Workflows::Core).to receive(:deploy).with(destination_server: :staging).and_return(true) }
|
462
|
+
specify { expect{ subject }.to have_said "Deployed to Staging.", :success }
|
463
|
+
end
|
464
|
+
|
465
|
+
context "but deployment is not successful" do
|
466
|
+
before { allow(GitReflow::Workflows::Core).to receive(:deploy).with(destination_server: :staging).and_return(false) }
|
467
|
+
specify { expect{ subject }.to have_said "There were issues deploying to staging.", :error }
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
context "no staging branch has been setup" do
|
472
|
+
before do
|
473
|
+
allow(GitReflow::Config).to receive(:get).with('reflow.staging-branch', local: true).and_return('')
|
474
|
+
stub_command_line_inputs({
|
475
|
+
"What's the name of your staging branch? (default: 'staging') " => "bobby"
|
476
|
+
})
|
477
|
+
end
|
478
|
+
|
479
|
+
it "sets the reflow.staging-branch git config to 'staging'" do
|
480
|
+
expect(GitReflow::Config).to receive(:set).with("reflow.staging-branch", "bobby", local: true)
|
481
|
+
subject
|
482
|
+
end
|
483
|
+
|
484
|
+
it "checks out and updates the staging branch" do
|
485
|
+
allow(GitReflow::Config).to receive(:set).with("reflow.staging-branch", "bobby", local: true)
|
486
|
+
expect { subject }.to have_run_commands_in_order([
|
487
|
+
"git checkout bobby",
|
488
|
+
"git pull origin bobby",
|
489
|
+
"git merge #{feature_branch}",
|
490
|
+
"git push origin bobby"
|
491
|
+
])
|
492
|
+
end
|
493
|
+
|
494
|
+
context "and I don't enter one in" do
|
495
|
+
before do
|
496
|
+
stub_command_line_inputs({
|
497
|
+
"What's the name of your staging branch? (default: 'staging') " => ""
|
498
|
+
})
|
499
|
+
end
|
500
|
+
|
501
|
+
it "sets the reflow.staging-branch git config to 'staging'" do
|
502
|
+
expect { subject }.to have_run_command_silently "git config --replace-all reflow.staging-branch \"staging\"", blocking: false
|
503
|
+
end
|
504
|
+
|
505
|
+
it "checks out and updates the staging branch" do
|
506
|
+
expect { subject }.to have_run_commands_in_order([
|
507
|
+
"git checkout staging",
|
508
|
+
"git pull origin staging",
|
509
|
+
"git merge #{feature_branch}",
|
510
|
+
"git push origin staging"
|
511
|
+
])
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
describe ".deliver" do
|
518
|
+
let(:feature_branch) { 'new-feature' }
|
519
|
+
let(:user) { 'reenhanced' }
|
520
|
+
let(:repo) { 'repo' }
|
521
|
+
|
522
|
+
subject { GitReflow::Workflows::Core.deliver }
|
523
|
+
|
524
|
+
before do
|
525
|
+
allow(GitReflow).to receive(:git_server).and_return(GitReflow::GitServer)
|
526
|
+
allow(GitReflow).to receive(:remote_user).and_return(user)
|
527
|
+
allow(GitReflow).to receive(:current_branch).and_return(feature_branch)
|
528
|
+
allow(GitReflow.git_server).to receive(:get_build_status).and_return(Struct.new(:state, :description, :url, :target_url).new)
|
529
|
+
end
|
530
|
+
|
531
|
+
context "pull request does not exist" do
|
532
|
+
before { allow(GitReflow.git_server).to receive(:find_open_pull_request).with( from: feature_branch, to: 'master').and_return(nil) }
|
533
|
+
specify { expect{ subject }.to have_said "No pull request exists for #{user}:#{feature_branch}\nPlease submit your branch for review first with \`git reflow review\`", :deliver_halted }
|
534
|
+
end
|
535
|
+
|
536
|
+
context "pull request exists" do
|
537
|
+
before do
|
538
|
+
allow(GitReflow.git_server).to receive(:find_open_pull_request).with( from: feature_branch, to: 'master').and_return(existing_gh_pull_request)
|
539
|
+
allow(GitReflow::Workflows::Core).to receive(:status)
|
540
|
+
end
|
541
|
+
|
542
|
+
context "and PR passes all QA checks" do
|
543
|
+
before { allow(existing_gh_pull_request).to receive(:good_to_merge?).and_return(true) }
|
544
|
+
|
545
|
+
it "displays the status of the PR" do
|
546
|
+
allow(existing_gh_pull_request).to receive(:merge!)
|
547
|
+
expect(GitReflow::Workflows::Core).to receive(:status).with(destination_branch: 'master')
|
548
|
+
subject
|
549
|
+
end
|
550
|
+
|
551
|
+
it "merges the feature branch" do
|
552
|
+
expect(existing_gh_pull_request).to receive(:merge!)
|
553
|
+
subject
|
554
|
+
end
|
555
|
+
|
556
|
+
context "but there is an error from the git server" do
|
557
|
+
let(:github_error) { Github::Error::UnprocessableEntity.new(eval(Fixture.new('pull_requests/pull_request_exists_error.json').to_s)) }
|
558
|
+
before do
|
559
|
+
allow(existing_gh_pull_request).to receive(:merge!).and_raise github_error
|
560
|
+
end
|
561
|
+
|
562
|
+
it "notifies the user of the error" do
|
563
|
+
expect { subject }.to have_said "Github Error: #{github_error.inspect}", :error
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
context "and PR fails some QA checks" do
|
569
|
+
before do
|
570
|
+
allow(existing_gh_pull_request).to receive(:good_to_merge?).and_return(false)
|
571
|
+
allow(existing_gh_pull_request).to receive(:rejection_message).and_return("I think you need a hug.")
|
572
|
+
end
|
573
|
+
|
574
|
+
it "does not merge the feature branch" do
|
575
|
+
expect(existing_gh_pull_request).to_not receive(:merge!)
|
576
|
+
subject
|
577
|
+
end
|
578
|
+
|
579
|
+
it "does not display the status of the PR" do
|
580
|
+
expect(GitReflow::Workflows::Core).to_not receive(:status).with(destination_branch: 'master')
|
581
|
+
subject
|
582
|
+
end
|
583
|
+
|
584
|
+
it "notifies the user of the reason the merge is unsafe" do
|
585
|
+
expect { subject }.to have_said "I think you need a hug.", :deliver_halted
|
586
|
+
end
|
587
|
+
|
588
|
+
context "but forcing the deliver" do
|
589
|
+
subject { GitReflow::Workflows::Core.deliver force: true }
|
590
|
+
|
591
|
+
before do
|
592
|
+
allow(existing_gh_pull_request).to receive(:good_to_merge?).with(force: true).and_return(true)
|
593
|
+
allow(existing_gh_pull_request).to receive(:merge!).with(force: true, base: 'master', skip_lgtm: true)
|
594
|
+
end
|
595
|
+
|
596
|
+
it "displays the status of the PR" do
|
597
|
+
expect(GitReflow::Workflows::Core).to receive(:status).with(destination_branch: 'master')
|
598
|
+
subject
|
599
|
+
end
|
600
|
+
|
601
|
+
it "merges the feature branch anyway" do
|
602
|
+
expect(existing_gh_pull_request).to receive(:merge!).with(force: true, base: 'master', skip_lgtm: true)
|
603
|
+
subject
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
context "and using a custom base branch" do
|
609
|
+
subject { GitReflow::Workflows::Core.deliver base: 'development' }
|
610
|
+
before do
|
611
|
+
expect(GitReflow.git_server).to receive(:find_open_pull_request).with( from: feature_branch, to: 'development').and_return(existing_gh_pull_request)
|
612
|
+
allow(existing_gh_pull_request).to receive(:good_to_merge?).and_return(true)
|
613
|
+
end
|
614
|
+
|
615
|
+
|
616
|
+
it "displays the status of the PR" do
|
617
|
+
allow(existing_gh_pull_request).to receive(:merge!).with(base: 'development')
|
618
|
+
expect(GitReflow::Workflows::Core).to receive(:status).with(destination_branch: 'development')
|
619
|
+
subject
|
620
|
+
end
|
621
|
+
|
622
|
+
it "merges the feature branch" do
|
623
|
+
expect(existing_gh_pull_request).to receive(:merge!).with(base: 'development')
|
624
|
+
subject
|
625
|
+
end
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
describe ".refresh" do
|
631
|
+
subject { GitReflow::Workflows::Core.refresh }
|
632
|
+
|
633
|
+
it "updates the feature branch with default remote repo and base branch" do
|
634
|
+
expect(GitReflow).to receive(:update_feature_branch).with(remote: 'origin', base: 'master')
|
635
|
+
subject
|
636
|
+
end
|
637
|
+
|
638
|
+
context "providing a custom base branch" do
|
639
|
+
subject { GitReflow::Workflows::Core.refresh base: 'development' }
|
640
|
+
|
641
|
+
it "updates the feature branch with default remote repo and base branch" do
|
642
|
+
expect(GitReflow).to receive(:update_feature_branch).with(remote: 'origin', base: 'development')
|
643
|
+
subject
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
context "provding a custom remote repo" do
|
648
|
+
subject { GitReflow::Workflows::Core.refresh remote: 'upstream' }
|
649
|
+
|
650
|
+
it "updates the feature branch with default remote repo and base branch" do
|
651
|
+
expect(GitReflow).to receive(:update_feature_branch).with(remote: 'upstream', base: 'master')
|
652
|
+
subject
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
context "providing a custom base branch and remote repo" do
|
657
|
+
subject { GitReflow::Workflows::Core.refresh remote: 'upstream', base: 'development' }
|
658
|
+
|
659
|
+
it "updates the feature branch with default remote repo and base branch" do
|
660
|
+
expect(GitReflow).to receive(:update_feature_branch).with(remote: 'upstream', base: 'development')
|
661
|
+
subject
|
662
|
+
end
|
663
|
+
end
|
664
|
+
end
|
665
|
+
end
|