hustle_and_flow 0.0.1 → 0.0.2
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/bin/hustle +5 -0
- data/lib/hustle_and_flow/binary/runner.rb +35 -0
- data/lib/hustle_and_flow/commands/start.rb +36 -0
- data/lib/hustle_and_flow/errors/unknown_issue_action_error.rb +6 -0
- data/lib/hustle_and_flow/formatters/branch_table_formatter.rb +81 -0
- data/lib/hustle_and_flow/formatters/issue_detail_formatter.rb +74 -0
- data/lib/hustle_and_flow/formatters/issue_table_formatter.rb +80 -0
- data/lib/hustle_and_flow/io/shell.rb +102 -0
- data/lib/hustle_and_flow/issue_tracker.rb +18 -0
- data/lib/hustle_and_flow/issue_trackers/github/issue.rb +192 -0
- data/lib/hustle_and_flow/issue_trackers/github/issues.rb +89 -0
- data/lib/hustle_and_flow/issue_trackers/github.rb +71 -0
- data/lib/hustle_and_flow/utils/string.rb +25 -0
- data/lib/hustle_and_flow/utils/url_slug.rb +28 -0
- data/lib/hustle_and_flow/vcs_repository.rb +19 -0
- data/lib/hustle_and_flow/version.rb +1 -1
- data/lib/hustle_and_flow/version_control/git/branch.rb +136 -0
- data/lib/hustle_and_flow/version_control/git/branches.rb +93 -0
- data/lib/hustle_and_flow/version_control/git/repository.rb +99 -0
- data/lib/hustle_and_flow.rb +1 -2
- data/spec/lib/hustle_and_flow/formatters/branch_table_formatter_spec.rb +44 -0
- data/spec/lib/hustle_and_flow/formatters/issue_detail_formatter_spec.rb +49 -0
- data/spec/lib/hustle_and_flow/formatters/issue_table_formatter_spec.rb +89 -0
- data/spec/lib/hustle_and_flow/io/shell_spec.rb +154 -0
- data/spec/lib/hustle_and_flow/issue_tracker_spec.rb +7 -0
- data/spec/lib/hustle_and_flow/issue_trackers/github/issue_spec.rb +354 -0
- data/spec/lib/hustle_and_flow/issue_trackers/github/issues_spec.rb +91 -0
- data/spec/lib/hustle_and_flow/issue_trackers/github_spec.rb +51 -0
- data/spec/lib/hustle_and_flow/vcs_repository_spec.rb +15 -0
- data/spec/lib/hustle_and_flow/version_control/git/branch_spec.rb +101 -0
- data/spec/lib/hustle_and_flow/version_control/git/branches_spec.rb +57 -0
- data/spec/lib/hustle_and_flow/version_control/git/repository_spec.rb +36 -0
- data/spec/lib/utils/url_slug_spec.rb +74 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/git_repo.rb +43 -0
- metadata +128 -16
- data/.gitignore +0 -19
- data/.ruby-version +0 -1
- data/.travis.yml +0 -13
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -56
- data/Rakefile +0 -2
- data/hustle_and_flow.gemspec +0 -37
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hustle_and_flow/formatters/issue_table_formatter'
|
3
|
+
require 'hustle_and_flow/issue_trackers/github/issue'
|
4
|
+
|
5
|
+
module HustleAndFlow
|
6
|
+
module Formatters
|
7
|
+
describe IssueTableFormatter do
|
8
|
+
it 'can output issue information as columns' do
|
9
|
+
issues = [
|
10
|
+
IssueTrackers::Github::Issue.new(
|
11
|
+
tracker: 'tracker',
|
12
|
+
data: {
|
13
|
+
number: 1,
|
14
|
+
state: 'open',
|
15
|
+
assignee: {
|
16
|
+
login: 'Michael Myers',
|
17
|
+
},
|
18
|
+
labels: [
|
19
|
+
{
|
20
|
+
name: 'feature',
|
21
|
+
},
|
22
|
+
],
|
23
|
+
title: 'Whatever This Feature Is Called Is Really Really Long, ' \
|
24
|
+
"Like Sooooo Long You Don't Even Know",
|
25
|
+
},
|
26
|
+
),
|
27
|
+
IssueTrackers::Github::Issue.new(
|
28
|
+
tracker: 'tracker',
|
29
|
+
data: {
|
30
|
+
number: 20,
|
31
|
+
state: 'closed',
|
32
|
+
assignee: {
|
33
|
+
login: 'Jeff Has a Really Really Long Name',
|
34
|
+
},
|
35
|
+
labels: [
|
36
|
+
{
|
37
|
+
name: 'bug',
|
38
|
+
},
|
39
|
+
],
|
40
|
+
title: 'My Short Issue Title',
|
41
|
+
},
|
42
|
+
),
|
43
|
+
]
|
44
|
+
|
45
|
+
columnizer = IssueTableFormatter.new(issues)
|
46
|
+
|
47
|
+
expect(columnizer.to_ary).to eql [
|
48
|
+
[
|
49
|
+
[
|
50
|
+
[:green],
|
51
|
+
'#1',
|
52
|
+
],
|
53
|
+
[
|
54
|
+
[:white],
|
55
|
+
'Michael Myers',
|
56
|
+
],
|
57
|
+
[
|
58
|
+
[:green, :bold],
|
59
|
+
'Feature',
|
60
|
+
],
|
61
|
+
[
|
62
|
+
[:white],
|
63
|
+
'Whatever This Feature Is Called Is Really Really Long, ' \
|
64
|
+
"Like Sooooo Long You Don't Even Know",
|
65
|
+
],
|
66
|
+
],
|
67
|
+
[
|
68
|
+
[
|
69
|
+
[:red],
|
70
|
+
'#20',
|
71
|
+
],
|
72
|
+
[
|
73
|
+
[:white],
|
74
|
+
'Jeff Has a Really Really Long Name',
|
75
|
+
],
|
76
|
+
[
|
77
|
+
[:red, :bold],
|
78
|
+
'Bug',
|
79
|
+
],
|
80
|
+
[
|
81
|
+
[:white],
|
82
|
+
'My Short Issue Title',
|
83
|
+
],
|
84
|
+
],
|
85
|
+
]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hustle_and_flow/io/shell'
|
3
|
+
require 'hustle_and_flow/issue_trackers/github/issue'
|
4
|
+
|
5
|
+
module HustleAndFlow
|
6
|
+
module Io
|
7
|
+
describe Shell do
|
8
|
+
let(:issue) { instance_double(HustleAndFlow::IssueTrackers::Github::Issue) }
|
9
|
+
let(:io) { Shell.new }
|
10
|
+
|
11
|
+
it 'considers the issue correct if it is new' do
|
12
|
+
allow(issue).to receive(:new?).
|
13
|
+
and_return(true)
|
14
|
+
allow(issue).to receive(:url).
|
15
|
+
and_return('http://example.com')
|
16
|
+
allow(Kernel).to receive(:system).
|
17
|
+
and_return(true)
|
18
|
+
|
19
|
+
expect(io.correct_issue?(issue)).to be_truthy
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'opens the URL of the issue if it is new' do
|
23
|
+
allow(issue).to receive(:new?).
|
24
|
+
and_return(true)
|
25
|
+
allow(issue).to receive(:url).
|
26
|
+
and_return('http://example.com')
|
27
|
+
allow(Kernel).to receive(:system).
|
28
|
+
and_return(true)
|
29
|
+
|
30
|
+
expect(io.correct_issue?(issue)).to be_truthy
|
31
|
+
expect(Kernel).to have_received(:system).
|
32
|
+
with('open http://example.com')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'considers the issue correct if the user responds positively when the issue has a body' do
|
36
|
+
allow(issue).to receive(:new?).
|
37
|
+
and_return(false)
|
38
|
+
allow(issue).to receive(:has_body?).
|
39
|
+
and_return(true)
|
40
|
+
allow(Formatters::IssueDetailFormatter).to receive(:to_details_s).
|
41
|
+
and_return ''
|
42
|
+
allow(io).to receive(:yes?).
|
43
|
+
and_return(true)
|
44
|
+
|
45
|
+
expect(io.correct_issue?(issue)).to be_truthy
|
46
|
+
expect(io).to have_received(:yes?).
|
47
|
+
with('Does this issue look correct?')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'displays the details of the issue to the user if it has a body' do
|
51
|
+
allow(issue).to receive(:new?).
|
52
|
+
and_return(false)
|
53
|
+
allow(issue).to receive(:has_body?).
|
54
|
+
and_return(true)
|
55
|
+
allow(Formatters::IssueDetailFormatter).to receive(:to_details_s).
|
56
|
+
and_return 'my details'
|
57
|
+
|
58
|
+
expect(io.correct_issue?(issue)).to be_truthy
|
59
|
+
expect(io).to have_received(:print_wrapped).
|
60
|
+
with('my details',
|
61
|
+
colorize: true)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'considers the issue incorrect if the user responds negatively when the issue has a body' do
|
65
|
+
allow(issue).to receive(:new?).
|
66
|
+
and_return(false)
|
67
|
+
allow(issue).to receive(:has_body?).
|
68
|
+
and_return(true)
|
69
|
+
allow(Formatters::IssueDetailFormatter).to receive(:to_details_s).
|
70
|
+
and_return ''
|
71
|
+
allow(io).to receive(:yes?).
|
72
|
+
and_return(false)
|
73
|
+
|
74
|
+
expect(io.correct_issue?(issue)).to be_falsey
|
75
|
+
expect(io).to have_received(:yes?).
|
76
|
+
with('Does this issue look correct?')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'considers the issue correct if the issue is neither new, nor has a body' do
|
80
|
+
allow(issue).to receive(:new?).
|
81
|
+
and_return(false)
|
82
|
+
allow(issue).to receive(:has_body?).
|
83
|
+
and_return(false)
|
84
|
+
|
85
|
+
expect(io.correct_issue?(issue)).to be_truthy
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'can print a table with colors' do
|
89
|
+
allow(io).to receive(:print_table).
|
90
|
+
and_return('yay')
|
91
|
+
|
92
|
+
io.print_formatted_table(
|
93
|
+
data: [
|
94
|
+
[
|
95
|
+
[[:green], '#1'],
|
96
|
+
[[:white], 'Michael Myers'],
|
97
|
+
[[:green, :bold], 'Feature'],
|
98
|
+
[[:white], 'Whatever This Feature Is Called Is Really Really Long, ' \
|
99
|
+
"Like Sooooo Long You Don't Even Know"],
|
100
|
+
],
|
101
|
+
[
|
102
|
+
[[:red], '#20'],
|
103
|
+
[[:white], 'Jeff Has a Really Really Long Name'],
|
104
|
+
[[:red, :bold], 'Bug'],
|
105
|
+
[[:white], 'My Short Issue Title'],
|
106
|
+
],
|
107
|
+
],
|
108
|
+
)
|
109
|
+
|
110
|
+
expect(io).to have_received(:print_table).
|
111
|
+
with(
|
112
|
+
[
|
113
|
+
[
|
114
|
+
"\e[32m#1\e[0m",
|
115
|
+
"\e[37mMichael Myers\e[0m",
|
116
|
+
"\e[32m\e[1mFeature\e[0m",
|
117
|
+
"\e[37mWhatever This Feature Is Called Is Really Really Long, " \
|
118
|
+
"Like Sooooo Long You Don't Even Know\e[0m",
|
119
|
+
],
|
120
|
+
[
|
121
|
+
"\e[31m#20\e[0m",
|
122
|
+
"\e[37mJeff Has a Really Really Long Name\e[0m",
|
123
|
+
"\e[31m\e[1mBug\e[0m",
|
124
|
+
"\e[37mMy Short Issue Title\e[0m",
|
125
|
+
],
|
126
|
+
],
|
127
|
+
truncate: true,
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'can print a table with a title' do
|
132
|
+
allow(io).to receive(:print_table).
|
133
|
+
and_return('yay')
|
134
|
+
allow(io).to receive(:terminal_width).
|
135
|
+
and_return(80)
|
136
|
+
allow($stdout).to receive(:puts)
|
137
|
+
|
138
|
+
io.print_formatted_table(
|
139
|
+
title: 'My Uber Fancy Title',
|
140
|
+
data: [
|
141
|
+
[
|
142
|
+
['green', '#1'],
|
143
|
+
],
|
144
|
+
],
|
145
|
+
)
|
146
|
+
|
147
|
+
expect($stdout).to have_received(:puts).
|
148
|
+
with("#{' ' * 30}My Uber Fancy Title#{' ' * 31}")
|
149
|
+
expect($stdout).to have_received(:puts).
|
150
|
+
with('-' * 80)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,354 @@
|
|
1
|
+
require 'rspectacular'
|
2
|
+
require 'octokit'
|
3
|
+
require 'hustle_and_flow/issue_trackers/github'
|
4
|
+
require 'hustle_and_flow/issue_trackers/github/issue'
|
5
|
+
|
6
|
+
module HustleAndFlow
|
7
|
+
module IssueTrackers
|
8
|
+
class Github
|
9
|
+
describe Issue, vcr: { record: :all } do
|
10
|
+
let(:repo) { OpenStruct.new(base_name: 'thekompanee/hustle_and_flow') }
|
11
|
+
let(:tracker) { Github.new(repo: repo) }
|
12
|
+
|
13
|
+
it 'can create an issue' do
|
14
|
+
issue = Issue.create(tracker: tracker,
|
15
|
+
title: 'My IssueTracker Issue Title')
|
16
|
+
|
17
|
+
expect(issue).to be_a Issue
|
18
|
+
expect(issue.title).to eql 'My IssueTracker Issue Title'
|
19
|
+
expect(issue.number).to be_a Integer
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'can create an issue with a body' do
|
23
|
+
issue = Issue.create(tracker: tracker,
|
24
|
+
title: 'My IssueTracker Issue Title',
|
25
|
+
body: 'My body is a wonderland')
|
26
|
+
|
27
|
+
expect(issue.body).to eql 'My body is a wonderland'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'can create an issue with a label' do
|
31
|
+
issue = Issue.create(tracker: tracker,
|
32
|
+
title: 'My IssueTracker Issue Title',
|
33
|
+
labels: 'feature')
|
34
|
+
|
35
|
+
expect(issue).to have_label 'feature'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'can create an issue with multiple labels' do
|
39
|
+
issue = Issue.create(tracker: tracker,
|
40
|
+
title: 'My IssueTracker Issue Title',
|
41
|
+
labels: %w{feature bug})
|
42
|
+
|
43
|
+
expect(issue).to have_label 'feature'
|
44
|
+
expect(issue).to have_label 'bug'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'when starting work on an issue, it reopens it if it is closed' do
|
48
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
49
|
+
allow(io).to receive(:correct_issue?).
|
50
|
+
and_return(true)
|
51
|
+
allow(io).to receive(:reassign_issue?).
|
52
|
+
and_return(true)
|
53
|
+
|
54
|
+
issue = Issue.new(tracker: tracker,
|
55
|
+
io: io,
|
56
|
+
data: {
|
57
|
+
number: 74,
|
58
|
+
state: 'closed',
|
59
|
+
html_url: 'https://github.com/thekompanee/hustle_and_flow' })
|
60
|
+
|
61
|
+
started_issue = issue.start(me: 'jfelchner')
|
62
|
+
|
63
|
+
expect(started_issue).to be_a Issue
|
64
|
+
expect(started_issue).not_to be_closed
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'when starting an issue, it reassigns the issue if it is unassigned' do
|
68
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
69
|
+
allow(io).to receive(:correct_issue?).
|
70
|
+
and_return(true)
|
71
|
+
|
72
|
+
issue = Issue.new(tracker: tracker,
|
73
|
+
io: io,
|
74
|
+
data: {
|
75
|
+
number: 74,
|
76
|
+
html_url: 'https://github.com/thekompanee/hustle_and_flow' })
|
77
|
+
|
78
|
+
started_issue = issue.start(me: 'jfelchner')
|
79
|
+
|
80
|
+
expect(started_issue).to be_a Issue
|
81
|
+
expect(started_issue).not_to eql issue
|
82
|
+
expect(started_issue).to be_assigned_to 'jfelchner'
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'does not reassign the issue if it is already assigned to the user' do
|
86
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
87
|
+
allow(io).to receive(:correct_issue?).
|
88
|
+
and_return(true)
|
89
|
+
|
90
|
+
issue = Issue.new(tracker: tracker,
|
91
|
+
io: io,
|
92
|
+
data: {
|
93
|
+
number: 74,
|
94
|
+
assignee: { login: 'jfelchner' },
|
95
|
+
html_url: 'https://github.com/thekompanee/hustle_and_flow' })
|
96
|
+
|
97
|
+
started_issue = issue.start(me: 'jfelchner')
|
98
|
+
|
99
|
+
expect(started_issue).to be_a Issue
|
100
|
+
expect(started_issue).to eql issue
|
101
|
+
expect(started_issue).to be_assigned_to 'jfelchner'
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'reassigns the issue if it is not already assigned to the user and the user ' \
|
105
|
+
'chooses to reassign it' do
|
106
|
+
|
107
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
108
|
+
allow(io).to receive(:correct_issue?).
|
109
|
+
and_return(true)
|
110
|
+
allow(io).to receive(:reassign_issue?).
|
111
|
+
and_return(true)
|
112
|
+
|
113
|
+
issue = Issue.new(tracker: tracker,
|
114
|
+
io: io,
|
115
|
+
data: {
|
116
|
+
number: 74,
|
117
|
+
assignee: { login: 'neo' },
|
118
|
+
html_url: 'https://github.com/thekompanee/hustle_and_flow' })
|
119
|
+
|
120
|
+
started_issue = issue.start(me: 'jfelchner')
|
121
|
+
|
122
|
+
expect(started_issue).to be_a Issue
|
123
|
+
expect(started_issue).not_to eql issue
|
124
|
+
expect(started_issue).to be_assigned_to('jfelchner')
|
125
|
+
expect(io).to have_received(:reassign_issue?).
|
126
|
+
with(from: 'neo')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'does not reassign the issue if it is not already assigned to the user but the ' \
|
130
|
+
'user chooses not to reassign it' do
|
131
|
+
|
132
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
133
|
+
allow(io).to receive(:correct_issue?).
|
134
|
+
and_return(true)
|
135
|
+
allow(io).to receive(:reassign_issue?).
|
136
|
+
and_return(false)
|
137
|
+
|
138
|
+
issue = Issue.create(tracker: tracker,
|
139
|
+
io: io,
|
140
|
+
title: 'Ninja Assassin',
|
141
|
+
assignee: 'blakecash')
|
142
|
+
|
143
|
+
started_issue = issue.start(me: 'jfelchner')
|
144
|
+
|
145
|
+
expect(started_issue).to be_a Issue
|
146
|
+
expect(started_issue).to eql issue
|
147
|
+
expect(io).to have_received(:reassign_issue?).
|
148
|
+
with(from: 'blakecash')
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'does not start work on an issue if it is not the correct one' do
|
152
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
153
|
+
allow(io).to receive(:correct_issue?).
|
154
|
+
and_return(false)
|
155
|
+
|
156
|
+
issue = Issue.create(io: io,
|
157
|
+
tracker: tracker,
|
158
|
+
title: 'My IssueTracker Issue Title')
|
159
|
+
|
160
|
+
expect(issue.start).to be_nil
|
161
|
+
expect(io).to have_received(:correct_issue?).
|
162
|
+
with(issue)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'considers the issue new if it was created less than 5 minutes ago' do
|
166
|
+
issue = Issue.new(tracker: tracker,
|
167
|
+
data: { created_at: Time.now.utc })
|
168
|
+
|
169
|
+
less_than_five_minutes_from_now = Time.now.utc + (5 * 60) - 1
|
170
|
+
|
171
|
+
Timecop.freeze(less_than_five_minutes_from_now) do
|
172
|
+
expect(issue).to be_new
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'does not consider the issue new if it was created exactly 5 minutes ago' do
|
177
|
+
issue = Issue.new(tracker: tracker,
|
178
|
+
data: { created_at: Time.now.utc })
|
179
|
+
|
180
|
+
five_minutes_from_now = Time.now.utc + (5 * 60)
|
181
|
+
|
182
|
+
Timecop.freeze(five_minutes_from_now) do
|
183
|
+
expect(issue).not_to be_new
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'does not have a body if the body is nil' do
|
188
|
+
issue = Issue.new(tracker: tracker,
|
189
|
+
data: { body: nil })
|
190
|
+
|
191
|
+
expect(issue).not_to have_body
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'does not have a body if the body is empty' do
|
195
|
+
issue = Issue.new(tracker: tracker,
|
196
|
+
data: { body: '' })
|
197
|
+
|
198
|
+
expect(issue).not_to have_body
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'does have a body if the body is not empty' do
|
202
|
+
issue = Issue.new(tracker: tracker,
|
203
|
+
data: { body: 'My body is a wonderland' })
|
204
|
+
|
205
|
+
expect(issue).to have_body
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'knows which labels are categories' do
|
209
|
+
issue = Issue.new(tracker: tracker,
|
210
|
+
data: { labels: [{ name: 'feature' }] })
|
211
|
+
|
212
|
+
expect(issue.category).to eql 'feature'
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'knows which labels are not categories' do
|
216
|
+
issue = Issue.new(tracker: tracker,
|
217
|
+
data: { labels: [{ name: 'featuring' }] })
|
218
|
+
|
219
|
+
expect(issue.category).to be_nil
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'knows if the issue is unassigned' do
|
223
|
+
issue = Issue.new(tracker: tracker,
|
224
|
+
data: { assignee: { login: 'bar' } })
|
225
|
+
|
226
|
+
expect(issue).not_to be_unassigned
|
227
|
+
|
228
|
+
issue = Issue.new(tracker: tracker,
|
229
|
+
data: { assignee: {} })
|
230
|
+
expect(issue).to be_unassigned
|
231
|
+
|
232
|
+
issue = Issue.new(tracker: tracker,
|
233
|
+
data: { assignee: nil })
|
234
|
+
expect(issue).to be_unassigned
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'can reassign an issue to another user' do
|
238
|
+
original_issue = Issue.create(tracker: tracker,
|
239
|
+
title: 'Ninjitsu')
|
240
|
+
|
241
|
+
reassigned_issue = original_issue.assign(to: 'jfelchner')
|
242
|
+
|
243
|
+
expect(reassigned_issue).to be_a Issue
|
244
|
+
expect(reassigned_issue).to be_assigned_to 'jfelchner'
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'marks the assignee as the contact if there is an assigned user' do
|
248
|
+
issue = Issue.new(tracker: tracker,
|
249
|
+
data: { assignee: { login: 'flibbity' } })
|
250
|
+
|
251
|
+
expect(issue.contact).to eql 'flibbity'
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'marks the creator as the contact if the issue is unassigned' do
|
255
|
+
issue = Issue.new(tracker: tracker,
|
256
|
+
data: { assignee: { login: 'undercoat' } })
|
257
|
+
|
258
|
+
expect(issue.contact).to eql 'undercoat'
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'marks the creator as the assignee if there is both an assignee and a creator' do
|
262
|
+
issue = Issue.new(tracker: tracker,
|
263
|
+
data: {
|
264
|
+
user: { login: 'undercoat' },
|
265
|
+
assignee: { login: 'flibbity' } })
|
266
|
+
|
267
|
+
expect(issue.contact).to eql 'flibbity'
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'can create a branch name from only its title' do
|
271
|
+
issue = Issue.new(tracker: tracker,
|
272
|
+
data: { title: 'My Branchy Branch' })
|
273
|
+
|
274
|
+
expect(issue.to_branch_name).to eql 'my-branchy-branch-v1'
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'can create a branch name from its title and number' do
|
278
|
+
issue = Issue.new(tracker: tracker,
|
279
|
+
data: {
|
280
|
+
title: 'My Branchy Branch',
|
281
|
+
number: 42 })
|
282
|
+
|
283
|
+
expect(issue.to_branch_name).to eql 'my-branchy-branch-closes-42-v1'
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'can create a branch name from its type, title and number' do
|
287
|
+
issue = Issue.create(tracker: tracker,
|
288
|
+
labels: [{ name: 'feature' }],
|
289
|
+
title: 'My Branchy Branch')
|
290
|
+
|
291
|
+
expect(issue.to_branch_name).to eql \
|
292
|
+
"feature/my-branchy-branch-closes-#{issue.number}-v1"
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'can create a branch name from a custom action' do
|
296
|
+
issue = Issue.new(tracker: tracker,
|
297
|
+
data: {
|
298
|
+
title: 'My Branchy Branch',
|
299
|
+
number: 42 })
|
300
|
+
|
301
|
+
branch_name = issue.to_branch_name(action: 'References')
|
302
|
+
|
303
|
+
expect(branch_name).to eql 'my-branchy-branch-references-42-v1'
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'cannot create a branch name from an unknown action' do
|
307
|
+
issue = Issue.new(tracker: tracker,
|
308
|
+
data: {
|
309
|
+
title: 'My Branchy Branch',
|
310
|
+
number: 42 })
|
311
|
+
|
312
|
+
expect { issue.to_branch_name(action: 'Killit') }.to \
|
313
|
+
raise_error HustleAndFlow::Errors::UnknownIssueActionError
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'can create a branch name from a custom version' do
|
317
|
+
issue = Issue.new(tracker: tracker,
|
318
|
+
data: {
|
319
|
+
title: 'My Branchy Branch',
|
320
|
+
number: 42 })
|
321
|
+
|
322
|
+
branch_name = issue.to_branch_name(version: 9_999)
|
323
|
+
|
324
|
+
expect(branch_name).to eql 'my-branchy-branch-closes-42-v9999'
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'knows how to match against the type and title' do
|
328
|
+
issue = Issue.new(tracker: tracker,
|
329
|
+
data: {
|
330
|
+
labels: [{ name: 'bug' }],
|
331
|
+
title: 'Found a bug' })
|
332
|
+
|
333
|
+
expect(issue).to be_match(type: 'bug',
|
334
|
+
title: 'Found a bug')
|
335
|
+
|
336
|
+
expect(issue).not_to be_match(type: 'foo',
|
337
|
+
title: 'Found a bug')
|
338
|
+
|
339
|
+
expect(issue).not_to be_match(type: 'bug',
|
340
|
+
title: 'xFound a bug')
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'knows how to match against the number' do
|
344
|
+
issue = Issue.new(tracker: tracker,
|
345
|
+
data: {
|
346
|
+
number: 1347 })
|
347
|
+
|
348
|
+
expect(issue).to be_match(number: 1347)
|
349
|
+
expect(issue).not_to be_match(number: 18)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hustle_and_flow/issue_trackers/github'
|
3
|
+
require 'hustle_and_flow/issue_trackers/github/issues'
|
4
|
+
|
5
|
+
module HustleAndFlow
|
6
|
+
module IssueTrackers
|
7
|
+
class Github
|
8
|
+
describe Issues, vcr: { record: :all } do
|
9
|
+
let(:repo) { OpenStruct.new(base_name: 'thekompanee/hustle_and_flow') }
|
10
|
+
let(:tracker) { Github.new(repo: repo) }
|
11
|
+
|
12
|
+
it 'can find an issue based on the type and title' do
|
13
|
+
issue = Issues.new(tracker: tracker).
|
14
|
+
find_or_create type: 'bug',
|
15
|
+
title: 'Menu item specifications not working'
|
16
|
+
|
17
|
+
expect(issue).to be_a Github::Issue
|
18
|
+
expect(issue.number).to eql 36
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'can find an issue based on the number' do
|
22
|
+
issue = Issues.new(tracker: tracker).
|
23
|
+
find_or_create number: 2
|
24
|
+
|
25
|
+
expect(issue).to be_a Github::Issue
|
26
|
+
expect(issue.title).to eql "hello there, is it tea you're looking for? 2"
|
27
|
+
expect(issue.number).to eql 2
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'can create an issue if the found issue does not exist' do
|
31
|
+
random = SecureRandom.hex(4)
|
32
|
+
issue = Issues.new(tracker: tracker).
|
33
|
+
find_or_create type: 'feature',
|
34
|
+
title: "Ninjitsu #{random}"
|
35
|
+
|
36
|
+
expect(issue).to be_a Github::Issue
|
37
|
+
expect(issue.title).to eql "Ninjitsu #{random}"
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can start an issue with a specified issue number' do
|
41
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
42
|
+
issue = Issues.start(tracker: tracker,
|
43
|
+
io: io,
|
44
|
+
me: 'jfelchner',
|
45
|
+
issue_data: {
|
46
|
+
number: 36,
|
47
|
+
})
|
48
|
+
|
49
|
+
expect(issue).to be_a Github::Issue
|
50
|
+
expect(issue.category).to eql 'bug'
|
51
|
+
expect(issue.title).to eql 'Menu item specifications not working'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'can start an issue if a type and title is specified' do
|
55
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
56
|
+
issue = Issues.start(tracker: tracker,
|
57
|
+
io: io,
|
58
|
+
me: 'jfelchner',
|
59
|
+
issue_data: {
|
60
|
+
type: 'bug',
|
61
|
+
title: 'Menu item specifications not working',
|
62
|
+
})
|
63
|
+
|
64
|
+
expect(issue).to be_a Github::Issue
|
65
|
+
expect(issue.number).to eql 36
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'can start an issue if a type and title is specified' do
|
69
|
+
io = instance_double(HustleAndFlow::Io::Shell)
|
70
|
+
|
71
|
+
allow(io).to receive(:print_formatted_table).
|
72
|
+
with(any_args).
|
73
|
+
and_return true
|
74
|
+
allow(io).to receive(:choose_issue).
|
75
|
+
and_return 216
|
76
|
+
|
77
|
+
issue = Issues.start(tracker: tracker,
|
78
|
+
io: io,
|
79
|
+
me: 'jfelchner',
|
80
|
+
issue_data: {
|
81
|
+
type: 'bug',
|
82
|
+
})
|
83
|
+
|
84
|
+
expect(issue).to be_a Github::Issue
|
85
|
+
expect(issue.title).to eql 'Ninjitsu'
|
86
|
+
expect(issue.number).to eql 216
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|