git_reflow 0.6.7 → 0.7.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +11 -9
- data/README.rdoc +3 -1
- data/bin/git-reflow +0 -11
- data/bin/gitreflow-common +1 -1
- data/git_reflow.gemspec +3 -2
- data/lib/git_reflow.rb +13 -60
- data/lib/git_reflow/commands/deliver.rb +1 -2
- data/lib/git_reflow/commands/start.rb +0 -6
- data/lib/git_reflow/config.rb +15 -14
- data/lib/git_reflow/git_server.rb +14 -4
- data/lib/git_reflow/git_server/base.rb +0 -39
- data/lib/git_reflow/git_server/bit_bucket.rb +15 -80
- data/lib/git_reflow/git_server/bit_bucket/pull_request.rb +84 -0
- data/lib/git_reflow/git_server/git_hub.rb +18 -75
- data/lib/git_reflow/git_server/git_hub/pull_request.rb +108 -0
- data/lib/git_reflow/git_server/pull_request.rb +97 -0
- data/lib/git_reflow/version.rb +1 -1
- data/spec/fixtures/issues/comment.json.erb +27 -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.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 +19 -0
- data/spec/fixtures/pull_requests/pull_request.json.erb +142 -0
- data/spec/fixtures/pull_requests/pull_requests.json +19 -0
- data/spec/fixtures/repositories/commit.json.erb +53 -0
- data/spec/fixtures/repositories/commits.json.erb +13 -0
- data/spec/git_reflow_spec.rb +32 -25
- data/spec/lib/git_reflow/config_spec.rb +22 -6
- data/spec/lib/git_server/bit_bucket_spec.rb +5 -34
- data/spec/lib/git_server/git_hub/pull_request_spec.rb +319 -0
- data/spec/lib/git_server/git_hub_spec.rb +17 -25
- data/spec/lib/git_server/pull_request_spec.rb +93 -0
- data/spec/support/command_line_helpers.rb +16 -1
- data/spec/support/fake_github.rb +128 -0
- data/spec/support/fixtures.rb +52 -6
- data/spec/support/github_helpers.rb +22 -12
- metadata +47 -6
@@ -0,0 +1,53 @@
|
|
1
|
+
{
|
2
|
+
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
3
|
+
"commit": {
|
4
|
+
"url": "https://api.github.com/repos/<%= repo_owner %>/<%= repo_name %>/git/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
5
|
+
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
6
|
+
"author": {
|
7
|
+
"name": "Monalisa Octocat",
|
8
|
+
"email": "support@github.com",
|
9
|
+
"date": "<%= created_at || "2011-04-14T16:00:49Z" %>"
|
10
|
+
},
|
11
|
+
"committer": {
|
12
|
+
"name": "Monalisa Octocat",
|
13
|
+
"email": "support@github.com",
|
14
|
+
"date": "<%= created_at || "2011-04-14T16:00:49Z" %>"
|
15
|
+
},
|
16
|
+
"message": "Fix all the bugs",
|
17
|
+
"tree": {
|
18
|
+
"url": "https://api.github.com/repos/<%= repo_owner %>/<%= repo_name %>/tree/6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
19
|
+
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
"author": {
|
23
|
+
"login": "<%= author %>",
|
24
|
+
"id": 1,
|
25
|
+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
26
|
+
"url": "https://api.github.com/users/<%= author %>"
|
27
|
+
},
|
28
|
+
"committer": {
|
29
|
+
"login": "<%= author %>",
|
30
|
+
"id": 1,
|
31
|
+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
32
|
+
"url": "https://api.github.com/users/<%= author %>"
|
33
|
+
},
|
34
|
+
"parents": [
|
35
|
+
{
|
36
|
+
"url": "https://api.github.com/repos/<%= repo_owner %>/<%= repo_name %>/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
|
37
|
+
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e"
|
38
|
+
}
|
39
|
+
],
|
40
|
+
"stats": {
|
41
|
+
"additions": 104,
|
42
|
+
"deletions": 4,
|
43
|
+
"total": 108
|
44
|
+
},
|
45
|
+
"files": [
|
46
|
+
{
|
47
|
+
"filename": "file1.txt",
|
48
|
+
"additions": 10,
|
49
|
+
"deletions": 2,
|
50
|
+
"total": 12
|
51
|
+
}
|
52
|
+
]
|
53
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
[
|
2
|
+
<% commits_json = [] %>
|
3
|
+
<% commits.each_with_index do |commit, index| %>
|
4
|
+
<% commits_json << Fixture.new('repositories/commit.json.erb',
|
5
|
+
id: index,
|
6
|
+
author: commit[:author],
|
7
|
+
repo_owner: repo_owner,
|
8
|
+
repo_name: repo_name,
|
9
|
+
created_at: commit[:created_at] || Chronic.parse("1.minute.ago")
|
10
|
+
).to_s %>
|
11
|
+
<% end %>
|
12
|
+
<%= commits_json.join(", ") %>
|
13
|
+
]
|
data/spec/git_reflow_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe GitReflow do
|
|
14
14
|
let(:hostname) { 'hostname.local' }
|
15
15
|
|
16
16
|
let(:github_authorizations) { Github::Client::Authorizations.new }
|
17
|
-
let(:existing_pull_requests) {
|
17
|
+
let(:existing_pull_requests) { Fixture.new('pull_requests/pull_requests.json').to_json_hashie }
|
18
18
|
let(:existing_pull_request) { GitReflow::GitServer::GitHub::PullRequest.new existing_pull_requests.first }
|
19
19
|
|
20
20
|
before do
|
@@ -37,11 +37,13 @@ describe GitReflow do
|
|
37
37
|
subject { GitReflow.status(base_branch) }
|
38
38
|
|
39
39
|
before do
|
40
|
-
GitReflow.
|
41
|
-
GitReflow.
|
40
|
+
allow(GitReflow).to receive(:current_branch).and_return(feature_branch)
|
41
|
+
allow(GitReflow).to receive(:destination_branch).and_return(base_branch)
|
42
42
|
|
43
|
-
Github.
|
44
|
-
GitReflow.
|
43
|
+
allow(Github).to receive(:new).and_return(github)
|
44
|
+
allow(GitReflow).to receive(:git_server).and_return(git_server)
|
45
|
+
allow(git_server).to receive(:connection).and_return(github)
|
46
|
+
allow(git_server).to receive(:get_build_status).and_return(Struct.new(:state, :description, :target_url).new())
|
45
47
|
end
|
46
48
|
|
47
49
|
context 'with no existing pull request' do
|
@@ -51,10 +53,12 @@ describe GitReflow do
|
|
51
53
|
end
|
52
54
|
|
53
55
|
context 'with an existing pull request' do
|
54
|
-
before
|
56
|
+
before do
|
57
|
+
git_server.stub(:find_open_pull_request).with({from: feature_branch, to: base_branch}).and_return(existing_pull_request)
|
58
|
+
end
|
55
59
|
|
56
60
|
it 'displays a summary of the pull request and asks to open it in the browser' do
|
57
|
-
|
61
|
+
existing_pull_request.should_receive(:display_pull_request_summary)
|
58
62
|
GitReflow.should_receive(:ask_to_open_in_browser).with(existing_pull_request.html_url)
|
59
63
|
subject
|
60
64
|
$output.should include "Here's the status of your review:"
|
@@ -77,6 +81,7 @@ describe GitReflow do
|
|
77
81
|
}
|
78
82
|
|
79
83
|
let(:github) do
|
84
|
+
allow_any_instance_of(GitReflow::GitServer::GitHub::PullRequest).to receive(:build).and_return(Struct.new(:state, :description, :url).new)
|
80
85
|
stub_github_with({
|
81
86
|
:user => user,
|
82
87
|
:password => password,
|
@@ -115,15 +120,15 @@ describe GitReflow do
|
|
115
120
|
context "pull request exists" do
|
116
121
|
before do
|
117
122
|
GitReflow.stub(:push_current_branch)
|
118
|
-
github_error = Github::Error::UnprocessableEntity.new( eval(
|
119
|
-
github.
|
120
|
-
|
123
|
+
github_error = Github::Error::UnprocessableEntity.new( eval(Fixture.new('pull_requests/pull_request_exists_error.json').to_s) )
|
124
|
+
github.should_receive(:find_open_pull_request).and_return(existing_pull_request)
|
125
|
+
existing_pull_request.stub(:display_pull_request_summary)
|
121
126
|
end
|
122
127
|
|
123
128
|
subject { GitReflow.review inputs }
|
124
129
|
|
125
130
|
it "displays a pull request summary for the existing pull request" do
|
126
|
-
|
131
|
+
existing_pull_request.should_receive(:display_pull_request_summary)
|
127
132
|
subject
|
128
133
|
end
|
129
134
|
|
@@ -138,6 +143,7 @@ describe GitReflow do
|
|
138
143
|
let(:branch) { 'new-feature' }
|
139
144
|
let(:inputs) { {} }
|
140
145
|
let!(:github) do
|
146
|
+
allow_any_instance_of(GitReflow::GitServer::GitHub::PullRequest).to receive(:build).and_return(Struct.new(:state, :description, :url).new)
|
141
147
|
stub_github_with({
|
142
148
|
:user => user,
|
143
149
|
:password => password,
|
@@ -173,16 +179,17 @@ describe GitReflow do
|
|
173
179
|
context "and pull request exists for the feature branch to the destination branch" do
|
174
180
|
before do
|
175
181
|
github.stub(:get_build_status).and_return(build_status)
|
176
|
-
github.
|
177
|
-
|
182
|
+
github.should_receive(:find_open_pull_request).and_return(existing_pull_request)
|
183
|
+
existing_pull_request.stub(:has_comments?).and_return(true)
|
184
|
+
github.stub(:reviewers).and_return(['codenamev'])
|
178
185
|
end
|
179
186
|
|
180
187
|
context 'and build status is not "success"' do
|
181
188
|
let(:build_status) { Hashie::Mash.new({ state: 'failure', description: 'Build resulted in failed test(s)' }) }
|
182
189
|
|
183
190
|
before do
|
184
|
-
|
185
|
-
|
191
|
+
existing_pull_request.stub(:build).and_return(build_status)
|
192
|
+
existing_pull_request.stub(:has_comments?).and_return(true)
|
186
193
|
end
|
187
194
|
|
188
195
|
it "halts delivery and notifies user of a failed build" do
|
@@ -196,8 +203,8 @@ describe GitReflow do
|
|
196
203
|
|
197
204
|
before do
|
198
205
|
# stubbing unrelated results so we can just test that it made it insdide the conditional block
|
199
|
-
|
200
|
-
|
206
|
+
existing_pull_request.stub(:has_comments?).and_return(true)
|
207
|
+
existing_pull_request.stub(:reviewers).and_return([])
|
201
208
|
GitReflow.stub(:update_destination).and_return(true)
|
202
209
|
GitReflow.stub(:merge_feature_branch).and_return(true)
|
203
210
|
GitReflow.stub(:append_to_squashed_commit_message).and_return(true)
|
@@ -213,14 +220,14 @@ describe GitReflow do
|
|
213
220
|
|
214
221
|
context 'and has comments' do
|
215
222
|
before do
|
216
|
-
|
223
|
+
existing_pull_request.stub(:has_comments?).and_return(true)
|
217
224
|
end
|
218
225
|
|
219
226
|
context 'but there is a LGTM' do
|
220
227
|
let(:lgtm_comment_authors) { ['nhance'] }
|
221
228
|
before do
|
222
|
-
|
223
|
-
|
229
|
+
existing_pull_request.stub(:approvals).and_return(lgtm_comment_authors)
|
230
|
+
existing_pull_request.stub(:reviewers_pending_response).and_return([])
|
224
231
|
end
|
225
232
|
|
226
233
|
it "includes the pull request body in the commit message" do
|
@@ -236,7 +243,7 @@ describe GitReflow do
|
|
236
243
|
existing_pull_request.description = ''
|
237
244
|
github.stub(:find_open_pull_request).and_return(existing_pull_request)
|
238
245
|
GitReflow.stub(:get_first_commit_message).and_return(first_commit_message)
|
239
|
-
|
246
|
+
existing_pull_request.stub(:reviewers).and_return(lgtm_comment_authors)
|
240
247
|
end
|
241
248
|
|
242
249
|
it "includes the first commit message for the new branch in the commit message of the merge" do
|
@@ -366,7 +373,7 @@ describe GitReflow do
|
|
366
373
|
|
367
374
|
context 'but there are still unaddressed comments' do
|
368
375
|
let(:open_comment_authors) { ['nhance', 'codenamev'] }
|
369
|
-
before {
|
376
|
+
before { existing_pull_request.stub(:reviewers_pending_response).and_return(open_comment_authors) }
|
370
377
|
it "notifies the user to get their code reviewed" do
|
371
378
|
expect { subject }.to have_said "You still need a LGTM from: #{open_comment_authors.join(', ')}", :deliver_halted
|
372
379
|
end
|
@@ -375,9 +382,9 @@ describe GitReflow do
|
|
375
382
|
|
376
383
|
context 'but has no comments' do
|
377
384
|
before do
|
378
|
-
|
379
|
-
|
380
|
-
|
385
|
+
existing_pull_request.stub(:has_comments?).and_return(false)
|
386
|
+
existing_pull_request.stub(:approvals).and_return([])
|
387
|
+
existing_pull_request.stub(:reviewers_pending_response).and_return([])
|
381
388
|
end
|
382
389
|
|
383
390
|
it "notifies the user to get their code reviewed" do
|
@@ -6,8 +6,24 @@ describe GitReflow::Config do
|
|
6
6
|
it { expect{ subject }.to have_run_command_silently 'git config --get chucknorris.roundhouse' }
|
7
7
|
|
8
8
|
context "and getting all values" do
|
9
|
-
subject { GitReflow::Config.get('chucknorris.roundhouse', all: true) }
|
10
|
-
it { expect{ subject }.to have_run_command_silently 'git config --get-all chucknorris.roundhouse' }
|
9
|
+
subject { GitReflow::Config.get('chucknorris.roundhouse-kick', all: true) }
|
10
|
+
it { expect{ subject }.to have_run_command_silently 'git config --get-all chucknorris.roundhouse-kick' }
|
11
|
+
|
12
|
+
context "and checking locally only" do
|
13
|
+
subject { GitReflow::Config.get('chucknorris.jump', local: true) }
|
14
|
+
it { expect{ subject }.to have_run_command_silently 'git config --local --get chucknorris.jump' }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "and checking for updates" do
|
19
|
+
before { GitReflow::Config.get('checknorris.roundhouse') }
|
20
|
+
subject { GitReflow::Config.get('chucknorris.roundhouse') }
|
21
|
+
it { expect{ subject }.to_not have_run_command_silently 'git config --get chucknorris.roundhouse-kick' }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "and checking locally only" do
|
25
|
+
subject { GitReflow::Config.get('chucknorris.smash', local: true) }
|
26
|
+
it { expect{ subject }.to have_run_command_silently 'git config --local --get chucknorris.smash' }
|
11
27
|
end
|
12
28
|
end
|
13
29
|
|
@@ -23,20 +39,20 @@ describe GitReflow::Config do
|
|
23
39
|
|
24
40
|
describe ".unset(key)" do
|
25
41
|
subject { GitReflow::Config.unset('chucknorris.roundhouse') }
|
26
|
-
it { expect{ subject }.to have_run_command_silently 'git config --global --unset chucknorris.roundhouse ' }
|
42
|
+
it { expect{ subject }.to have_run_command_silently 'git config --global --unset-all chucknorris.roundhouse ' }
|
27
43
|
|
28
44
|
context "for multi-value keys" do
|
29
45
|
subject { GitReflow::Config.unset('chucknorris.roundhouse', value: 'to the face') }
|
30
|
-
it { expect{ subject }.to have_run_command_silently 'git config --global --unset chucknorris.roundhouse "to the face"' }
|
46
|
+
it { expect{ subject }.to have_run_command_silently 'git config --global --unset-all chucknorris.roundhouse "to the face"' }
|
31
47
|
end
|
32
48
|
|
33
49
|
context "for current project only" do
|
34
50
|
subject { GitReflow::Config.unset('chucknorris.roundhouse', local: true) }
|
35
|
-
it { expect{ subject }.to have_run_command_silently 'git config --unset chucknorris.roundhouse ' }
|
51
|
+
it { expect{ subject }.to have_run_command_silently 'git config --unset-all chucknorris.roundhouse ' }
|
36
52
|
|
37
53
|
context "for multi-value keys" do
|
38
54
|
subject { GitReflow::Config.unset('chucknorris.roundhouse', value: 'to the face', local: true) }
|
39
|
-
it { expect{ subject }.to have_run_command_silently 'git config --unset chucknorris.roundhouse "to the face"' }
|
55
|
+
it { expect{ subject }.to have_run_command_silently 'git config --unset-all chucknorris.roundhouse "to the face"' }
|
40
56
|
end
|
41
57
|
end
|
42
58
|
end
|
@@ -25,7 +25,7 @@ describe GitReflow::GitServer::BitBucket do
|
|
25
25
|
subject { GitReflow::GitServer::BitBucket.new({}) }
|
26
26
|
|
27
27
|
it 'sets the reflow git server provider to BitBucket in the git config' do
|
28
|
-
GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'BitBucket')
|
28
|
+
GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'BitBucket', local: false)
|
29
29
|
subject
|
30
30
|
end
|
31
31
|
|
@@ -47,10 +47,11 @@ describe GitReflow::GitServer::BitBucket do
|
|
47
47
|
|
48
48
|
context 'already authenticated' do
|
49
49
|
it "notifies the user of successful setup" do
|
50
|
-
GitReflow::Config.
|
50
|
+
allow(GitReflow::Config).to receive(:set).with('reflow.git-server', 'BitBucket', local: false)
|
51
51
|
allow(GitReflow::Config).to receive(:get).with('remote.origin.url').and_return(remote_url)
|
52
|
-
allow(GitReflow::Config).to receive(:get).with('bitbucket.user').and_return(user)
|
53
|
-
allow(GitReflow::Config).to receive(:get).with('bitbucket.api-key', reload: true).and_return(api_key)
|
52
|
+
allow(GitReflow::Config).to receive(:get).with('bitbucket.user', local: false).and_return(user)
|
53
|
+
allow(GitReflow::Config).to receive(:get).with('bitbucket.api-key', reload: true, local: false).and_return(api_key)
|
54
|
+
allow(GitReflow::Config).to receive(:get).with('reflow.local-projects', all: true).and_return('')
|
54
55
|
expect { subject }.to have_output "\nYour BitBucket account was already setup with:"
|
55
56
|
expect { subject }.to have_output "\tUser Name: #{user}"
|
56
57
|
end
|
@@ -77,34 +78,4 @@ describe GitReflow::GitServer::BitBucket do
|
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
80
|
-
xdescribe '#create_pull_request(options)' do
|
81
|
-
let(:title) { 'Fresh title' }
|
82
|
-
let(:body) { 'Funky body' }
|
83
|
-
let(:current_branch) { 'new-feature' }
|
84
|
-
|
85
|
-
it 'creates a pull request using the remote user and repo' do
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
xdescribe '#find_pull_request(from, to)' do
|
90
|
-
end
|
91
|
-
|
92
|
-
xdescribe '#pull_request_comments(pull_request)' do
|
93
|
-
end
|
94
|
-
|
95
|
-
xdescribe '#has_pull_request_comments?(pull_request)' do
|
96
|
-
end
|
97
|
-
|
98
|
-
xdescribe '#get_build_status(sha)' do
|
99
|
-
end
|
100
|
-
|
101
|
-
xdescribe '#find_authors_of_open_pull_request_comments(pull_request)' do
|
102
|
-
end
|
103
|
-
|
104
|
-
xdescribe '#comment_authors_for_pull_request(pull_request, options = {})' do
|
105
|
-
end
|
106
|
-
|
107
|
-
xdescribe '#get_commited_time(commit_sha)' do
|
108
|
-
end
|
109
|
-
|
110
81
|
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GitReflow::GitServer::GitHub::PullRequest do
|
4
|
+
let(:user) { 'reenhanced' }
|
5
|
+
let(:password) { 'shazam' }
|
6
|
+
let(:repo) { 'repo' }
|
7
|
+
let(:oauth_token_hash) { Hashie::Mash.new({ token: 'a1b2c3d4e5f6g7h8i9j0'}) }
|
8
|
+
let(:hostname) { 'hostname.local' }
|
9
|
+
let(:github_site) { 'https://github.com' }
|
10
|
+
let(:github_api_endpoint) { 'https://api.github.com' }
|
11
|
+
let(:enterprise_site) { 'https://github.gittyup.com' }
|
12
|
+
let(:enterprise_api) { 'https://github.gittyup.com/api/v3' }
|
13
|
+
let(:github) { stub_github_with }
|
14
|
+
let!(:github_api) { github.connection }
|
15
|
+
let(:existing_pull_request) { Fixture.new('pull_requests/external_pull_request.json').to_json_hashie }
|
16
|
+
let(:existing_pull_requests) { Fixture.new('pull_requests/pull_requests.json').to_json_hashie }
|
17
|
+
let(:existing_pull_commits) { Fixture.new('pull_requests/commits.json').to_json_hashie }
|
18
|
+
let(:comment_author) { 'octocat' }
|
19
|
+
let(:existing_pull_comments) {
|
20
|
+
Fixture.new('pull_requests/comments.json.erb',
|
21
|
+
repo_owner: user,
|
22
|
+
repo_name: repo,
|
23
|
+
comments: [{author: comment_author}],
|
24
|
+
pull_request_number: existing_pull_request.number).to_json_hashie }
|
25
|
+
let(:existing_issue_comments) {
|
26
|
+
Fixture.new('issues/comments.json.erb',
|
27
|
+
repo_owner: user,
|
28
|
+
repo_name: repo,
|
29
|
+
comments: [{author: comment_author}],
|
30
|
+
pull_request_number: existing_pull_request.number).to_json_hashie }
|
31
|
+
|
32
|
+
subject { GitReflow::GitServer::GitHub::PullRequest.new(existing_pull_request) }
|
33
|
+
|
34
|
+
|
35
|
+
before do
|
36
|
+
stub_command_line_inputs({
|
37
|
+
"Please enter your GitHub username: " => user,
|
38
|
+
"Please enter your GitHub password (we do NOT store this): " => password,
|
39
|
+
"Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
|
40
|
+
"Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api
|
41
|
+
})
|
42
|
+
|
43
|
+
github.class.stub(:remote_user).and_return(user)
|
44
|
+
github.class.stub(:remote_repo_name).and_return(repo)
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#initialize(options)' do
|
48
|
+
specify { expect(subject.number).to eql(existing_pull_request.number) }
|
49
|
+
specify { expect(subject.description).to eql(existing_pull_request.body) }
|
50
|
+
specify { expect(subject.html_url).to eql(existing_pull_request.html_url) }
|
51
|
+
specify { expect(subject.feature_branch_name).to eql(existing_pull_request.head.label) }
|
52
|
+
specify { expect(subject.base_branch_name).to eql(existing_pull_request.base.label) }
|
53
|
+
specify { expect(subject.build_status).to eql('success') }
|
54
|
+
specify { expect(subject.source_object).to eql(existing_pull_request) }
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#commit_author' do
|
58
|
+
before do
|
59
|
+
stub_request(:get, %r{#{GitReflow.git_server.class.api_endpoint}/repos/#{user}/#{repo}/pulls/#{existing_pull_request.number}/commits}).
|
60
|
+
with(query: {"access_token" => "a1b2c3d4e5f6g7h8i9j0"}).
|
61
|
+
to_return(:body => Fixture.new("pull_requests/commits.json").to_s, status: 201, headers: {content_type: "application/json; charset=utf-8"})
|
62
|
+
end
|
63
|
+
specify { expect(subject.commit_author).to eql("#{existing_pull_commits.first.commit.author.name} <#{existing_pull_commits.first.commit.author.email}>") }
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#comments' do
|
67
|
+
before do
|
68
|
+
FakeGitHub.new(
|
69
|
+
repo_owner: user,
|
70
|
+
repo_name: repo,
|
71
|
+
pull_request: {
|
72
|
+
number: existing_pull_request.number,
|
73
|
+
comments: [{author: comment_author}]
|
74
|
+
},
|
75
|
+
issue: {
|
76
|
+
number: existing_pull_request.number,
|
77
|
+
comments: [{author: comment_author}]
|
78
|
+
})
|
79
|
+
end
|
80
|
+
|
81
|
+
specify { expect(subject.comments).to eql(existing_pull_comments.to_a + existing_issue_comments.to_a) }
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#reviewers' do
|
85
|
+
before do
|
86
|
+
allow(existing_pull_request.user).to receive(:login).and_return('ringo')
|
87
|
+
|
88
|
+
FakeGitHub.new(
|
89
|
+
repo_owner: user,
|
90
|
+
repo_name: repo,
|
91
|
+
pull_request: {
|
92
|
+
number: existing_pull_request.number,
|
93
|
+
owner: existing_pull_request.user.login,
|
94
|
+
comments: [{author: 'tito'}, {author: 'bobby'}, {author: 'ringo'}]
|
95
|
+
},
|
96
|
+
issue: {
|
97
|
+
number: existing_pull_request.number,
|
98
|
+
comments: [{author: 'ringo'}, {author: 'randy'}]
|
99
|
+
})
|
100
|
+
end
|
101
|
+
|
102
|
+
specify { expect(subject.reviewers).to eql(['tito', 'bobby', 'randy']) }
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#approvals' do
|
106
|
+
context "no comments" do
|
107
|
+
before do
|
108
|
+
FakeGitHub.new(
|
109
|
+
repo_owner: user,
|
110
|
+
repo_name: repo,
|
111
|
+
pull_request: {
|
112
|
+
number: existing_pull_request.number,
|
113
|
+
owner: existing_pull_request.head.user.login,
|
114
|
+
comments: []
|
115
|
+
})
|
116
|
+
end
|
117
|
+
|
118
|
+
specify { expect(subject.approvals).to eq([]) }
|
119
|
+
end
|
120
|
+
|
121
|
+
context "single reviewer without approval" do
|
122
|
+
before do
|
123
|
+
FakeGitHub.new(
|
124
|
+
repo_owner: user,
|
125
|
+
repo_name: repo,
|
126
|
+
pull_request: {
|
127
|
+
number: existing_pull_request.number,
|
128
|
+
owner: existing_pull_request.head.user.login,
|
129
|
+
comments: [{author: 'tito', body: 'This is some funky stuff'}]
|
130
|
+
})
|
131
|
+
end
|
132
|
+
|
133
|
+
specify { expect(subject.approvals).to eq([]) }
|
134
|
+
end
|
135
|
+
|
136
|
+
context "single reviewer with approval" do
|
137
|
+
before do
|
138
|
+
FakeGitHub.new(
|
139
|
+
repo_owner: user,
|
140
|
+
repo_name: repo,
|
141
|
+
pull_request: {
|
142
|
+
number: existing_pull_request.number,
|
143
|
+
owner: existing_pull_request.head.user.login,
|
144
|
+
comments: [{author: 'tito', body: 'LGTM'}]
|
145
|
+
})
|
146
|
+
end
|
147
|
+
|
148
|
+
specify { expect(subject.approvals).to eq(['tito']) }
|
149
|
+
|
150
|
+
context "but a new commit has been introduced" do
|
151
|
+
before do
|
152
|
+
FakeGitHub.new(
|
153
|
+
repo_owner: user,
|
154
|
+
repo_name: repo,
|
155
|
+
commits: [
|
156
|
+
{
|
157
|
+
author: user,
|
158
|
+
pull_request_number: existing_pull_request.number,
|
159
|
+
created_at: Chronic.parse("1 second ago")
|
160
|
+
}
|
161
|
+
],
|
162
|
+
pull_request: {
|
163
|
+
number: existing_pull_request.number,
|
164
|
+
owner: existing_pull_request.head.user.login,
|
165
|
+
comments: [{author: 'tito', body: 'LGTM', created_at: Chronic.parse('1 minute ago')}]
|
166
|
+
})
|
167
|
+
end
|
168
|
+
|
169
|
+
specify { expect(subject.approvals).to eq([]) }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "multiple reviewers with only one approval" do
|
174
|
+
before do
|
175
|
+
FakeGitHub.new(
|
176
|
+
repo_owner: user,
|
177
|
+
repo_name: repo,
|
178
|
+
pull_request: {
|
179
|
+
number: existing_pull_request.number,
|
180
|
+
owner: existing_pull_request.head.user.login,
|
181
|
+
comments: [{author: 'tito', body: 'LGTM'}, {author: 'ringo', body: 'Needs more cowbell.'}]
|
182
|
+
})
|
183
|
+
end
|
184
|
+
|
185
|
+
specify { expect(subject.approvals).to eq(['tito']) }
|
186
|
+
end
|
187
|
+
|
188
|
+
context "multiple reviewers with all approvals" do
|
189
|
+
before do
|
190
|
+
FakeGitHub.new(
|
191
|
+
repo_owner: user,
|
192
|
+
repo_name: repo,
|
193
|
+
pull_request: {
|
194
|
+
number: existing_pull_request.number,
|
195
|
+
owner: existing_pull_request.head.user.login,
|
196
|
+
comments: [{author: 'tito', body: 'lgtm'}, {author: 'ringo', body: ':+1:'}]
|
197
|
+
})
|
198
|
+
end
|
199
|
+
|
200
|
+
specify { expect(subject.approvals).to eq(['tito', 'ringo']) }
|
201
|
+
|
202
|
+
context "but a new commit has been introduced" do
|
203
|
+
before do
|
204
|
+
FakeGitHub.new(
|
205
|
+
repo_owner: user,
|
206
|
+
repo_name: repo,
|
207
|
+
commits: [
|
208
|
+
{
|
209
|
+
author: user,
|
210
|
+
pull_request_number: existing_pull_request.number,
|
211
|
+
created_at: Chronic.parse("1 second ago")
|
212
|
+
}
|
213
|
+
],
|
214
|
+
pull_request: {
|
215
|
+
number: existing_pull_request.number,
|
216
|
+
owner: existing_pull_request.head.user.login,
|
217
|
+
comments: [{author: 'tito', body: 'lgtm', created_at: Chronic.parse('1 minute ago')}, {author: 'ringo', body: ':+1:', created_at: Chronic.parse('1 minute ago')}]
|
218
|
+
})
|
219
|
+
end
|
220
|
+
|
221
|
+
specify { expect(subject.approvals).to eq([]) }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
describe '#last_comment' do
|
228
|
+
before do
|
229
|
+
FakeGitHub.new(
|
230
|
+
repo_owner: user,
|
231
|
+
repo_name: repo,
|
232
|
+
pull_request: {
|
233
|
+
number: existing_pull_request.number,
|
234
|
+
owner: existing_pull_request.head.user.login,
|
235
|
+
comments: [{author: 'tito', body: 'lgtm'}, {author: 'ringo', body: 'Cha cha cha'}]
|
236
|
+
})
|
237
|
+
end
|
238
|
+
|
239
|
+
specify { expect(subject.last_comment).to eq('"Cha cha cha"') }
|
240
|
+
end
|
241
|
+
|
242
|
+
describe '#build' do
|
243
|
+
let(:build) { Fixture.new('repositories/statuses.json').to_json_hashie.first }
|
244
|
+
|
245
|
+
context "with an existing build" do
|
246
|
+
specify { expect(subject.build.state).to eq(build.state) }
|
247
|
+
specify { expect(subject.build.description).to eq(build.description) }
|
248
|
+
specify { expect(subject.build.url).to eq(build.target_url) }
|
249
|
+
end
|
250
|
+
|
251
|
+
context "no build found" do
|
252
|
+
before { allow(GitReflow.git_server).to receive(:get_build_status).and_return(nil) }
|
253
|
+
specify { expect(subject.build.state).to eq(nil) }
|
254
|
+
specify { expect(subject.build.description).to eq(nil) }
|
255
|
+
specify { expect(subject.build.url).to eq(nil) }
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
describe '.create(options)' do
|
261
|
+
let(:title) { 'Bone Saw is ready!' }
|
262
|
+
let(:body) { 'Snap into a Slim Jim!' }
|
263
|
+
let(:base_branch_name) { 'base-branch' }
|
264
|
+
let(:pull_request_response) do
|
265
|
+
Fixture.new('pull_requests/pull_request.json.erb',
|
266
|
+
number: 2,
|
267
|
+
title: title,
|
268
|
+
body: body,
|
269
|
+
base_branch: base_branch_name,
|
270
|
+
repo_owner: user,
|
271
|
+
repo_name: repo)
|
272
|
+
end
|
273
|
+
|
274
|
+
subject { GitReflow::GitServer::GitHub::PullRequest.create(title: title, body: body, base: base_branch_name) }
|
275
|
+
|
276
|
+
before do
|
277
|
+
stub_request(:post, %r{/repos/#{user}/#{repo}/pulls}).
|
278
|
+
to_return(body: pull_request_response.to_s, status: 201, headers: {content_type: "application/json; charset=utf-8"})
|
279
|
+
end
|
280
|
+
|
281
|
+
specify { expect(subject.class.to_s).to eql('GitReflow::GitServer::GitHub::PullRequest') }
|
282
|
+
specify { expect(subject.title).to eql(title) }
|
283
|
+
specify { expect(subject.description).to eql(body) }
|
284
|
+
specify { expect(subject.base_branch_name).to eql(base_branch_name) }
|
285
|
+
end
|
286
|
+
|
287
|
+
describe '.find_open(options)' do
|
288
|
+
let(:feature_branch) { 'new-feature' }
|
289
|
+
let(:base_branch) { 'base-branch' }
|
290
|
+
|
291
|
+
subject { GitReflow::GitServer::GitHub::PullRequest.find_open(from: feature_branch, to: base_branch) }
|
292
|
+
|
293
|
+
before do
|
294
|
+
allow(GitReflow.git_server.class).to receive(:current_branch).and_return(feature_branch)
|
295
|
+
FakeGitHub.new(
|
296
|
+
repo_owner: user,
|
297
|
+
repo_name: repo,
|
298
|
+
pull_request: {
|
299
|
+
number: existing_pull_request.number,
|
300
|
+
owner: existing_pull_request.head.user.login,
|
301
|
+
base_branch: base_branch,
|
302
|
+
feature_branch: feature_branch
|
303
|
+
})
|
304
|
+
end
|
305
|
+
|
306
|
+
specify { expect(subject.class.to_s).to eql('GitReflow::GitServer::GitHub::PullRequest') }
|
307
|
+
specify { expect(subject.number).to eql(existing_pull_request.number) }
|
308
|
+
|
309
|
+
context "without any options" do
|
310
|
+
let(:base_branch) { 'master' }
|
311
|
+
subject { GitReflow::GitServer::GitHub::PullRequest.find_open() }
|
312
|
+
it "defaults to the current branch as the feature branch and 'master' as the base branch" do
|
313
|
+
expect(subject.class.to_s).to eql('GitReflow::GitServer::GitHub::PullRequest')
|
314
|
+
expect(subject.number).to eql(existing_pull_request.number)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|