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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc2e0db8f1f84d6d27f7057eecdb21a24aab3f7e
|
4
|
+
data.tar.gz: b7e681c5a4954a09144b509b5434a649b9c378a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21647bb1f08a246343b1c3cb8920a668f87cbe2c461affaeceec60bb57f3d2c0f1c39357c4bcf77ae0419ff150a46ff8f6db9f21842c175cd5a3731f04af12ed
|
7
|
+
data.tar.gz: f4e2ac2ca8900f6a195d284d32e6e001751ee79528f8d0bbfdf899334f8e54e5bde6d96388892cc741cd2e928cfc8af743c512e1d1091eeb139cc59530a38791
|
data/.dockerignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/config/
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,24 +1,21 @@
|
|
1
1
|
source 'http://rubygems.org'
|
2
2
|
|
3
|
-
|
4
|
-
gem 'haml'
|
5
|
-
gem 'octokit', '~> 3.8.0'
|
6
|
-
gem 'ruby-trello'
|
7
|
-
gem 'rdoc'
|
8
|
-
gem 'rspec'
|
9
|
-
gem 'webmock'
|
10
|
-
gem 'rake'
|
11
|
-
gem 'ap'
|
12
|
-
gem 'byebug'
|
13
|
-
gem 'simplecov'
|
14
|
-
gem 'prophet'
|
15
|
-
gem 'coveralls'
|
16
|
-
gem 'sequel'
|
17
|
-
gem 'sqlite3'
|
3
|
+
gemspec
|
18
4
|
|
5
|
+
group :development, :test do
|
6
|
+
gem 'ap'
|
7
|
+
gem 'rake'
|
8
|
+
gem 'debugger-linecache'
|
9
|
+
gem 'byebug'
|
10
|
+
end
|
19
11
|
|
20
|
-
group :
|
12
|
+
group :test do
|
13
|
+
gem 'rspec'
|
14
|
+
gem 'webmock'
|
21
15
|
gem 'guard'
|
22
16
|
gem 'guard-rspec'
|
23
17
|
gem 'libnotify'
|
18
|
+
gem 'simplecov'
|
19
|
+
gem 'coveralls'
|
20
|
+
gem 'rdoc'
|
24
21
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,42 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
reviewlette (1.0.0)
|
5
|
+
octokit
|
6
|
+
ruby-trello
|
7
|
+
|
1
8
|
GEM
|
2
9
|
remote: http://rubygems.org/
|
3
10
|
specs:
|
4
|
-
activemodel (
|
5
|
-
activesupport (=
|
6
|
-
|
7
|
-
|
8
|
-
i18n (~> 0.
|
9
|
-
json (~> 1.7, >= 1.7.7)
|
11
|
+
activemodel (5.0.0.1)
|
12
|
+
activesupport (= 5.0.0.1)
|
13
|
+
activesupport (5.0.0.1)
|
14
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
+
i18n (~> 0.7)
|
10
16
|
minitest (~> 5.1)
|
11
|
-
thread_safe (~> 0.1)
|
12
17
|
tzinfo (~> 1.1)
|
13
|
-
addressable (2.
|
18
|
+
addressable (2.5.0)
|
19
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
14
20
|
ap (0.1.1)
|
15
21
|
httparty (>= 0.7.7)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
simplecov (>= 0.7)
|
27
|
-
term-ansicolor
|
28
|
-
thor
|
29
|
-
crack (0.4.2)
|
22
|
+
byebug (9.0.6)
|
23
|
+
coderay (1.1.1)
|
24
|
+
concurrent-ruby (1.0.2)
|
25
|
+
coveralls (0.8.17)
|
26
|
+
json (>= 1.8, < 3)
|
27
|
+
simplecov (~> 0.12.0)
|
28
|
+
term-ansicolor (~> 1.3)
|
29
|
+
thor (~> 0.19.1)
|
30
|
+
tins (~> 1.6)
|
31
|
+
crack (0.4.3)
|
30
32
|
safe_yaml (~> 1.0.0)
|
33
|
+
debugger-linecache (1.2.0)
|
31
34
|
diff-lcs (1.2.5)
|
32
|
-
docile (1.1.
|
33
|
-
|
35
|
+
docile (1.1.5)
|
36
|
+
domain_name (0.5.20161129)
|
37
|
+
unf (>= 0.0.5, < 1.0.0)
|
38
|
+
faraday (0.10.0)
|
34
39
|
multipart-post (>= 1.2, < 3)
|
35
|
-
ffi (1.9.
|
40
|
+
ffi (1.9.14)
|
36
41
|
formatador (0.2.5)
|
37
|
-
guard (2.
|
42
|
+
guard (2.14.0)
|
38
43
|
formatador (>= 0.2.4)
|
39
|
-
listen (
|
44
|
+
listen (>= 2.7, < 4.0)
|
40
45
|
lumberjack (~> 1.0)
|
41
46
|
nenv (~> 0.1)
|
42
47
|
notiffany (~> 0.0)
|
@@ -44,97 +49,96 @@ GEM
|
|
44
49
|
shellany (~> 0.0)
|
45
50
|
thor (>= 0.18.1)
|
46
51
|
guard-compat (1.2.1)
|
47
|
-
guard-rspec (4.
|
52
|
+
guard-rspec (4.7.3)
|
48
53
|
guard (~> 2.1)
|
49
54
|
guard-compat (~> 1.1)
|
50
55
|
rspec (>= 2.99.0, < 4.0)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
httparty (0.
|
55
|
-
json (~> 1.8)
|
56
|
+
hashdiff (0.3.1)
|
57
|
+
http-cookie (1.0.3)
|
58
|
+
domain_name (~> 0.5)
|
59
|
+
httparty (0.14.0)
|
56
60
|
multi_xml (>= 0.5.2)
|
57
|
-
i18n (0.
|
58
|
-
json (
|
61
|
+
i18n (0.7.0)
|
62
|
+
json (2.0.2)
|
59
63
|
libnotify (0.9.1)
|
60
64
|
ffi (>= 1.0.11)
|
61
|
-
listen (
|
62
|
-
|
63
|
-
rb-
|
64
|
-
|
65
|
-
lumberjack (1.0.
|
65
|
+
listen (3.1.5)
|
66
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
67
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
68
|
+
ruby_dep (~> 1.2)
|
69
|
+
lumberjack (1.0.10)
|
66
70
|
method_source (0.8.2)
|
67
|
-
mime-types (2.3)
|
68
|
-
minitest (5.
|
69
|
-
|
70
|
-
multi_xml (0.5.5)
|
71
|
+
mime-types (2.99.3)
|
72
|
+
minitest (5.10.1)
|
73
|
+
multi_xml (0.6.0)
|
71
74
|
multipart-post (2.0.0)
|
72
|
-
nenv (0.
|
73
|
-
|
75
|
+
nenv (0.3.0)
|
76
|
+
netrc (0.11.0)
|
77
|
+
notiffany (0.1.1)
|
74
78
|
nenv (~> 0.1)
|
75
79
|
shellany (~> 0.0)
|
76
|
-
oauth (0.
|
77
|
-
octokit (
|
78
|
-
sawyer (~> 0.
|
79
|
-
|
80
|
-
octokit
|
81
|
-
rspec
|
82
|
-
pry (0.10.1)
|
80
|
+
oauth (0.5.1)
|
81
|
+
octokit (4.6.2)
|
82
|
+
sawyer (~> 0.8.0, >= 0.5.3)
|
83
|
+
pry (0.10.4)
|
83
84
|
coderay (~> 1.1.0)
|
84
85
|
method_source (~> 0.8.1)
|
85
86
|
slop (~> 3.4)
|
86
|
-
|
87
|
-
|
88
|
-
rb-
|
87
|
+
public_suffix (2.0.4)
|
88
|
+
rake (12.0.0)
|
89
|
+
rb-fsevent (0.9.8)
|
90
|
+
rb-inotify (0.9.7)
|
89
91
|
ffi (>= 0.5.0)
|
90
|
-
rdoc (
|
91
|
-
|
92
|
-
|
93
|
-
mime-types (>= 1.16)
|
94
|
-
|
95
|
-
|
96
|
-
rspec-
|
97
|
-
rspec-
|
98
|
-
|
99
|
-
|
100
|
-
|
92
|
+
rdoc (5.0.0)
|
93
|
+
rest-client (1.8.0)
|
94
|
+
http-cookie (>= 1.0.2, < 2.0)
|
95
|
+
mime-types (>= 1.16, < 3.0)
|
96
|
+
netrc (~> 0.7)
|
97
|
+
rspec (3.5.0)
|
98
|
+
rspec-core (~> 3.5.0)
|
99
|
+
rspec-expectations (~> 3.5.0)
|
100
|
+
rspec-mocks (~> 3.5.0)
|
101
|
+
rspec-core (3.5.4)
|
102
|
+
rspec-support (~> 3.5.0)
|
103
|
+
rspec-expectations (3.5.0)
|
104
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
105
|
+
rspec-support (~> 3.5.0)
|
106
|
+
rspec-mocks (3.5.0)
|
101
107
|
diff-lcs (>= 1.2.0, < 2.0)
|
102
|
-
rspec-support (~> 3.
|
103
|
-
rspec-
|
104
|
-
|
105
|
-
rspec-support (3.0.0)
|
106
|
-
ruby-trello (1.1.1)
|
108
|
+
rspec-support (~> 3.5.0)
|
109
|
+
rspec-support (3.5.0)
|
110
|
+
ruby-trello (1.5.1)
|
107
111
|
activemodel (>= 3.2.0)
|
108
112
|
addressable (~> 2.3)
|
109
113
|
json
|
110
|
-
oauth (
|
111
|
-
rest-client (~> 1.
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
114
|
+
oauth (>= 0.4.5)
|
115
|
+
rest-client (~> 1.8.0)
|
116
|
+
ruby_dep (1.5.0)
|
117
|
+
safe_yaml (1.0.4)
|
118
|
+
sawyer (0.8.1)
|
119
|
+
addressable (>= 2.3.5, < 2.6)
|
120
|
+
faraday (~> 0.8, < 1.0)
|
117
121
|
shellany (0.0.1)
|
118
|
-
simplecov (0.
|
122
|
+
simplecov (0.12.0)
|
119
123
|
docile (~> 1.1.0)
|
120
|
-
|
121
|
-
simplecov-html (~> 0.
|
122
|
-
simplecov-html (0.
|
124
|
+
json (>= 1.8, < 3)
|
125
|
+
simplecov-html (~> 0.10.0)
|
126
|
+
simplecov-html (0.10.0)
|
123
127
|
slop (3.6.0)
|
124
|
-
|
125
|
-
term-ansicolor (1.3.0)
|
128
|
+
term-ansicolor (1.4.0)
|
126
129
|
tins (~> 1.0)
|
127
|
-
thor (0.19.
|
128
|
-
thread_safe (0.3.
|
129
|
-
|
130
|
-
|
131
|
-
hitimes
|
132
|
-
tins (1.1.0)
|
133
|
-
tzinfo (1.2.1)
|
130
|
+
thor (0.19.4)
|
131
|
+
thread_safe (0.3.5)
|
132
|
+
tins (1.13.0)
|
133
|
+
tzinfo (1.2.2)
|
134
134
|
thread_safe (~> 0.1)
|
135
|
-
|
135
|
+
unf (0.1.4)
|
136
|
+
unf_ext
|
137
|
+
unf_ext (0.0.7.2)
|
138
|
+
webmock (2.3.1)
|
136
139
|
addressable (>= 2.3.6)
|
137
140
|
crack (>= 0.3.2)
|
141
|
+
hashdiff
|
138
142
|
|
139
143
|
PLATFORMS
|
140
144
|
ruby
|
@@ -143,21 +147,16 @@ DEPENDENCIES
|
|
143
147
|
ap
|
144
148
|
byebug
|
145
149
|
coveralls
|
150
|
+
debugger-linecache
|
146
151
|
guard
|
147
152
|
guard-rspec
|
148
|
-
haml
|
149
|
-
json
|
150
153
|
libnotify
|
151
|
-
octokit (~> 3.8.0)
|
152
|
-
prophet
|
153
154
|
rake
|
154
155
|
rdoc
|
156
|
+
reviewlette!
|
155
157
|
rspec
|
156
|
-
ruby-trello
|
157
|
-
sequel
|
158
158
|
simplecov
|
159
|
-
sqlite3
|
160
159
|
webmock
|
161
160
|
|
162
161
|
BUNDLED WITH
|
163
|
-
1.
|
162
|
+
1.13.6
|
data/README.md
CHANGED
@@ -1,43 +1,43 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
[](https://coveralls.io/r/jschmid1/reviewlette)
|
5
|
-
[](https://codeclimate.com/github/jschmid1/reviewlette)
|
6
|
-
|
7
|
-
Tool to automatically assign a "Reviewer" to a GitHub Issue and to the attached Trello Card.
|
1
|
+
[](https://codeclimate.com/github/SUSE/reviewlette)
|
2
|
+
[](https://travis-ci.org/SUSE/reviewlette)
|
8
3
|
|
4
|
+
# Reviewlette
|
5
|
+
Tool to automatically assign reviewers to GitHub pull requests and to move and comment on their Trello cards.
|
9
6
|
|
10
7
|
What it does:
|
11
8
|
|
12
|
-
- Finds
|
13
|
-
- Assigns
|
14
|
-
- Locates the right
|
15
|
-
-
|
16
|
-
-
|
17
|
-
- Move the card to 'In review'
|
18
|
-
|
9
|
+
- Finds pull requests with missing reviewers in your GitHub repos.
|
10
|
+
- Assigns random members of your team.
|
11
|
+
- Locates the right card in your Trello board.
|
12
|
+
- Mentions the assigned reviewer in a comment on the card.
|
13
|
+
- Moves the card to the 'In review' column.
|
19
14
|
|
20
15
|
## Installation
|
16
|
+
For the latest and greatest version you should `git clone https://github.com/SUSE/reviewlette`
|
21
17
|
|
18
|
+
## Usage
|
19
|
+
```ruby
|
20
|
+
Reviewlette.new(members: User.all, github_config: {}, trello_config: {}).run
|
22
21
|
```
|
23
|
-
gem install reviewlette
|
24
|
-
reviewlette
|
25
|
-
```
|
26
|
-
|
27
22
|
|
28
|
-
|
23
|
+
Users must respond to `trello_handle` and `github_handle` methods.
|
29
24
|
|
30
|
-
|
31
|
-
#### Review_#23_name_of_review_42 <= trello card number
|
25
|
+
Examples for `github_config` and `trello_config` can be found in `config/`.
|
32
26
|
|
33
|
-
|
34
|
-
|
27
|
+
### Matching Trello cards
|
28
|
+
To match a Trello card to a pull request, its title has to end with the card number (not the id)
|
35
29
|
|
30
|
+
#### Example:
|
36
31
|
|
37
|
-
|
32
|
+
URL of the Trello card: _https://trello.com/c/cardid/4242-fix-everything_
|
38
33
|
|
39
|
-
|
40
|
-
[Using ruby-trello as a Trello api wrapper](https://github.com/jeremytregunna/ruby-trello)
|
34
|
+
Pull request title should be: `Fix almost everything 4242`
|
41
35
|
|
36
|
+
__Note:__ Pull requests without a matching Trello card get skipped and won't be assigned to a reviewer.
|
42
37
|
|
38
|
+
### Labels
|
39
|
+
You can tweak Reviewlette's behavior by adding special labels to your pull request:
|
43
40
|
|
41
|
+
| Label | Description |
|
42
|
+
|-------------|----------------------|
|
43
|
+
| 2 reviewers | Assign two reviewers |
|
data/config/github_example.yml
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
# generate the token here: https://github.com/settings/tokens/new
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
"SUSE/scc-provisioning", "SUSE/scc-token", "SUSE/TeamDashboard" ]
|
1
|
+
token: # generate the token here: https://github.com/settings/tokens/new
|
2
|
+
repos:
|
3
|
+
- user/repo1
|
4
|
+
- org/repo2
|
data/lib/reviewlette.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
require 'reviewlette/trello_connection'
|
2
2
|
require 'reviewlette/github_connection'
|
3
|
-
require 'reviewlette/vacations'
|
4
3
|
require 'yaml'
|
5
4
|
|
6
|
-
VERSION = '0.0.9'
|
7
|
-
|
8
5
|
class Reviewlette
|
9
|
-
def initialize
|
10
|
-
@trello = TrelloConnection.new
|
11
|
-
@
|
12
|
-
@
|
6
|
+
def initialize(members:, github_config: nil, trello_config: nil)
|
7
|
+
@trello = TrelloConnection.new(trello_config)
|
8
|
+
@github = github_config || YAML.load_file("#{File.dirname(__FILE__)}/../config/github.yml")
|
9
|
+
@members = members
|
13
10
|
end
|
14
11
|
|
15
12
|
def run
|
@@ -27,12 +24,20 @@ class Reviewlette
|
|
27
24
|
return
|
28
25
|
end
|
29
26
|
|
30
|
-
repo.
|
31
|
-
issue_id
|
27
|
+
repo.pull_requests.each do |issue|
|
28
|
+
issue_id = issue[:number]
|
32
29
|
issue_title = issue[:title]
|
30
|
+
issue_labels = repo.labels(issue_id)
|
31
|
+
|
32
|
+
puts "*** Checking GitHub pull request: #{issue_title}"
|
33
|
+
matched = issue_title.match(/\d+[_'"]?$/)
|
34
|
+
|
35
|
+
unless matched
|
36
|
+
puts 'Pull request not assigned to a trello card'
|
37
|
+
next
|
38
|
+
end
|
33
39
|
|
34
|
-
|
35
|
-
card_id = issue_title.split(/[_ -#\.]/).last.to_i
|
40
|
+
card_id = matched[0].to_i
|
36
41
|
card = @trello.find_card_by_id(card_id)
|
37
42
|
|
38
43
|
unless card
|
@@ -41,35 +46,38 @@ class Reviewlette
|
|
41
46
|
end
|
42
47
|
|
43
48
|
puts "Found matching trello card: #{card.name}"
|
44
|
-
reviewer = select_reviewer(issue, card)
|
45
49
|
|
46
|
-
|
47
|
-
|
48
|
-
|
50
|
+
assignees = issue[:assignees].map(&:login)
|
51
|
+
already_assigned_members = @members.select { |m| assignees.include? m.github_handle }
|
52
|
+
wanted_number = how_many_should_review(issue_labels)
|
53
|
+
|
54
|
+
if assignees.size < wanted_number
|
55
|
+
reviewers = select_reviewers(card, wanted_number, already_assigned_members)
|
56
|
+
if reviewers.empty?
|
57
|
+
puts "Could not find a reviewer for card: #{card.name}"
|
58
|
+
next
|
59
|
+
end
|
60
|
+
repo.add_assignees(issue_id, reviewers.map { |r| r.github_handle } )
|
61
|
+
repo.comment_reviewers(issue_id, reviewers, card)
|
62
|
+
@trello.comment_reviewers(card, repo_name, issue_id, reviewers)
|
63
|
+
@trello.move_card_to_list(card, 'In review')
|
64
|
+
already_assigned_members
|
49
65
|
end
|
50
66
|
|
51
|
-
repo.add_assignee(issue_id, reviewer['github_username'])
|
52
|
-
repo.reviewer_comment(issue_id, reviewer['github_username'], card)
|
53
|
-
comment = "@#{reviewer['trello_username']} will review https://github.com/#{repo_name}/issues/#{issue_id}"
|
54
67
|
|
55
|
-
@trello.comment_on_card(comment, card)
|
56
|
-
@trello.move_card_to_list(card, 'In review')
|
57
68
|
end
|
58
69
|
end
|
59
70
|
|
60
|
-
def
|
61
|
-
reviewers = @members
|
62
|
-
|
63
|
-
|
64
|
-
members_on_vacation = Vacations.members_on_vacation(reviewers)
|
71
|
+
def select_reviewers(card, number = 1, already_assigned = [])
|
72
|
+
reviewers = @members
|
73
|
+
reviewers.reject! { |r| card.members.map(&:username).include? r.trello_handle }
|
74
|
+
reviewers -= already_assigned
|
65
75
|
|
66
|
-
reviewers
|
67
|
-
|
68
|
-
# remove trello card owner
|
69
|
-
reviewers = reviewers.reject {|r| card.members.map(&:username).include? r['trello_username'] }
|
70
|
-
reviewer = reviewers.sample
|
71
|
-
puts "Selected reviewer: #{reviewer['name']} from pool #{reviewers.map {|r| r['name'] }}" if reviewer
|
72
|
-
reviewer
|
76
|
+
reviewers.sample(number - already_assigned.size) + already_assigned
|
73
77
|
end
|
74
78
|
|
79
|
+
def how_many_should_review(labels)
|
80
|
+
return 2 if labels.include? '2 reviewers'
|
81
|
+
1
|
82
|
+
end
|
75
83
|
end
|