reviewlette 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -6
- data/Gemfile +1 -1
- data/Gemfile.lock +6 -6
- data/README.md +5 -57
- data/Rakefile +13 -1
- data/bin/reviewlette +2 -1
- data/config/github_example.yml +3 -0
- data/config/members_example.yml +25 -0
- data/config/trello_example.yml +9 -0
- data/lib/reviewlette/github_connection.rb +29 -34
- data/lib/reviewlette/trello_connection.rb +30 -64
- data/lib/reviewlette/vacations.rb +23 -31
- data/lib/reviewlette.rb +36 -185
- data/reviewlette.gemspec +2 -2
- data/spec/github_connection_spec.rb +18 -73
- data/spec/reviewlette_spec.rb +40 -336
- data/spec/spec_helper.rb +1 -8
- data/spec/trello_connection_spec.rb +29 -164
- data/spec/vacation_spec.rb +26 -4
- metadata +12 -27
- data/Guardfile +0 -24
- data/config/.github.yml +0 -2
- data/config/.members.yml +0 -1
- data/config/.trello.yml +0 -4
- data/lib/matching.rb +0 -0
- data/lib/reviewlette/database.rb +0 -77
- data/lib/reviewlette/exceptions.rb +0 -7
- data/lib/reviewlette/graph.html +0 -17
- data/lib/reviewlette/graph_gen.rb +0 -62
- data/lib/reviewlette/mail.rb +0 -27
- data/lib/reviewlette/reviewlette.db +0 -0
- data/lib/reviewlette/version.rb +0 -3
- data/prophet.rb +0 -4
- data/reviewlette.db +0 -0
- data/spec/database_spec.rb +0 -34
- data/spec/support/request_stubbing.rb +0 -305
- data/task +0 -1
data/lib/reviewlette.rb
CHANGED
@@ -1,202 +1,53 @@
|
|
1
1
|
require 'reviewlette/trello_connection'
|
2
2
|
require 'reviewlette/github_connection'
|
3
|
-
require 'reviewlette/database'
|
4
|
-
require 'reviewlette/graph_gen'
|
5
3
|
require 'reviewlette/vacations'
|
6
4
|
require 'yaml'
|
7
|
-
require 'octokit'
|
8
|
-
require 'trello'
|
9
5
|
|
10
|
-
|
6
|
+
VERSION = '0.0.7'
|
7
|
+
MEMBERS_CONFIG = YAML.load_file("#{File.dirname(__FILE__)}/../config/members.yml")
|
11
8
|
|
12
|
-
|
13
|
-
@trello_connection = Reviewlette::TrelloConnection.new
|
14
|
-
member_ids.map{|id| @trello_connection.find_member_by_id(id)}
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
module Reviewlette
|
19
|
-
|
20
|
-
attr_accessor :trello_connection, :github_connection, :repo, :board, :db
|
21
|
-
|
22
|
-
TRELLO_CONFIG1 = YAML.load_file("#{File.dirname(__FILE__)}/../config/.trello.yml")
|
23
|
-
|
24
|
-
class << self
|
25
|
-
|
26
|
-
# Execute logic.
|
27
|
-
def spin
|
28
|
-
setup
|
29
|
-
get_available_repos.each do |repo|
|
30
|
-
@repo = repo
|
31
|
-
get_unassigned_github_issues.each do |issue|
|
32
|
-
@number = issue[:number]
|
33
|
-
@title = issue[:title]
|
34
|
-
@body = issue[:body]
|
35
|
-
update_vacations
|
36
|
-
|
37
|
-
if find_card(@title.to_s) and find_id
|
38
|
-
if set_reviewer
|
39
|
-
transform_name
|
40
|
-
add_reviewer_on_github
|
41
|
-
comment_on_github
|
42
|
-
# add_to_trello_card
|
43
|
-
comment_on_trello
|
44
|
-
move_to_list
|
45
|
-
@db.add_pr_to_db(@title, @reviewer.username)
|
46
|
-
@reviewer = nil
|
47
|
-
Reviewlette::Graphgenerator.new.write_to_graphs('graph.html',Reviewlette::Graphgenerator.new.model_graphs(Reviewlette::Database.new.conscruct_line_data.to_json, Reviewlette::Database.new.conscruct_graph_struct.to_json, 'Donut'))
|
48
|
-
else
|
49
|
-
comment_on_error
|
50
|
-
end
|
51
|
-
end
|
52
|
-
puts 'No new issues.' unless @issues.present?
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def get_available_repos
|
58
|
-
@repos = Reviewlette::GithubConnection::GITHUB_CONFIG['repo']
|
59
|
-
end
|
60
|
-
|
61
|
-
# Finds card based on title of Github Issue.
|
62
|
-
# Or by branch name if title does not include the trello number.
|
63
|
-
# Happens if the pullrequest consists of only one commit.
|
64
|
-
def find_card(title)
|
65
|
-
begin
|
66
|
-
match_pr_id_with_issue_id
|
67
|
-
@id = title.split('_').last.to_i
|
68
|
-
@id = fetch_branch if @id == 0 && !(@pullreq_ids.values.index(@number)).nil?
|
69
|
-
raise NoTrelloCardException, "Could not find a Trello card. Found #{title.split('_').last} instead, maybe the naming of your pullrequest is wrong? And/or you dont have a branch?" if @id == 0
|
70
|
-
true
|
71
|
-
rescue NoTrelloCardException => e
|
72
|
-
@logger.error e.message
|
73
|
-
puts (e.message)
|
74
|
-
false
|
75
|
-
end
|
76
|
-
end
|
9
|
+
class Reviewlette
|
77
10
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
83
|
-
end
|
11
|
+
def initialize
|
12
|
+
@github = GithubConnection.new
|
13
|
+
@trello = TrelloConnection.new
|
14
|
+
end
|
84
15
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
16
|
+
def run
|
17
|
+
@github.unassigned_pull_requests.each do |issue|
|
18
|
+
issue_id = issue[:number]
|
19
|
+
issue_title = issue[:title]
|
20
|
+
puts "*** Checking unassigned github pull request: #{issue_title}"
|
21
|
+
card_id = issue_title.split(/[_ -#\.]/).last.to_i
|
22
|
+
if card = @trello.find_card_by_id(card_id)
|
23
|
+
puts "Found matching trello card: #{card.name}"
|
24
|
+
reviewer = select_reviewer(issue, card)
|
25
|
+
if reviewer
|
26
|
+
@github.add_assignee(issue_id, reviewer['github_username'])
|
27
|
+
@github.reviewer_comment(issue_id, reviewer['github_username'], card)
|
28
|
+
comment = "@#{reviewer['trello_username']} will review https://github.com/#{@github.repo}/issues/#{issue_id}"
|
29
|
+
@trello.comment_on_card(comment, card)
|
30
|
+
@trello.move_card_to_list(card, 'In review')
|
91
31
|
else
|
92
|
-
|
32
|
+
puts "Could not find a reviewer for card: #{card.name}"
|
93
33
|
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def parse_vacations
|
98
|
-
split = @vacations.map { |x| x.split(' - ') }
|
99
|
-
split.map { |x| x.map { |b| Date.parse(b) } }
|
100
|
-
end
|
101
|
-
|
102
|
-
# gets the branchname from github pullrequest
|
103
|
-
def fetch_branch
|
104
|
-
pr_id = @pullreq_ids.values.index(@number)
|
105
|
-
branch_name = @github_connection.get_branch_name(pr_id, @repo)
|
106
|
-
branch_name.split('_').last.to_i
|
107
|
-
end
|
108
|
-
|
109
|
-
# Matches Pull Request IDs with the respective Order of PullRequests
|
110
|
-
# to call them and get the branch name.
|
111
|
-
def match_pr_id_with_issue_id
|
112
|
-
@pullreq_ids = {}
|
113
|
-
@counter = 0
|
114
|
-
@github_connection.list_pulls(@repo).each do |x|
|
115
|
-
@pullreq_ids[@counter] = x.number
|
116
|
-
@counter +=1
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# TODO: Generic Error message.
|
121
|
-
def comment_on_error
|
122
|
-
@trello_connection.comment_on_card("Skipped Issue #{@number} because everyone on the team is assigned to the card", @card)
|
123
|
-
end
|
124
|
-
|
125
|
-
# Gets [Array(String, String)] all GitHub Issues that are not assigned to someone.
|
126
|
-
def get_unassigned_github_issues
|
127
|
-
@issues = @github_connection.list_issues(@repo).select{|issue| !issue[:assignee]}
|
128
|
-
end
|
129
|
-
|
130
|
-
# Sets instance variables.
|
131
|
-
def setup
|
132
|
-
@logger = Logger.new('review.log')
|
133
|
-
@db = Reviewlette::Database.new
|
134
|
-
@github_connection = Reviewlette::GithubConnection.new
|
135
|
-
@trello_connection = Reviewlette::TrelloConnection.new
|
136
|
-
@board = Trello::Board.find(TRELLO_CONFIG1['board_id'])
|
137
|
-
end
|
138
|
-
|
139
|
-
# Finds a sets card.
|
140
|
-
def find_id
|
141
|
-
if @id != 0
|
142
|
-
@card = @trello_connection.find_card_by_id(@id)
|
143
|
-
true
|
144
34
|
else
|
145
|
-
|
146
|
-
false
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# Selects and sets reviewer.
|
151
|
-
def set_reviewer
|
152
|
-
begin
|
153
|
-
while !(@reviewer)
|
154
|
-
@reviewer = @trello_connection.determine_reviewer(@card) if @card
|
155
|
-
end
|
156
|
-
@trelloname = @reviewer.username
|
157
|
-
puts "Selected #{@reviewer.username}"
|
158
|
-
return true
|
159
|
-
rescue AlreadyAssignedException => e
|
160
|
-
@logger.warn("Skipped Issue #{@card.short_id} because #{e.message}")
|
161
|
-
puts ("Skipped Issue #{@card.short_id} because #{e.message}")
|
162
|
-
return false
|
35
|
+
puts "No matching card found (id #{card_id})"
|
163
36
|
end
|
164
37
|
end
|
165
38
|
|
166
|
-
|
167
|
-
def transform_name
|
168
|
-
@githubname = @db.find_gh_name_by_trello_name(@trelloname)
|
169
|
-
end
|
170
|
-
|
171
|
-
# Adds Assignee on GitHub.
|
172
|
-
def add_reviewer_on_github
|
173
|
-
@github_connection.add_assignee(@repo, @number, @title, @body, @githubname) if @number && @githubname
|
174
|
-
end
|
175
|
-
|
176
|
-
# Comments on GitHub.
|
177
|
-
def comment_on_github
|
178
|
-
@github_connection.comment_on_issue(@repo, @number, @githubname, @card.url) if @number && @githubname
|
179
|
-
end
|
180
|
-
# Adds Reviewer on Trello Card.
|
181
|
-
def add_to_trello_card
|
182
|
-
@trello_connection.add_reviewer_to_card(@reviewer, @card)
|
183
|
-
end
|
184
|
-
|
185
|
-
# Comments on Trello Card.
|
186
|
-
def comment_on_trello
|
187
|
-
@full_comment = '@' + @trelloname + ' will review ' + 'https://github.com/'+ @repo+'/issues/'+@number.to_s
|
188
|
-
@trello_connection.comment_on_card(@full_comment, @card) if @full_comment
|
189
|
-
end
|
39
|
+
end
|
190
40
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
41
|
+
def select_reviewer(issue, card)
|
42
|
+
reviewers = MEMBERS_CONFIG['members']
|
43
|
+
# remove people on vacation
|
44
|
+
members_on_vacation = Vacations.members_on_vacation
|
45
|
+
reviewers = reviewers.reject{|r| members_on_vacation.include? r['suse_username'] }
|
46
|
+
# remove trello card owner
|
47
|
+
reviewers = reviewers.reject{|r| card.members.map(&:username).include? r['trello_username'] }
|
48
|
+
reviewer = reviewers.sample
|
49
|
+
puts "Selected reviewer: #{reviewer['name']} from pool #{reviewers.map{|r| r['name']}}" if reviewer
|
50
|
+
reviewer
|
201
51
|
end
|
52
|
+
|
202
53
|
end
|
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'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "reviewlette"
|
8
|
-
spec.version =
|
8
|
+
spec.version = 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.}
|
@@ -1,96 +1,41 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe GithubConnection do
|
4
4
|
|
5
|
-
|
5
|
+
GITHUB_CONFIG = { token: '661', repo: 'SUSE/reviewlette' }
|
6
|
+
subject { GithubConnection }
|
7
|
+
let( :connection ) { subject.new }
|
6
8
|
|
7
9
|
describe '.new' do
|
8
10
|
|
9
|
-
it '
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe '#pull_merged?' do
|
17
|
-
let( :connection ) { subject.new }
|
18
|
-
|
19
|
-
it 'checks if the pull is merged' do
|
20
|
-
allow(connection.client).to receive(:pull_merged?).with('true', 6).and_return true
|
21
|
-
expect(connection.pull_merged?('true', 6)).to be true
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'checks if the pull is not merged' do
|
25
|
-
allow(connection.client).to receive(:pull_merged?).with('false', 5).and_return false
|
26
|
-
expect(connection.pull_merged?('false', 5)).to be false
|
11
|
+
it 'initializes octokit client and repo' do
|
12
|
+
expect(Octokit::Client).to receive(:new).with(:access_token => GITHUB_CONFIG['token'])
|
13
|
+
connection = subject.new
|
14
|
+
expect(connection.repo).to eq(GITHUB_CONFIG['repo'])
|
27
15
|
end
|
28
16
|
end
|
29
17
|
|
30
18
|
describe '#add_assignee' do
|
31
|
-
let( :connection ) { subject.new }
|
32
|
-
|
33
19
|
it 'adds an assignee to the gh issue' do
|
34
|
-
|
35
|
-
|
36
|
-
allow(connection.client).to receive(:update_issue).with(*params2).and_return true
|
37
|
-
expect(connection.add_assignee(*params)).to eq true
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'fails to add an assignee to the gh issue' do
|
41
|
-
params = [connection.repo, 4, 'title', 'body', 'name']
|
42
|
-
params2 = [connection.repo, 4, 'title', 'body', :assignee => 'name']
|
43
|
-
allow(connection.client).to receive(:update_issue).with(*params2).and_return false
|
44
|
-
expect(connection.add_assignee(*params)).to eq false
|
20
|
+
expect(connection.client).to receive(:update_issue).with(connection.repo, 11, :assignee => 'test')
|
21
|
+
connection.add_assignee(11, 'test')
|
45
22
|
end
|
46
23
|
end
|
47
24
|
|
48
|
-
describe '#
|
49
|
-
let( :connection ) { subject.new }
|
50
|
-
|
25
|
+
describe '#reviewer_comment' do
|
51
26
|
it 'comments on a given issue' do
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'fails to comment on a given issue and fails' do
|
59
|
-
params = [connection.repo, 4, '@name is your reviewer :thumbsup: check url']
|
60
|
-
params2 = [connection.repo, 4, 'name', 'url']
|
61
|
-
allow(connection.client).to receive(:add_comment).with(*params).and_return false
|
62
|
-
expect(connection.comment_on_issue(*params2)).to eq false
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
describe '#list_issues' do
|
67
|
-
let( :connection ) { subject.new }
|
68
|
-
|
69
|
-
it 'fails to determine if an assignee is set' do
|
70
|
-
allow(connection.client).to receive_message_chain(:list_issues)
|
71
|
-
connection.list_issues(connection.repo)
|
27
|
+
card = Trello::Card.new
|
28
|
+
allow(card).to receive(:url).and_return('url')
|
29
|
+
expect(connection.client).to receive(:add_comment).with(connection.repo, 11, anything)
|
30
|
+
connection.reviewer_comment(11, 'test', card)
|
72
31
|
end
|
73
32
|
end
|
74
33
|
|
75
34
|
describe '#list_pulls' do
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
expect(connection.client).to receive(:pull_requests)
|
80
|
-
connection.list_pulls(connection.repo)
|
35
|
+
it 'lists all pullrequests for a given repository' do
|
36
|
+
expect(connection.client).to receive(:pull_requests).with(connection.repo)
|
37
|
+
connection.list_pulls
|
81
38
|
end
|
82
39
|
end
|
83
40
|
|
84
|
-
describe '#get_branch_name' do
|
85
|
-
let( :connection ) { subject.new }
|
86
|
-
|
87
|
-
it 'get branch name based on a repo and a pullrequest id' do
|
88
|
-
pulls = [double({ 'head' => double({ 'ref' => 'number'})})]
|
89
|
-
pr = pulls.first
|
90
|
-
expect(connection.client).to receive(:pull_requests).with(connection.repo).and_return pulls
|
91
|
-
expect(pulls).to receive(:[]).with(3).and_return pr
|
92
|
-
expect(pr).to receive(:head).and_return pr.head
|
93
|
-
connection.get_branch_name(3, connection.repo)
|
94
|
-
end
|
95
|
-
end
|
96
41
|
end
|