reviewlette 0.0.6 → 0.0.7
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/.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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa4d4a0eb15ee9feae3c0d1d10cea567af2f2ffe
|
4
|
+
data.tar.gz: 84e46cc35612094c580654a48c5cd03eec633bb0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 104f9629561f1e3f329eebc6823810dcc25174e24b412132e5f297538b51c7ce2ebc76378e1583964619fbd59f1ec8d661ed41711cabbb974209cfc3872d93d7
|
7
|
+
data.tar.gz: dd5b12654663ed8a7aca64d2998157365bb250f2f6582cbbe3c207a2f7d94546ae899fe1d3b44c0d8851d97d94e06c38f1a806a5178f4d6492128691edbace98
|
data/.gitignore
CHANGED
@@ -2,14 +2,8 @@
|
|
2
2
|
*.db
|
3
3
|
*.log
|
4
4
|
*.html
|
5
|
-
database
|
6
|
-
*.yml~
|
7
5
|
.idea
|
8
|
-
/.idea
|
9
|
-
.idea*
|
10
|
-
/.idea/*
|
11
6
|
*.rbc
|
12
|
-
*.yml
|
13
7
|
.bundle
|
14
8
|
coverage
|
15
9
|
.swp
|
@@ -25,3 +19,7 @@ tmp
|
|
25
19
|
_yardoc
|
26
20
|
rdoc/
|
27
21
|
doc/
|
22
|
+
config/github.yml
|
23
|
+
config/trello.yml
|
24
|
+
config/members.yml
|
25
|
+
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -10,7 +10,7 @@ GEM
|
|
10
10
|
minitest (~> 5.1)
|
11
11
|
thread_safe (~> 0.1)
|
12
12
|
tzinfo (~> 1.1)
|
13
|
-
addressable (2.3.
|
13
|
+
addressable (2.3.8)
|
14
14
|
ap (0.1.1)
|
15
15
|
httparty (>= 0.7.7)
|
16
16
|
builder (3.2.2)
|
@@ -27,7 +27,7 @@ GEM
|
|
27
27
|
safe_yaml (~> 1.0.0)
|
28
28
|
diff-lcs (1.2.5)
|
29
29
|
docile (1.1.3)
|
30
|
-
faraday (0.9.
|
30
|
+
faraday (0.9.1)
|
31
31
|
multipart-post (>= 1.2, < 3)
|
32
32
|
haml (4.0.5)
|
33
33
|
tilt
|
@@ -42,8 +42,8 @@ GEM
|
|
42
42
|
multi_xml (0.5.5)
|
43
43
|
multipart-post (2.0.0)
|
44
44
|
oauth (0.4.7)
|
45
|
-
octokit (3.
|
46
|
-
sawyer (~> 0.5.3)
|
45
|
+
octokit (3.8.0)
|
46
|
+
sawyer (~> 0.6.0, >= 0.5.3)
|
47
47
|
prophet (1.5.5)
|
48
48
|
octokit
|
49
49
|
rspec
|
@@ -71,7 +71,7 @@ GEM
|
|
71
71
|
oauth (~> 0.4.5)
|
72
72
|
rest-client (~> 1.6.7)
|
73
73
|
safe_yaml (1.0.3)
|
74
|
-
sawyer (0.
|
74
|
+
sawyer (0.6.0)
|
75
75
|
addressable (~> 2.3.5)
|
76
76
|
faraday (~> 0.8, < 0.10)
|
77
77
|
sequel (4.13.0)
|
@@ -102,7 +102,7 @@ DEPENDENCIES
|
|
102
102
|
coveralls
|
103
103
|
haml
|
104
104
|
json
|
105
|
-
octokit (~> 3.0)
|
105
|
+
octokit (~> 3.8.0)
|
106
106
|
prophet
|
107
107
|
rake
|
108
108
|
rdoc
|
data/README.md
CHANGED
@@ -10,31 +10,18 @@ Tool to automatically assign a "Reviewer" to a GitHub Issue and to the attached
|
|
10
10
|
What it does:
|
11
11
|
|
12
12
|
- Finds unassigned issues on GitHub.
|
13
|
-
-
|
13
|
+
- Assigns a member of your team.
|
14
14
|
- Locates the right Card on Trello.
|
15
15
|
- Checks if the assignee is on vacation(using tel).
|
16
16
|
- Adds the assigned member to the Card.
|
17
|
-
-
|
18
|
-
- Prints graphs using Morris.js to display statistics(autorefresh every 5 seconds).
|
19
|
-
|
20
|
-
|
21
|
-

|
17
|
+
- Move the card to 'In review'
|
22
18
|
|
23
19
|
|
24
20
|
## Installation
|
25
21
|
|
26
|
-
```
|
27
|
-
git clone git@github.com:jschmid1/reviewlette.git
|
28
|
-
cd reviewlette
|
29
|
-
bundle
|
30
|
-
cd bin
|
31
|
-
./reviewlette
|
32
|
-
```
|
33
|
-
|
34
|
-
or
|
35
|
-
|
36
22
|
```
|
37
23
|
gem install reviewlette
|
24
|
+
reviewlette
|
38
25
|
```
|
39
26
|
|
40
27
|
|
@@ -43,52 +30,13 @@ gem install reviewlette
|
|
43
30
|
#### Name your pullrequest like so:
|
44
31
|
#### Review_#23_name_of_review_42 <= trello card number
|
45
32
|
|
46
|
-
Fill `config/.trello.yml`
|
47
|
-
|
48
|
-
```yml
|
49
|
-
-comsumerkey: theconsumerkey11
|
50
|
-
-consumersecret: theconsumersecret11
|
51
|
-
-oauthtoken: theoauthtoken11
|
52
|
-
```
|
53
|
-
|
54
|
-
[Which can be generated here](https://trello.com/1/appKey/generate)
|
55
|
-
|
56
|
-
Fill `config/.github.yml` with your **token** and **repo**
|
57
|
-
|
58
|
-
```yml
|
59
|
-
-token: thetokenfromgithub
|
60
|
-
-repo: ['my/repo', 'my/otherrepo']
|
61
|
-
```
|
62
|
-
|
63
|
-
[Which can be generated here](https://github.com/settings/applications/new)
|
33
|
+
Fill `config/.trello.yml` (instructions in the file)
|
34
|
+
Fill `config/.github.yml` (instructions in the file
|
64
35
|
|
65
36
|
|
66
|
-
Edit the `reviewlette.db` scaffold in the main directory to your needs.
|
67
|
-
|
68
|
-
Structure:
|
69
|
-
|
70
|
-
| primary_key | first_name | last_name | Reviews_count | created_at | github_name | trello_name | vacation_status | tel_name |
|
71
|
-
|:-------------:|:-------------: |:-------------:|:-------------: |:-------------:|:-------------:|:-------------:|:-------------: |:-------------:|
|
72
|
-
| Integer(PK) | Text | Text | Integer | Text | Text |Text | Numeric| Text|
|
73
|
-
| 1 | Joshua | Schmid | 30 | 2014-01-01 | jschmid1 |jschmid1 | false | jschmid|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
You can either use a GUI like [Sqlite database browser](http://sqlitebrowser.org/) or the sqlite commandline interface
|
79
|
-
|
80
|
-
e.g.
|
81
|
-
|
82
|
-
```ruby
|
83
|
-
insert into reviewer values('John','Smith', '0', '', 'github_name', 'trello_name', 'false', 'tel_name');
|
84
|
-
```
|
85
|
-
|
86
37
|
---
|
87
38
|
|
88
39
|
[Using Octokit as a GitHub api wrapper](https://github.com/octokit/octokit.rb)
|
89
|
-
|
90
|
-
[Using Sequel as Database Module](https://github.com/jeremyevans/sequel)
|
91
|
-
|
92
40
|
[Using ruby-trello as a Trello api wrapper](https://github.com/jeremytregunna/ruby-trello)
|
93
41
|
|
94
42
|
|
data/Rakefile
CHANGED
@@ -2,4 +2,16 @@ require 'rspec/core/rake_task'
|
|
2
2
|
|
3
3
|
RSpec::Core::RakeTask.new(:spec)
|
4
4
|
|
5
|
-
task :default => :spec
|
5
|
+
task :default => :spec
|
6
|
+
|
7
|
+
desc 'Run console loaded with gem'
|
8
|
+
task :console do
|
9
|
+
require 'irb'
|
10
|
+
require 'irb/completion'
|
11
|
+
require 'byebug'
|
12
|
+
require 'awesome_print'
|
13
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
|
14
|
+
require 'reviewlette'
|
15
|
+
ARGV.clear
|
16
|
+
IRB.start
|
17
|
+
end
|
data/bin/reviewlette
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
members:
|
2
|
+
- name: Tom
|
3
|
+
suse_username: tschmidt
|
4
|
+
trello_username: thomasschmidt
|
5
|
+
github_username: digitaltom
|
6
|
+
- name: Artem
|
7
|
+
suse_username: achernikov
|
8
|
+
trello_username: artemchernikov
|
9
|
+
github_username: kalabiyau
|
10
|
+
- name: Kirill
|
11
|
+
suse_username: kpimenov
|
12
|
+
trello_username: kirillpimenov
|
13
|
+
github_username: kirushik
|
14
|
+
- name: Vlad
|
15
|
+
suse_username: vlewin
|
16
|
+
trello_username: vlewin
|
17
|
+
github_username: vlewin
|
18
|
+
- name: Will
|
19
|
+
suse_username: wstephenson
|
20
|
+
trello_username: wstephenson
|
21
|
+
github_username: wstephenson
|
22
|
+
- name: Nadja
|
23
|
+
suse_username: nwalter
|
24
|
+
trello_username: nadjaw2
|
25
|
+
github_username: nadjaw
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# Get your trello keys here: https://trello.com/app-key
|
2
|
+
consumerkey:
|
3
|
+
|
4
|
+
# request the token here:
|
5
|
+
# https://trello.com/1/authorize?key=<key from above>&name=reviewlette&expiration=never&response_type=token&scope=read,write
|
6
|
+
oauthtoken:
|
7
|
+
|
8
|
+
# The board_id can be read from the url of the board.
|
9
|
+
board_id:
|
@@ -1,45 +1,40 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'octokit'
|
3
3
|
|
4
|
-
|
4
|
+
GITHUB_CONFIG = YAML.load_file("#{File.dirname(__FILE__)}/../../config/github.yml")
|
5
5
|
|
6
|
-
|
6
|
+
class GithubConnection
|
7
7
|
|
8
|
-
|
8
|
+
attr_accessor :client, :repo
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def gh_connection
|
17
|
-
@client = Octokit::Client.new(:access_token => GITHUB_CONFIG['token'])
|
18
|
-
end
|
19
|
-
|
20
|
-
def get_branch_name(pr_id, repo)
|
21
|
-
@client.pull_requests(repo)[pr_id].head.ref
|
22
|
-
end
|
23
|
-
|
24
|
-
def list_pulls(repo)
|
25
|
-
@client.pull_requests(repo)
|
26
|
-
end
|
27
|
-
|
28
|
-
def pull_merged?(repo, number)
|
29
|
-
client.pull_merged?(repo, number)
|
30
|
-
end
|
10
|
+
def initialize
|
11
|
+
@client = Octokit::Client.new(:access_token => GITHUB_CONFIG['token'])
|
12
|
+
@repo = GITHUB_CONFIG['repo']
|
13
|
+
end
|
31
14
|
|
32
|
-
|
33
|
-
|
34
|
-
|
15
|
+
def list_pulls
|
16
|
+
@client.pull_requests(@repo)
|
17
|
+
end
|
35
18
|
|
36
|
-
|
37
|
-
|
38
|
-
|
19
|
+
def add_assignee(number, assignee)
|
20
|
+
@client.update_issue(@repo, number, assignee: assignee)
|
21
|
+
end
|
39
22
|
|
40
|
-
|
41
|
-
|
42
|
-
|
23
|
+
def reviewer_comment(number, assignee, trello_card)
|
24
|
+
comment = "@#{assignee} is your reviewer :dancers: check #{trello_card.url} \n" \
|
25
|
+
"@#{assignee}: Please review this pull request using our guidelines: \n" \
|
26
|
+
"* test for acceptance criteria / functionality \n" \
|
27
|
+
"* check if the new code is covered with tests \n" \
|
28
|
+
"* check for unintended consequences \n" \
|
29
|
+
"* encourage usage of the boyscout rule \n" \
|
30
|
+
"* make sure the code is architected in the best way \n" \
|
31
|
+
"* check that no unnecessary technical debt got introduced \n" \
|
32
|
+
"* make sure that no unnecessary FIXMEs or TODOs got added \n"
|
33
|
+
@client.add_comment(@repo, number, comment)
|
34
|
+
end
|
43
35
|
|
36
|
+
def unassigned_pull_requests
|
37
|
+
list_pulls.select { |issue| !issue[:assignee] }
|
44
38
|
end
|
45
|
-
|
39
|
+
|
40
|
+
end
|
@@ -1,79 +1,45 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'trello'
|
3
|
-
require 'logger'
|
4
|
-
require_relative 'database'
|
5
|
-
require_relative 'exceptions'
|
6
3
|
|
7
|
-
|
4
|
+
TRELLO_CONFIG = YAML.load_file("#{File.dirname(__FILE__)}/../../config/trello.yml")
|
8
5
|
|
9
|
-
|
10
|
-
@trello_connection = ::Reviewlette::TrelloConnection.new
|
11
|
-
member_ids.map{|id| @trello_connection.find_member_by_id(id)}
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
module Reviewlette
|
16
|
-
|
17
|
-
class TrelloConnection
|
18
|
-
|
19
|
-
attr_accessor :board
|
20
|
-
|
21
|
-
def initialize
|
22
|
-
setup_trello
|
23
|
-
end
|
24
|
-
|
25
|
-
def determine_reviewer(card)
|
26
|
-
raise AlreadyAssignedException, "Everyone on the team is assigned to the Card." if reviewer_exception_handler(card)
|
27
|
-
find_member_by_username(sample_reviewer(card))
|
28
|
-
end
|
29
|
-
|
30
|
-
def sample_reviewer(card)
|
31
|
-
(team - card.assignees.map(&:username)).sample
|
32
|
-
end
|
33
|
-
|
34
|
-
def reviewer_exception_handler(card)
|
35
|
-
(team - card.assignees.map(&:username)).count <= 0
|
36
|
-
end
|
37
|
-
|
38
|
-
def add_reviewer_to_card(reviewer, card)
|
39
|
-
card.add_member(reviewer) if reviewer
|
40
|
-
end
|
6
|
+
class TrelloConnection
|
41
7
|
|
42
|
-
|
43
|
-
card.add_comment(reviewer) if reviewer
|
44
|
-
end
|
8
|
+
attr_accessor :board
|
45
9
|
|
46
|
-
|
47
|
-
|
10
|
+
def initialize
|
11
|
+
Trello.configure do |config|
|
12
|
+
config.developer_public_key = TRELLO_CONFIG['consumerkey']
|
13
|
+
config.member_token = TRELLO_CONFIG['oauthtoken']
|
48
14
|
end
|
15
|
+
@board = Trello::Board.find(TRELLO_CONFIG['board_id'])
|
16
|
+
end
|
49
17
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
18
|
+
def add_reviewer_to_card(reviewer, card)
|
19
|
+
reviewer = find_member_by_username(reviewer)
|
20
|
+
card.add_member(reviewer)
|
21
|
+
end
|
54
22
|
|
55
|
-
|
56
|
-
|
57
|
-
|
23
|
+
def comment_on_card(comment, card)
|
24
|
+
card.add_comment(comment)
|
25
|
+
end
|
58
26
|
|
59
|
-
|
60
|
-
|
61
|
-
|
27
|
+
def move_card_to_list(card, column_name)
|
28
|
+
column = find_column(column_name)
|
29
|
+
card.move_to_list(column)
|
30
|
+
end
|
62
31
|
|
63
|
-
|
64
|
-
|
65
|
-
|
32
|
+
def find_column(column_name)
|
33
|
+
@board.lists.find { |x| x.name == column_name }
|
34
|
+
end
|
66
35
|
|
67
|
-
|
68
|
-
|
69
|
-
|
36
|
+
def find_member_by_username(username)
|
37
|
+
@board.members.find { |m| m.username == username }
|
38
|
+
end
|
70
39
|
|
71
|
-
|
72
|
-
|
73
|
-
config.developer_public_key = ::Reviewlette::TRELLO_CONFIG1['consumerkey']
|
74
|
-
config.member_token = ::Reviewlette::TRELLO_CONFIG1['oauthtoken']
|
75
|
-
end
|
76
|
-
@board = Trello::Board.find(::Reviewlette::TRELLO_CONFIG1['board_id'])
|
77
|
-
end
|
40
|
+
def find_card_by_id(id)
|
41
|
+
@board.cards.find { |c| c.short_id == id.to_i }
|
78
42
|
end
|
43
|
+
|
79
44
|
end
|
45
|
+
|
@@ -1,38 +1,30 @@
|
|
1
1
|
require 'net/telnet'
|
2
|
-
module Reviewlette
|
3
2
|
|
4
|
-
|
3
|
+
class Vacations
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
if l[0,1] == "-"
|
15
|
-
collect = false
|
16
|
-
next
|
17
|
-
end
|
18
|
-
dates = []
|
19
|
-
l.split(" ").each do |date|
|
20
|
-
unless date =~ /#{Time.now.year}/
|
21
|
-
next
|
22
|
-
end
|
23
|
-
dates.push(date)
|
24
|
-
end
|
25
|
-
case dates.size
|
26
|
-
when 1
|
27
|
-
vacations.push("#{dates[0]}")
|
28
|
-
when 2
|
29
|
-
vacations.push("#{dates[0]} - #{dates[1]}")
|
30
|
-
else
|
31
|
-
end
|
5
|
+
def self.find_vacations(username)
|
6
|
+
vacations = []
|
7
|
+
tn = Net::Telnet.new('Host' => 'present.suse.de', 'Port' => 9874, 'Binmode' => false)
|
8
|
+
tn.cmd("#{username}").split("\n").each do |line|
|
9
|
+
if line =~ /\S{3} #{Time.now.year}-\d\d-\d\d/
|
10
|
+
dates = []
|
11
|
+
line.split(" ").each do |date|
|
12
|
+
dates.push(date) if date =~ /#{Time.now.year}-\d\d-\d\d/
|
32
13
|
end
|
14
|
+
dates[1] = dates[0] unless dates[1]
|
15
|
+
vacations.push(Date.parse(dates[0])..Date.parse(dates[1]))
|
33
16
|
end
|
34
|
-
tn.close
|
35
|
-
vacations
|
36
17
|
end
|
18
|
+
tn.close
|
19
|
+
vacations
|
37
20
|
end
|
38
|
-
|
21
|
+
|
22
|
+
def self.members_on_vacation
|
23
|
+
members_on_vacation = MEMBERS_CONFIG['members'].collect do |member|
|
24
|
+
username = member['suse_username']
|
25
|
+
username if (username && Vacations.find_vacations(username).any? { |v| v === Date.today })
|
26
|
+
end
|
27
|
+
members_on_vacation.compact
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|