octopolo 0.3.6 → 0.4.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 +8 -8
- data/.travis.yml +4 -0
- data/CHANGELOG.markdown +5 -0
- data/lib/octopolo/commands/issue.rb +14 -0
- data/lib/octopolo/github.rb +9 -2
- data/lib/octopolo/github/issue.rb +106 -0
- data/lib/octopolo/github/issue_creator.rb +147 -0
- data/lib/octopolo/github/pull_request.rb +10 -81
- data/lib/octopolo/github/pull_request_creator.rb +12 -97
- data/lib/octopolo/renderer.rb +1 -0
- data/lib/octopolo/scripts/issue.rb +140 -0
- data/lib/octopolo/scripts/pull_request.rb +5 -71
- data/lib/octopolo/templates/issue_body.erb +22 -0
- data/lib/octopolo/version.rb +1 -1
- data/spec/octopolo/github/issue_creator_spec.rb +217 -0
- data/spec/octopolo/github/issue_spec.rb +243 -0
- data/spec/octopolo/github/pull_request_creator_spec.rb +11 -11
- data/spec/octopolo/github/pull_request_spec.rb +16 -16
- data/spec/octopolo/github_spec.rb +15 -0
- data/spec/octopolo/scripts/issue_spec.rb +233 -0
- data/spec/octopolo/scripts/pull_request_spec.rb +3 -3
- metadata +13 -2
@@ -0,0 +1,243 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "../../../lib/octopolo/github/issue"
|
3
|
+
require_relative "../../../lib/octopolo/github/issue_creator"
|
4
|
+
|
5
|
+
module Octopolo
|
6
|
+
module GitHub
|
7
|
+
describe Issue do
|
8
|
+
let(:repo_name) { "account/repo" }
|
9
|
+
let(:issue_number) { 7 }
|
10
|
+
let(:issue_hash) { stub }
|
11
|
+
let(:comments) { stub }
|
12
|
+
let(:octo) { stub }
|
13
|
+
|
14
|
+
context ".new" do
|
15
|
+
it "remembers the issue identifiers" do
|
16
|
+
i = Issue.new repo_name, issue_number
|
17
|
+
i.repo_name.should == repo_name
|
18
|
+
i.number.should == issue_number
|
19
|
+
end
|
20
|
+
|
21
|
+
it "optionally accepts the github data" do
|
22
|
+
i = Issue.new repo_name, issue_number, octo
|
23
|
+
i.data.should == octo
|
24
|
+
end
|
25
|
+
|
26
|
+
it "fails if not given a repo name" do
|
27
|
+
expect { Issue.new nil, issue_number }.to raise_error(Issue::MissingParameter)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "fails if not given a issue number" do
|
31
|
+
expect { Issue.new repo_name, nil }.to raise_error(Issue::MissingParameter)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "#data" do
|
36
|
+
let(:issue) { Issue.new repo_name, issue_number }
|
37
|
+
|
38
|
+
it "fetches the details from GitHub" do
|
39
|
+
GitHub.should_receive(:issue).with(issue.repo_name, issue.number) { octo }
|
40
|
+
issue.data.should == octo
|
41
|
+
end
|
42
|
+
|
43
|
+
it "catches the information" do
|
44
|
+
GitHub.should_receive(:issue).once { octo }
|
45
|
+
issue.data
|
46
|
+
issue.data
|
47
|
+
end
|
48
|
+
|
49
|
+
it "fails if given invalid information" do
|
50
|
+
GitHub.should_receive(:issue).and_raise(Octokit::NotFound)
|
51
|
+
expect { issue.data }.to raise_error(Issue::NotFound)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "fetching its attributes from Octokit" do
|
56
|
+
let(:issue) { Issue.new repo_name, issue_number }
|
57
|
+
|
58
|
+
before do
|
59
|
+
issue.stub(data: octo)
|
60
|
+
end
|
61
|
+
|
62
|
+
context "#title" do
|
63
|
+
let(:octo) { stub(title: "the title") }
|
64
|
+
|
65
|
+
it "retrieves from the github data" do
|
66
|
+
issue.title.should == octo.title
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "#comments" do
|
71
|
+
it "fetches through octokit" do
|
72
|
+
GitHub.should_receive(:issue_comments).with(issue.repo_name, issue.number) { comments }
|
73
|
+
issue.comments.should == comments
|
74
|
+
end
|
75
|
+
|
76
|
+
it "caches the result" do
|
77
|
+
GitHub.should_receive(:issue_comments).once { comments }
|
78
|
+
issue.comments
|
79
|
+
issue.comments
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "#commenter_names" do
|
84
|
+
let(:comment1) { stub(user: stub(login: "pbyrne")) }
|
85
|
+
let(:comment2) { stub(user: stub(login: "anfleene")) }
|
86
|
+
|
87
|
+
before do
|
88
|
+
issue.stub(comments: [comment1, comment2])
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns only unique values" do
|
92
|
+
# make it same commenter
|
93
|
+
comment2.user.stub(login: comment1.user.login)
|
94
|
+
names = issue.commenter_names
|
95
|
+
names.size.should == 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "#without_octopolo_users" do
|
100
|
+
let(:users) { ["anfleene", "tst-octopolo"] }
|
101
|
+
|
102
|
+
it "excludes the github octopolo users" do
|
103
|
+
issue.exclude_octopolo_user(users).should_not include("tst-octopolo")
|
104
|
+
issue.exclude_octopolo_user(users).should include("anfleene")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "#url" do
|
109
|
+
let(:octo) { stub(html_url: "http://example.com") }
|
110
|
+
|
111
|
+
it "retrieves from the github data" do
|
112
|
+
issue.url.should == octo.html_url
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "#external_urls" do
|
117
|
+
# nicked from https://github.com/tstmedia/ngin/issue/1151
|
118
|
+
let(:body) do
|
119
|
+
<<-END
|
120
|
+
http://thedesk.tstmedia.com/admin.php?pg=request&reqid=44690 - verified
|
121
|
+
http://thedesk.tstmedia.com/admin.php?pg=request&reqid=44693 - verified
|
122
|
+
|
123
|
+
development_ftp_server: ftp.tstmedia.com
|
124
|
+
development_username: startribuneftptest@ftp.tstmedia.com
|
125
|
+
development_password: JUm1kU7STYt0
|
126
|
+
http://www.ngin.com.stage.ngin-staging.com/api/volleyball/stats/summaries?id=68382&gender=girls&tst_test=1&date=8/24/2012
|
127
|
+
END
|
128
|
+
end
|
129
|
+
|
130
|
+
before do
|
131
|
+
issue.stub(body: body)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "parses from the body" do
|
135
|
+
urls = issue.external_urls
|
136
|
+
urls.size.should == 3
|
137
|
+
urls.should include "http://thedesk.tstmedia.com/admin.php?pg=request&reqid=44690"
|
138
|
+
urls.should include "http://thedesk.tstmedia.com/admin.php?pg=request&reqid=44693"
|
139
|
+
urls.should include "http://www.ngin.com.stage.ngin-staging.com/api/volleyball/stats/summaries?id=68382&gender=girls&tst_test=1&date=8/24/2012"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "#body" do
|
144
|
+
let(:octo) { stub(body: "asdf") }
|
145
|
+
|
146
|
+
it "retrieves from the github data" do
|
147
|
+
issue.body.should == octo.body
|
148
|
+
end
|
149
|
+
|
150
|
+
it "returns an empty string if the GitHub data has no body" do
|
151
|
+
octo.stub(body: nil)
|
152
|
+
issue.body.should == ""
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "#human_app_name" do
|
158
|
+
let(:repo_name) { "account_name/repo_name" }
|
159
|
+
let(:issue) { Issue.new repo_name, issue_number }
|
160
|
+
|
161
|
+
it "infers from the repo_name" do
|
162
|
+
issue.repo_name = "account/foo"
|
163
|
+
issue.human_app_name.should == "Foo"
|
164
|
+
issue.repo_name = "account/foo_bar"
|
165
|
+
issue.human_app_name.should == "Foo Bar"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "#write_comment(message)" do
|
170
|
+
let(:issue) { Issue.new repo_name, issue_number }
|
171
|
+
let(:message) { "Test message" }
|
172
|
+
let(:error) { Octokit::UnprocessableEntity.new }
|
173
|
+
|
174
|
+
it "creates the message through octokit" do
|
175
|
+
GitHub.should_receive(:add_comment).with(issue.repo_name, issue.number, ":octocat: #{message}")
|
176
|
+
|
177
|
+
issue.write_comment message
|
178
|
+
end
|
179
|
+
|
180
|
+
it "raises CommentFailed if an exception occurs" do
|
181
|
+
GitHub.should_receive(:add_comment).and_raise(error)
|
182
|
+
|
183
|
+
expect { issue.write_comment message }.to raise_error(Issue::CommentFailed, "Unable to write the comment: '#{error.message}'")
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context ".create repo_name, options" do
|
188
|
+
let(:options) { stub(:hash) }
|
189
|
+
let(:number) { stub(:integer) }
|
190
|
+
let(:data) { stub(:data)}
|
191
|
+
let(:creator) { stub(:issue_creator, number: number, data: data)}
|
192
|
+
let(:issue) { stub(:issue) }
|
193
|
+
|
194
|
+
it "passes on to IssueCreator and returns a new Issue" do
|
195
|
+
IssueCreator.should_receive(:perform).with(repo_name, options) { creator }
|
196
|
+
Issue.should_receive(:new).with(repo_name, number, data) { issue }
|
197
|
+
Issue.create(repo_name, options).should == issue
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context "labeling" do
|
202
|
+
let(:label1) { Label.new(name: "low-risk", color: "343434") }
|
203
|
+
let(:label2) { Label.new(name: "high-risk", color: '565656') }
|
204
|
+
let(:issue) { Issue.new repo_name, issue_number }
|
205
|
+
|
206
|
+
context "#add_labels" do
|
207
|
+
it "sends the correct arguments to add_labels_to_issue for multiple labels" do
|
208
|
+
allow(Label).to receive(:build_label_array) {[label1,label2]}
|
209
|
+
expect(GitHub).to receive(:add_labels_to_issue).with(repo_name, issue_number, ["low-risk","high-risk"])
|
210
|
+
issue.add_labels([label1, label2])
|
211
|
+
end
|
212
|
+
|
213
|
+
it "sends the correct arguments to add_labels_to_issue for a single label" do
|
214
|
+
allow(Label).to receive(:build_label_array) {[label1]}
|
215
|
+
expect(GitHub).to receive(:add_labels_to_issue).with(repo_name, issue_number, ["low-risk"])
|
216
|
+
issue.add_labels(label1)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context "#remove_from_issue" do
|
221
|
+
|
222
|
+
it "sends the correct arguments to remove_label" do
|
223
|
+
allow(Label).to receive(:build_label_array) {[label1]}
|
224
|
+
expect(GitHub).to receive(:remove_label).with(repo_name, issue_number, "low-risk")
|
225
|
+
issue.remove_labels(label1)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "calls remove_label only once" do
|
229
|
+
allow(Label).to receive(:build_label_array) {[label1]}
|
230
|
+
expect(GitHub).to receive(:remove_label).once
|
231
|
+
issue.remove_labels(label1)
|
232
|
+
end
|
233
|
+
|
234
|
+
it "calls remove_label twice" do
|
235
|
+
allow(Label).to receive(:build_label_array) {[label1, label2]}
|
236
|
+
expect(GitHub).to receive(:remove_label).twice
|
237
|
+
issue.remove_labels([label1,label2])
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -34,7 +34,7 @@ module Octopolo
|
|
34
34
|
end
|
35
35
|
|
36
36
|
context "#perform" do
|
37
|
-
let(:
|
37
|
+
let(:data) { stub(:mash, number: 123) }
|
38
38
|
|
39
39
|
before do
|
40
40
|
creator.stub({
|
@@ -46,10 +46,10 @@ module Octopolo
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "generates the pull request with the given details and retains the information" do
|
49
|
-
GitHub.should_receive(:create_pull_request).with(repo_name, destination_branch, source_branch, title, body) {
|
50
|
-
creator.perform.should ==
|
51
|
-
creator.number.should ==
|
52
|
-
creator.
|
49
|
+
GitHub.should_receive(:create_pull_request).with(repo_name, destination_branch, source_branch, title, body) { data }
|
50
|
+
creator.perform.should == data
|
51
|
+
creator.number.should == data.number
|
52
|
+
creator.data.should == data
|
53
53
|
end
|
54
54
|
|
55
55
|
it "raises CannotCreate if any exception occurs" do
|
@@ -72,17 +72,17 @@ module Octopolo
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
context "#
|
76
|
-
let(:details) { stub(:
|
75
|
+
context "#data" do
|
76
|
+
let(:details) { stub(:data) }
|
77
77
|
|
78
78
|
it "returns the stored pull request details" do
|
79
|
-
creator.
|
80
|
-
creator.
|
79
|
+
creator.data = details
|
80
|
+
creator.data.should == details
|
81
81
|
end
|
82
82
|
|
83
83
|
it "raises an exception if no information has been captured yet" do
|
84
|
-
creator.
|
85
|
-
expect { creator.
|
84
|
+
creator.data = nil
|
85
|
+
expect { creator.data }.to raise_error(PullRequestCreator::NotYetCreated)
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -20,7 +20,7 @@ module Octopolo
|
|
20
20
|
|
21
21
|
it "optionally accepts the github data" do
|
22
22
|
pr = PullRequest.new repo_name, pr_number, octo
|
23
|
-
pr.
|
23
|
+
pr.data.should == octo
|
24
24
|
end
|
25
25
|
|
26
26
|
it "fails if not given a repo name" do
|
@@ -32,23 +32,23 @@ module Octopolo
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
context "#
|
35
|
+
context "#data" do
|
36
36
|
let(:pull) { PullRequest.new repo_name, pr_number }
|
37
37
|
|
38
38
|
it "fetches the details from GitHub" do
|
39
39
|
GitHub.should_receive(:pull_request).with(pull.repo_name, pull.number) { octo }
|
40
|
-
pull.
|
40
|
+
pull.data.should == octo
|
41
41
|
end
|
42
42
|
|
43
43
|
it "catches the information" do
|
44
44
|
GitHub.should_receive(:pull_request).once { octo }
|
45
|
-
pull.
|
46
|
-
pull.
|
45
|
+
pull.data
|
46
|
+
pull.data
|
47
47
|
end
|
48
48
|
|
49
49
|
it "fails if given invalid information" do
|
50
50
|
GitHub.should_receive(:pull_request).and_raise(Octokit::NotFound)
|
51
|
-
expect { pull.
|
51
|
+
expect { pull.data }.to raise_error(PullRequest::NotFound)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -56,7 +56,7 @@ module Octopolo
|
|
56
56
|
let(:pull) { PullRequest.new repo_name, pr_number }
|
57
57
|
|
58
58
|
before do
|
59
|
-
pull.stub(
|
59
|
+
pull.stub(data: octo)
|
60
60
|
end
|
61
61
|
|
62
62
|
context "#title" do
|
@@ -130,11 +130,11 @@ module Octopolo
|
|
130
130
|
|
131
131
|
before do
|
132
132
|
pull.stub(comments: [comment1, comment2], author_names: [])
|
133
|
+
GitHub::User.stub(:new).with("pbyrne").and_return(stub(:author_name => "pbyrne"))
|
134
|
+
GitHub::User.stub(:new).with("anfleene").and_return(stub(:author_name => "anfleene"))
|
133
135
|
end
|
134
136
|
|
135
137
|
it "returns the names of the commit authors" do
|
136
|
-
GitHub.stub(:user).with("pbyrne").and_return(Hashie::Mash.new(:name => "pbyrne"))
|
137
|
-
GitHub.stub(:user).with("anfleene").and_return(Hashie::Mash.new(:name => "anfleene"))
|
138
138
|
names = pull.commenter_names
|
139
139
|
names.should_not be_empty
|
140
140
|
names.size.should == 2
|
@@ -160,8 +160,8 @@ module Octopolo
|
|
160
160
|
let(:users) { ["anfleene", "tst-octopolo"] }
|
161
161
|
|
162
162
|
it "excludes the github octopolo users" do
|
163
|
-
pull.
|
164
|
-
pull.
|
163
|
+
pull.exclude_octopolo_user(users).should_not include("tst-octopolo")
|
164
|
+
pull.exclude_octopolo_user(users).should include("anfleene")
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
@@ -276,13 +276,13 @@ module Octopolo
|
|
276
276
|
context ".create repo_name, options" do
|
277
277
|
let(:options) { stub(:hash) }
|
278
278
|
let(:number) { stub(:integer) }
|
279
|
-
let(:
|
280
|
-
let(:creator) { stub(:pull_request_creator, number: number,
|
279
|
+
let(:data) { stub(:data)}
|
280
|
+
let(:creator) { stub(:pull_request_creator, number: number, data: data)}
|
281
281
|
let(:pull_request) { stub(:pull_request) }
|
282
282
|
|
283
283
|
it "passes on to PullRequestCreator and returns a new PullRequest" do
|
284
284
|
PullRequestCreator.should_receive(:perform).with(repo_name, options) { creator }
|
285
|
-
PullRequest.should_receive(:new).with(repo_name, number,
|
285
|
+
PullRequest.should_receive(:new).with(repo_name, number, data) { pull_request }
|
286
286
|
PullRequest.create(repo_name, options).should == pull_request
|
287
287
|
end
|
288
288
|
end
|
@@ -295,13 +295,13 @@ module Octopolo
|
|
295
295
|
context "#add_labels" do
|
296
296
|
it "sends the correct arguments to add_labels_to_pull for multiple labels" do
|
297
297
|
allow(Label).to receive(:build_label_array) {[label1,label2]}
|
298
|
-
expect(GitHub).to receive(:
|
298
|
+
expect(GitHub).to receive(:add_labels_to_issue).with(repo_name, pr_number, ["low-risk","high-risk"])
|
299
299
|
pull_request.add_labels([label1, label2])
|
300
300
|
end
|
301
301
|
|
302
302
|
it "sends the correct arguments to add_labels_to_pull for a single label" do
|
303
303
|
allow(Label).to receive(:build_label_array) {[label1]}
|
304
|
-
expect(GitHub).to receive(:
|
304
|
+
expect(GitHub).to receive(:add_labels_to_issue).with(repo_name, pr_number, ["low-risk"])
|
305
305
|
pull_request.add_labels(label1)
|
306
306
|
end
|
307
307
|
end
|
@@ -54,6 +54,14 @@ module Octopolo
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
context ".issue *args" do
|
58
|
+
it "sends onto the client wrapper" do
|
59
|
+
client.should_receive(:issue).with("a", "b") { data }
|
60
|
+
result = GitHub.issue("a", "b")
|
61
|
+
result.should == data
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
57
65
|
context ".pull_request_commits *args" do
|
58
66
|
it "sends onto the client wrapper" do
|
59
67
|
client.should_receive(:pull_request_commits).with("a", "b") { data }
|
@@ -96,6 +104,13 @@ module Octopolo
|
|
96
104
|
end
|
97
105
|
end
|
98
106
|
|
107
|
+
context ".create_issue" do
|
108
|
+
it "sends the issue to the API" do
|
109
|
+
client.should_receive(:create_issue).with("repo", "title", "body") { data }
|
110
|
+
GitHub.create_issue("repo", "title", "body").should == data
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
99
114
|
context ".add_comment" do
|
100
115
|
it "sends the comment to the API" do
|
101
116
|
client.should_receive(:add_comment).with("repo", 123, "contents of comment")
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "../../../lib/octopolo/scripts/issue"
|
3
|
+
require_relative "../../../lib/octopolo/github/issue"
|
4
|
+
|
5
|
+
module Octopolo
|
6
|
+
module Scripts
|
7
|
+
describe Issue do
|
8
|
+
let(:config) do
|
9
|
+
stub(:config, {
|
10
|
+
deploy_branch: "production",
|
11
|
+
github_repo: "tstmedia/foo",
|
12
|
+
use_pivotal_tracker: true,
|
13
|
+
use_jira: true
|
14
|
+
})
|
15
|
+
end
|
16
|
+
let(:cli) { stub(:cli) }
|
17
|
+
let(:git) { stub(:Git) }
|
18
|
+
let(:issue_url) { "http://github.com/tstmedia/octopolo/issues/0" }
|
19
|
+
let(:issue) { stub(:issue) }
|
20
|
+
|
21
|
+
subject { Issue.new }
|
22
|
+
|
23
|
+
before do
|
24
|
+
Issue.any_instance.stub({
|
25
|
+
:cli => cli,
|
26
|
+
:config => config,
|
27
|
+
:git => git
|
28
|
+
})
|
29
|
+
end
|
30
|
+
|
31
|
+
context "#new" do
|
32
|
+
it "accepts options" do
|
33
|
+
expect(Issue.new(:foo => 'bar').options).to eq(:foo => 'bar')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "#execute" do
|
38
|
+
it "if connected to GitHub, asks some questions, creates the issue, and opens it" do
|
39
|
+
GitHub.should_receive(:connect).and_yield
|
40
|
+
expect(subject).to receive(:ask_questionaire)
|
41
|
+
expect(subject).to receive(:create_issue)
|
42
|
+
expect(subject).to receive(:update_pivotal)
|
43
|
+
expect(subject).to receive(:update_jira)
|
44
|
+
expect(subject).to receive(:update_label)
|
45
|
+
expect(subject).to receive(:open_in_browser)
|
46
|
+
|
47
|
+
subject.execute
|
48
|
+
end
|
49
|
+
|
50
|
+
it "if not connected to GitHub, does nothing" do
|
51
|
+
GitHub.should_receive(:connect) # and not yield, no github credentials
|
52
|
+
expect { subject.execute }.to_not raise_error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "#ask_questionaire" do
|
57
|
+
it "asks appropriate questions to create a issue" do
|
58
|
+
expect(subject).to receive(:announce)
|
59
|
+
expect(subject).to receive(:ask_title)
|
60
|
+
expect(subject).to receive(:ask_pivotal_ids)
|
61
|
+
expect(subject).to receive(:ask_jira_ids)
|
62
|
+
expect(subject).to receive(:ask_label)
|
63
|
+
|
64
|
+
subject.send(:ask_questionaire)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "#announce" do
|
69
|
+
it "displays information about the issue to be created" do
|
70
|
+
cli.should_receive(:say).with("Preparing an issue for #{config.github_repo}.")
|
71
|
+
subject.send(:announce)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "#ask_title" do
|
76
|
+
let(:title) { "title" }
|
77
|
+
|
78
|
+
it "asks for and captures a title for the issue" do
|
79
|
+
cli.should_receive(:prompt).with("Title:") { title }
|
80
|
+
subject.send(:ask_title)
|
81
|
+
expect(subject.title).to eq(title)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "#ask_label" do
|
86
|
+
let(:label1) {Octopolo::GitHub::Label.new(name: "low-risk", color: '151515')}
|
87
|
+
let(:label2) {Octopolo::GitHub::Label.new(name: "high-risk", color: '151515')}
|
88
|
+
let(:choices) {["low-risk","high-risk","None"]}
|
89
|
+
|
90
|
+
it "asks for and capture a label" do
|
91
|
+
allow(Octopolo::GitHub::Label).to receive(:all) {[label1,label2]}
|
92
|
+
expect(cli).to receive(:ask).with("Label:", choices)
|
93
|
+
subject.send(:ask_label)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "asks for a label" do
|
97
|
+
allow(Octopolo::GitHub::Label).to receive(:all) {[label1,label2]}
|
98
|
+
allow(Octopolo::GitHub::Label).to receive(:get_names) {choices}
|
99
|
+
allow(cli).to receive(:ask) {"low-risk"}
|
100
|
+
expect(subject.send(:ask_label)).to eq(label1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "#ask_pivotal_ids" do
|
105
|
+
let(:ids_with_whitespace) { "123 456" }
|
106
|
+
let(:ids_with_commas) { "234, 567" }
|
107
|
+
|
108
|
+
it "asks for and captures IDs for related pivotal tasks" do
|
109
|
+
cli.should_receive(:prompt).with("Pivotal Tracker story ID(s):") { ids_with_whitespace }
|
110
|
+
subject.send(:ask_pivotal_ids)
|
111
|
+
expect(subject.pivotal_ids).to eq(%w(123 456))
|
112
|
+
end
|
113
|
+
|
114
|
+
it "asks for and captures IDs with commas" do
|
115
|
+
cli.should_receive(:prompt).with("Pivotal Tracker story ID(s):") { ids_with_commas }
|
116
|
+
subject.send(:ask_pivotal_ids)
|
117
|
+
expect(subject.pivotal_ids).to eq(%w(234 567))
|
118
|
+
end
|
119
|
+
|
120
|
+
it "sets to an empty array if not provided an ansswer" do
|
121
|
+
cli.should_receive(:prompt).with("Pivotal Tracker story ID(s):") { "" }
|
122
|
+
subject.send(:ask_pivotal_ids)
|
123
|
+
expect(subject.pivotal_ids).to eq([])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "#create_issue" do
|
128
|
+
let(:attributes) { stub(:hash) }
|
129
|
+
|
130
|
+
before do
|
131
|
+
subject.stub(:issue_attributes) { attributes }
|
132
|
+
end
|
133
|
+
|
134
|
+
it "creates and stores the issue" do
|
135
|
+
GitHub::Issue.should_receive(:create).with(config.github_repo, attributes) { issue }
|
136
|
+
subject.send(:create_issue)
|
137
|
+
expect(subject.issue).to eq(issue)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "#issue_attributes" do
|
142
|
+
before do
|
143
|
+
subject.title = "title"
|
144
|
+
subject.pivotal_ids = %w(123)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "combines the anssers with a handful of deault values" do
|
148
|
+
subject.send(:issue_attributes).should == {
|
149
|
+
title: subject.title,
|
150
|
+
pivotal_ids: subject.pivotal_ids,
|
151
|
+
jira_ids: subject.jira_ids,
|
152
|
+
editor: nil
|
153
|
+
}
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "#label_choices" do
|
158
|
+
let(:label1) { Octopolo::GitHub::Label.new(name: "low-risk", color: '151515') }
|
159
|
+
let(:label2) { Octopolo::GitHub::Label.new(name: "high-risk", color: '151515') }
|
160
|
+
let(:github_labels) { [label1, label2] }
|
161
|
+
|
162
|
+
it "returns the labels plus 'None'" do
|
163
|
+
allow(Octopolo::GitHub::Label).to receive(:all) { github_labels }
|
164
|
+
expect(subject.send(:label_choices)).to eq github_labels
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "#update_pivotal" do
|
169
|
+
before do
|
170
|
+
subject.pivotal_ids = %w(123 234)
|
171
|
+
subject.issue = stub(url: "test")
|
172
|
+
end
|
173
|
+
let(:story_commenter) { stub(perform: true) }
|
174
|
+
|
175
|
+
it "creates a story commenter for each pivotal_id" do
|
176
|
+
Pivotal::StoryCommenter.should_receive(:new).with("123", "test") { story_commenter }
|
177
|
+
Pivotal::StoryCommenter.should_receive(:new).with("234", "test") { story_commenter }
|
178
|
+
subject.send(:update_pivotal)
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
context "#update_jira" do
|
184
|
+
before do
|
185
|
+
subject.jira_ids = %w(123 234)
|
186
|
+
subject.issue = stub(url: "test")
|
187
|
+
end
|
188
|
+
let(:story_commenter) { stub(perform: true) }
|
189
|
+
|
190
|
+
it "creates a story commenter for each pivotal_id" do
|
191
|
+
Jira::StoryCommenter.should_receive(:new).with("123", "test") { story_commenter }
|
192
|
+
Jira::StoryCommenter.should_receive(:new).with("234", "test") { story_commenter }
|
193
|
+
subject.send(:update_jira)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "#update_label" do
|
198
|
+
before do
|
199
|
+
subject.label = "high-risk"
|
200
|
+
subject.issue = stub()
|
201
|
+
end
|
202
|
+
it "calls update_label with proper arguments" do
|
203
|
+
expect(subject.issue).to receive(:add_labels).with('high-risk')
|
204
|
+
subject.send(:update_label)
|
205
|
+
end
|
206
|
+
|
207
|
+
context "doesn't know yet label" do
|
208
|
+
before do
|
209
|
+
subject.label = nil
|
210
|
+
end
|
211
|
+
it "doesn't call update_label when label is don't know yet" do
|
212
|
+
expect(subject.issue).to_not receive(:add_labels)
|
213
|
+
subject.send(:update_label)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
context "#open_in_browser" do
|
220
|
+
before do
|
221
|
+
subject.issue = issue
|
222
|
+
issue.stub(:url) { issue_url }
|
223
|
+
end
|
224
|
+
|
225
|
+
it "copies the issue's URL to the clipboard and opens it in the browser" do
|
226
|
+
cli.should_receive(:copy_to_clipboard) { issue.url}
|
227
|
+
cli.should_receive(:open) { issue.url }
|
228
|
+
subject.send(:open_in_browser)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|