reviewlette 0.0.9 → 1.0.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/.dockerignore +1 -0
- data/.travis.yml +2 -2
- data/Gemfile +13 -16
- data/Gemfile.lock +100 -101
- data/README.md +26 -26
- data/config/github_example.yml +4 -5
- data/lib/reviewlette.rb +40 -32
- data/lib/reviewlette/github_connection.rb +42 -38
- data/lib/reviewlette/trello_connection.rb +34 -33
- data/lib/reviewlette/version.rb +3 -0
- data/reviewlette.gemspec +4 -7
- data/spec/github_connection_spec.rb +23 -20
- data/spec/reviewlette_spec.rb +136 -38
- data/spec/trello_connection_spec.rb +18 -17
- metadata +12 -45
- data/bin/reviewlette +0 -8
- data/config/members_example.yml +0 -25
- data/lib/reviewlette/vacations.rb +0 -30
- data/spec/vacation_spec.rb +0 -36
@@ -1,42 +1,46 @@
|
|
1
|
-
require 'yaml'
|
2
1
|
require 'octokit'
|
3
2
|
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
class Reviewlette
|
4
|
+
class GithubConnection
|
5
|
+
attr_accessor :client, :repo
|
6
|
+
|
7
|
+
def initialize(repo, token)
|
8
|
+
@client = Octokit::Client.new(access_token: token)
|
9
|
+
@repo = repo
|
10
|
+
end
|
11
|
+
|
12
|
+
def pull_requests
|
13
|
+
@client.pull_requests(@repo)
|
14
|
+
end
|
15
|
+
|
16
|
+
def labels(issue)
|
17
|
+
@client.labels_for_issue(@repo, issue).map(&:name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_assignees(number, assignees)
|
21
|
+
@client.update_issue(@repo, number, assignees: assignees)
|
22
|
+
end
|
23
|
+
|
24
|
+
def comment_reviewers(number, reviewers, trello_card)
|
25
|
+
assignees = reviewers.map { |r| "@#{r.github_handle}" }.join(' and ')
|
26
|
+
|
27
|
+
comment = <<-eos
|
28
|
+
#{assignees} will review your pull request :dancers: check #{trello_card.url}
|
29
|
+
#{assignees}: Please review this pull request using our guidelines:
|
30
|
+
* test for acceptance criteria / functionality
|
31
|
+
* check if the new code is covered with tests
|
32
|
+
* check for unintended consequences
|
33
|
+
* encourage usage of the boyscout rule
|
34
|
+
* make sure the code is architected in the best way
|
35
|
+
* check that no unnecessary technical debt got introduced
|
36
|
+
* make sure that no unnecessary FIXMEs or TODOs got added
|
37
|
+
eos
|
38
|
+
|
39
|
+
@client.add_comment(@repo, number, comment)
|
40
|
+
end
|
41
|
+
|
42
|
+
def repo_exists?
|
43
|
+
@client.repository?(@repo)
|
44
|
+
end
|
15
45
|
end
|
16
|
-
|
17
|
-
def add_assignee(number, assignee)
|
18
|
-
@client.update_issue(@repo, number, assignee: assignee)
|
19
|
-
end
|
20
|
-
|
21
|
-
def reviewer_comment(number, assignee, trello_card)
|
22
|
-
comment = "@#{assignee} is your reviewer :dancers: check #{trello_card.url} \n" \
|
23
|
-
"@#{assignee}: Please review this pull request using our guidelines: \n" \
|
24
|
-
"* test for acceptance criteria / functionality \n" \
|
25
|
-
"* check if the new code is covered with tests \n" \
|
26
|
-
"* check for unintended consequences \n" \
|
27
|
-
"* encourage usage of the boyscout rule \n" \
|
28
|
-
"* make sure the code is architected in the best way \n" \
|
29
|
-
"* check that no unnecessary technical debt got introduced \n" \
|
30
|
-
"* make sure that no unnecessary FIXMEs or TODOs got added \n"
|
31
|
-
@client.add_comment(@repo, number, comment)
|
32
|
-
end
|
33
|
-
|
34
|
-
def unassigned_pull_requests
|
35
|
-
list_pulls.select { |issue| !issue[:assignee] }
|
36
|
-
end
|
37
|
-
|
38
|
-
def repo_exists?
|
39
|
-
@client.repository?(@repo)
|
40
|
-
end
|
41
|
-
|
42
46
|
end
|
@@ -1,45 +1,46 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'trello'
|
3
3
|
|
4
|
-
|
5
|
-
class TrelloConnection
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
class Reviewlette
|
5
|
+
class TrelloConnection
|
6
|
+
|
7
|
+
attr_accessor :board
|
8
|
+
|
9
|
+
def initialize(config = nil)
|
10
|
+
config ||= YAML.load_file("#{File.dirname(__FILE__)}/../../config/trello.yml")
|
11
|
+
Trello.configure do |conf|
|
12
|
+
conf.developer_public_key = config['consumerkey']
|
13
|
+
conf.member_token = config['oauthtoken']
|
14
|
+
end
|
15
|
+
@board = Trello::Board.find(config['board_id'])
|
14
16
|
end
|
15
|
-
@board = Trello::Board.find(@trello['board_id'])
|
16
|
-
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def add_reviewer_to_card(reviewer, card)
|
19
|
+
reviewer = find_member_by_username(reviewer)
|
20
|
+
card.add_member(reviewer)
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
def comment_reviewers(card, repo_name, issue_id, reviewers)
|
24
|
+
comment = reviewers.map { |r| "@#{r.trello_handle}" }.join(' and ')
|
25
|
+
comment += " will review https://github.com/#{repo_name}/issues/#{issue_id}"
|
26
|
+
card.add_comment(comment)
|
27
|
+
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def move_card_to_list(card, column_name)
|
30
|
+
column = find_column(column_name)
|
31
|
+
card.move_to_list(column)
|
32
|
+
end
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
def find_column(column_name)
|
35
|
+
@board.lists.find { |x| x.name == column_name }
|
36
|
+
end
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
def find_member_by_username(username)
|
39
|
+
@board.members.find { |m| m.username == username }
|
40
|
+
end
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
+
def find_card_by_id(id)
|
43
|
+
@board.cards.find { |c| c.short_id == id.to_i }
|
44
|
+
end
|
42
45
|
end
|
43
|
-
|
44
46
|
end
|
45
|
-
|
data/reviewlette.gemspec
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'reviewlette'
|
4
|
+
require 'reviewlette/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "reviewlette"
|
8
|
-
spec.version = VERSION
|
8
|
+
spec.version = Reviewlette::VERSION
|
9
9
|
spec.authors = ["jschmid1"]
|
10
10
|
spec.email = ["jschmid@suse.de"]
|
11
11
|
spec.summary = %q{Randomly assignes a reviewer to your Pullrequest and corresponding Trello Card.}
|
@@ -18,9 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_runtime_dependency 'ruby-trello'
|
22
|
-
spec.add_runtime_dependency 'octokit'
|
23
|
-
spec.add_runtime_dependency 'sequel', '=4.13.0'
|
24
|
-
spec.add_runtime_dependency 'sqlite3', '=1.3.9'
|
21
|
+
spec.add_runtime_dependency 'ruby-trello'
|
22
|
+
spec.add_runtime_dependency 'octokit'
|
25
23
|
end
|
26
|
-
|
@@ -1,46 +1,49 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe GithubConnection do
|
4
|
-
|
5
|
-
|
6
|
-
let(
|
7
|
-
let(
|
8
|
-
let(
|
3
|
+
describe Reviewlette::GithubConnection do
|
4
|
+
subject { described_class.new(repo, token) }
|
5
|
+
let(:repo) { 'test' }
|
6
|
+
let(:token) { 'foo' }
|
7
|
+
let(:member1) { double(name: 'test1', github_handle: 'githubtest1') }
|
8
|
+
let(:member2) { double(name: 'test2', github_handle: 'githubtest2') }
|
9
9
|
|
10
10
|
describe '.new' do
|
11
11
|
it 'initializes octokit client and repo' do
|
12
12
|
expect(Octokit::Client).to receive(:new).with(:access_token => token)
|
13
|
-
expect(
|
13
|
+
expect(subject.repo).to eq(repo)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
describe '#
|
18
|
-
it 'adds
|
19
|
-
expect(
|
20
|
-
|
17
|
+
describe '#add_assignees' do
|
18
|
+
it 'adds assignees to the GitHub issue' do
|
19
|
+
expect(subject.client).to receive(:update_issue).with(repo, 11, assignees: ['test'])
|
20
|
+
subject.add_assignees(11, ['test'])
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
describe '#
|
24
|
+
describe '#comment_reviewers' do
|
25
25
|
it 'comments on a given issue' do
|
26
|
-
card
|
26
|
+
card = Trello::Card.new
|
27
|
+
reviewers = [member1, member2]
|
28
|
+
|
27
29
|
allow(card).to receive(:url).and_return('url')
|
28
|
-
expect(
|
29
|
-
|
30
|
+
expect(subject.client).to receive(:add_comment).with(repo, 11, anything)
|
31
|
+
|
32
|
+
subject.comment_reviewers(11, reviewers, card)
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
33
|
-
describe '#
|
36
|
+
describe '#pull_requests' do
|
34
37
|
it 'lists all pullrequests for a given repository' do
|
35
|
-
expect(
|
36
|
-
|
38
|
+
expect(subject.client).to receive(:pull_requests).with(repo)
|
39
|
+
subject.pull_requests
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
40
43
|
describe '#repo_exists?' do
|
41
44
|
it 'checks if a certain repository exists' do
|
42
|
-
expect(
|
43
|
-
|
45
|
+
expect(subject.client).to receive(:repository?).with(repo)
|
46
|
+
subject.repo_exists?
|
44
47
|
end
|
45
48
|
|
46
49
|
end
|
data/spec/reviewlette_spec.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Reviewlette do
|
4
|
-
|
4
|
+
let(:instance) { described_class.new members: [member1, member2] }
|
5
|
+
subject { instance }
|
5
6
|
|
6
|
-
let(:
|
7
|
-
|
8
|
-
let(:members_config) { { 'members' => [member1, member2] } }
|
9
|
-
let(:member1) { { 'name' => 'test1', 'suse_username' => 'test1', 'trello_username' => 'trellotest1' } }
|
10
|
-
let(:member2) { { 'name' => 'test2', 'suse_username' => 'test2', 'trello_username' => 'trellotest2' } }
|
7
|
+
let(:member1) { double(name: 'test1', github_handle: 'pinky', trello_handle: 'trellotest1') }
|
8
|
+
let(:member2) { double(name: 'test2', github_handle: 'brain', trello_handle: 'trellotest2') }
|
11
9
|
|
12
10
|
let(:github_config) { { token: token, repos: [repo, repo2] } }
|
13
11
|
let(:token) { '1234' }
|
@@ -15,71 +13,171 @@ describe Reviewlette do
|
|
15
13
|
let(:repo2) { 'SUSE/foo' }
|
16
14
|
|
17
15
|
before do
|
18
|
-
allow(TrelloConnection).to receive(:new).and_return TrelloConnection
|
19
|
-
allow(GithubConnection).to receive(:new).with(repo, token).and_return GithubConnection
|
16
|
+
allow(described_class::TrelloConnection).to receive(:new).and_return described_class::TrelloConnection
|
17
|
+
allow(described_class::GithubConnection).to receive(:new).with(repo, token).and_return described_class::GithubConnection
|
20
18
|
allow(YAML).to receive(:load_file).with(/github\.yml/).and_return github_config
|
21
|
-
allow(YAML).to receive(:load_file).with(/members\.yml/).and_return members_config
|
22
19
|
end
|
23
20
|
|
24
21
|
describe '.new' do
|
25
22
|
it 'sets trello connections' do
|
26
|
-
expect(TrelloConnection).to receive(:new)
|
27
|
-
subject
|
23
|
+
expect(described_class::TrelloConnection).to receive(:new)
|
24
|
+
subject
|
28
25
|
end
|
29
26
|
end
|
30
27
|
|
31
28
|
describe '.run' do
|
32
29
|
it 'iterates over all open repositories and looks for unassigned pull requests' do
|
33
30
|
github_config[:repos].each do |r|
|
34
|
-
expect(
|
35
|
-
|
31
|
+
expect(subject).to receive(:check_repo).with(r, token)
|
32
|
+
subject.check_repo(r, token)
|
36
33
|
end
|
37
34
|
end
|
38
35
|
end
|
39
36
|
|
40
37
|
describe '.check_repo' do
|
38
|
+
context 'invalid repo' do
|
39
|
+
it 'skips the repo' do
|
40
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return false
|
41
|
+
expect { subject.check_repo(repo, token) }.to output(/does not exist/).to_stdout
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
41
45
|
it 'iterates over all open pull requests and extracts trello ids from name' do
|
42
|
-
expect(GithubConnection).to receive(:repo_exists?).and_return true
|
43
|
-
expect(GithubConnection).to receive(:
|
44
|
-
expect(
|
46
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return true
|
47
|
+
expect(described_class::GithubConnection).to receive(:pull_requests).and_return([{number: 11, title: 'test_issue_12'}])
|
48
|
+
expect(described_class::GithubConnection).to receive(:labels).and_return([])
|
49
|
+
expect(described_class::TrelloConnection).to receive(:find_card_by_id).with(12)
|
45
50
|
|
46
|
-
|
51
|
+
subject.check_repo(repo, token)
|
47
52
|
end
|
48
53
|
|
49
|
-
it '
|
50
|
-
|
54
|
+
it 'iterates over all pull requests and skips those with no card id' do
|
55
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return true
|
56
|
+
expect(described_class::GithubConnection).to receive(:pull_requests).and_return([{ number: 11, title: 'no card id' }])
|
57
|
+
expect(described_class::GithubConnection).to receive(:labels).and_return([])
|
51
58
|
|
52
|
-
expect(
|
53
|
-
|
54
|
-
|
55
|
-
|
59
|
+
expect { subject.check_repo(repo, token) }.to output(/Pull request not assigned to a trello card/).to_stdout
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'adds assignees and reviewers comment on github, adds comment on trello and moves card' do
|
63
|
+
card = Trello::Card.new
|
64
|
+
user = double(github_handle: 'testgit', trello_handle: 'testtrello')
|
65
|
+
pullrequest = { number: 11, title: 'test_issue_12', assignees: [] }
|
56
66
|
|
57
|
-
expect(GithubConnection).to receive(:
|
58
|
-
expect(GithubConnection).to receive(:
|
67
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return true
|
68
|
+
expect(described_class::GithubConnection).to receive(:pull_requests).and_return([pullrequest])
|
69
|
+
expect(described_class::GithubConnection).to receive(:labels).and_return([])
|
70
|
+
expect(described_class::TrelloConnection).to receive(:find_card_by_id).with(12).and_return(card)
|
71
|
+
expect(subject).to receive(:select_reviewers).and_return([user])
|
59
72
|
|
60
|
-
expect(
|
61
|
-
expect(
|
73
|
+
expect(described_class::GithubConnection).to receive(:add_assignees).with(11, ['testgit'])
|
74
|
+
expect(described_class::GithubConnection).to receive(:comment_reviewers).with(11, [user], card)
|
62
75
|
|
63
|
-
|
76
|
+
expect(described_class::TrelloConnection).to receive(:comment_reviewers).with(card, 'SUSE/test', 11, [user])
|
77
|
+
expect(described_class::TrelloConnection).to receive(:move_card_to_list).with(card, 'In review')
|
78
|
+
|
79
|
+
subject.check_repo(repo, token)
|
64
80
|
end
|
65
81
|
|
66
|
-
|
82
|
+
context 'pull request with one reviewer but two wanted' do
|
83
|
+
it 'selects a second reviewer' do
|
84
|
+
card = Trello::Card.new
|
85
|
+
pullrequest = { number: 11, title: 'pr title 42', assignees: [OpenStruct.new({login: 'pinky'})] }
|
86
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return true
|
87
|
+
expect(described_class::GithubConnection).to receive(:pull_requests).and_return([pullrequest])
|
88
|
+
expect(described_class::GithubConnection).to receive(:labels).and_return(['2 reviewers'])
|
89
|
+
expect(described_class::TrelloConnection).to receive(:find_card_by_id).with(42).and_return(card)
|
90
|
+
|
91
|
+
expect(described_class::GithubConnection).to receive(:add_assignees).with(11, ['pinky', 'brain'])
|
92
|
+
expect(described_class::GithubConnection).to receive(:comment_reviewers).with(11, [member1, member2], card)
|
93
|
+
expect(described_class::TrelloConnection).to receive(:comment_reviewers).with(card, repo, 11, [member1, member2])
|
94
|
+
expect(described_class::TrelloConnection).to receive(:move_card_to_list).with(card, 'In review')
|
95
|
+
expect(subject).to receive(:select_reviewers).with(card, 2, [member1]).and_return([member1, member2])
|
96
|
+
subject.check_repo(repo, token)
|
97
|
+
end
|
98
|
+
end
|
67
99
|
|
68
|
-
|
69
|
-
|
70
|
-
|
100
|
+
context 'pull request with two reviewers but no "2 reviewers" label' do
|
101
|
+
it 'keeps both reviewers' do
|
102
|
+
card = Trello::Card.new
|
103
|
+
pullrequest = { number: 11, title: 'pr title 42', assignees: [ OpenStruct.new({login: 'pinky'}), OpenStruct.new({login: 'brain'})] }
|
104
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return true
|
105
|
+
expect(described_class::GithubConnection).to receive(:pull_requests).and_return([pullrequest])
|
106
|
+
expect(described_class::GithubConnection).to receive(:labels).and_return([])
|
107
|
+
expect(described_class::TrelloConnection).to receive(:find_card_by_id).with(42).and_return(card)
|
108
|
+
|
109
|
+
expect(described_class::GithubConnection).not_to receive(:add_assignees)
|
110
|
+
expect(described_class::TrelloConnection).not_to receive(:move_card_to_list).with(card, 'In review')
|
111
|
+
subject.check_repo(repo, token)
|
112
|
+
end
|
113
|
+
end
|
71
114
|
|
72
|
-
|
73
|
-
|
74
|
-
|
115
|
+
context 'pull request with already correct number of reviewers' do
|
116
|
+
it 'does not assign nor comment in GitHub or Trello' do
|
117
|
+
card = Trello::Card.new
|
118
|
+
pullrequest = { number: 11, title: 'pr title 42', assignees: [ OpenStruct.new({login: 'pinky'}), OpenStruct.new({login: 'pinky'})] }
|
119
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return true
|
120
|
+
expect(described_class::GithubConnection).to receive(:pull_requests).and_return([pullrequest])
|
121
|
+
expect(described_class::GithubConnection).to receive(:labels).and_return(['2 reviewers'])
|
122
|
+
expect(described_class::TrelloConnection).to receive(:find_card_by_id).with(42).and_return(card)
|
123
|
+
|
124
|
+
expect(described_class::GithubConnection).not_to receive(:add_assignees)
|
125
|
+
expect(described_class::GithubConnection).not_to receive(:comment_reviewers)
|
126
|
+
expect(described_class::TrelloConnection).not_to receive(:comment_reviewers)
|
127
|
+
expect(described_class::TrelloConnection).not_to receive(:move_card_to_list).with(card, 'In review')
|
128
|
+
subject.check_repo(repo, token)
|
129
|
+
end
|
75
130
|
end
|
76
131
|
|
132
|
+
it 'does not find a reviewer' do
|
133
|
+
card = Trello::Card.new
|
134
|
+
|
135
|
+
expect(described_class::GithubConnection).to receive(:repo_exists?).and_return true
|
136
|
+
expect(described_class::GithubConnection).to receive(:pull_requests).and_return([{ number: 11, title: 'test_issue_12', assignees: [] }])
|
137
|
+
expect(described_class::GithubConnection).to receive(:labels).and_return([])
|
138
|
+
expect(described_class::TrelloConnection).to receive(:find_card_by_id).with(12).and_return(card)
|
139
|
+
expect(subject).to receive(:select_reviewers).and_return []
|
140
|
+
|
141
|
+
expect { subject.check_repo(repo, token) }.to output(/Could not find a reviewer/).to_stdout
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '.select_reviewers' do
|
77
147
|
it 'excludes the owner of the trello card' do
|
78
148
|
card = Trello::Card.new
|
149
|
+
reviewers = [member1, member2]
|
150
|
+
|
151
|
+
allow(card).to receive_message_chain(:members, :map).and_return(reviewers)
|
152
|
+
expect(subject.select_reviewers(card).size).to eq(1)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'selects n reviewers' do
|
156
|
+
card = Trello::Card.new
|
157
|
+
|
158
|
+
allow(card).to receive_message_chain(:members, :map).and_return([member1])
|
159
|
+
expect(subject.select_reviewers(card, 2)).to match_array([member1, member2])
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'selects only one reviewer if no second is available' do
|
163
|
+
card = Trello::Card.new
|
164
|
+
|
165
|
+
allow(card).to receive_message_chain(:members, :map).and_return([member2.trello_handle])
|
166
|
+
expect(subject.select_reviewers(card, 2)).to eq([member1])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '.how_many_should_review' do
|
171
|
+
subject { instance.how_many_should_review(labels) }
|
172
|
+
|
173
|
+
context 'with "2 reviewers" label' do
|
174
|
+
let(:labels) { ['foo', '2 reviewers', 'bar'] }
|
175
|
+
it { is_expected.to eq(2) }
|
176
|
+
end
|
79
177
|
|
80
|
-
|
81
|
-
|
82
|
-
|
178
|
+
context 'with no "2 reviewers" label' do
|
179
|
+
let(:labels) { ['foo', 'bar'] }
|
180
|
+
it { is_expected.to eq(1) }
|
83
181
|
end
|
84
182
|
end
|
85
183
|
end
|