reviewlette 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 53593949368f61246646984e517e18c7e478497c
4
+ data.tar.gz: 2c1af0b6ac234d1a06ea28f1906323857a398073
5
+ SHA512:
6
+ metadata.gz: 1e3e7d9571d7869b2f49e34a7d1be93269e8f8c6f300f00f02bb757e3036aeab4248dfddb8a9479735aac970ebbad56765b6defbfd4bcfc234ac3a94476bf60f
7
+ data.tar.gz: f4fbe33ad2be3922ae2e9de8d494209f2defbecb0cd19f49affed7d72b4c88cd7d2bbd3b7e942920644f33f2349f74ed83f1995884441f222c0fe3ff92d5f2dc
@@ -0,0 +1,27 @@
1
+ *.gem
2
+ *.db
3
+ *.log
4
+ *.html
5
+ database
6
+ *.yml~
7
+ .idea
8
+ /.idea
9
+ .idea*
10
+ /.idea/*
11
+ *.rbc
12
+ *.yml
13
+ .bundle
14
+ coverage
15
+ .swp
16
+ InstalledFiles
17
+ lib/bundler/man
18
+ pkg
19
+ rdoc
20
+ spec/reports
21
+ test/tmp
22
+ test/version_tmp
23
+ tmp
24
+ .yardoc
25
+ _yardoc
26
+ rdoc/
27
+ doc/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'json'
4
+ gem 'haml'
5
+ gem 'octokit', '~> 3.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'
@@ -0,0 +1,114 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (4.1.1)
5
+ activesupport (= 4.1.1)
6
+ builder (~> 3.1)
7
+ activesupport (4.1.1)
8
+ i18n (~> 0.6, >= 0.6.9)
9
+ json (~> 1.7, >= 1.7.7)
10
+ minitest (~> 5.1)
11
+ thread_safe (~> 0.1)
12
+ tzinfo (~> 1.1)
13
+ addressable (2.3.6)
14
+ ap (0.1.1)
15
+ httparty (>= 0.7.7)
16
+ builder (3.2.2)
17
+ byebug (3.1.2)
18
+ columnize (~> 0.8)
19
+ columnize (0.8.9)
20
+ coveralls (0.7.0)
21
+ multi_json (~> 1.3)
22
+ rest-client
23
+ simplecov (>= 0.7)
24
+ term-ansicolor
25
+ thor
26
+ crack (0.4.2)
27
+ safe_yaml (~> 1.0.0)
28
+ diff-lcs (1.2.5)
29
+ docile (1.1.3)
30
+ faraday (0.9.0)
31
+ multipart-post (>= 1.2, < 3)
32
+ haml (4.0.5)
33
+ tilt
34
+ httparty (0.13.1)
35
+ json (~> 1.8)
36
+ multi_xml (>= 0.5.2)
37
+ i18n (0.6.9)
38
+ json (1.8.1)
39
+ mime-types (2.3)
40
+ minitest (5.3.4)
41
+ multi_json (1.10.0)
42
+ multi_xml (0.5.5)
43
+ multipart-post (2.0.0)
44
+ oauth (0.4.7)
45
+ octokit (3.1.0)
46
+ sawyer (~> 0.5.3)
47
+ prophet (1.5.5)
48
+ octokit
49
+ rspec
50
+ rake (10.3.2)
51
+ rdoc (4.1.1)
52
+ json (~> 1.4)
53
+ rest-client (1.6.7)
54
+ mime-types (>= 1.16)
55
+ rspec (3.0.0)
56
+ rspec-core (~> 3.0.0)
57
+ rspec-expectations (~> 3.0.0)
58
+ rspec-mocks (~> 3.0.0)
59
+ rspec-core (3.0.0)
60
+ rspec-support (~> 3.0.0)
61
+ rspec-expectations (3.0.0)
62
+ diff-lcs (>= 1.2.0, < 2.0)
63
+ rspec-support (~> 3.0.0)
64
+ rspec-mocks (3.0.0)
65
+ rspec-support (~> 3.0.0)
66
+ rspec-support (3.0.0)
67
+ ruby-trello (1.1.1)
68
+ activemodel (>= 3.2.0)
69
+ addressable (~> 2.3)
70
+ json
71
+ oauth (~> 0.4.5)
72
+ rest-client (~> 1.6.7)
73
+ safe_yaml (1.0.3)
74
+ sawyer (0.5.4)
75
+ addressable (~> 2.3.5)
76
+ faraday (~> 0.8, < 0.10)
77
+ sequel (4.13.0)
78
+ simplecov (0.8.2)
79
+ docile (~> 1.1.0)
80
+ multi_json
81
+ simplecov-html (~> 0.8.0)
82
+ simplecov-html (0.8.0)
83
+ sqlite3 (1.3.9)
84
+ term-ansicolor (1.3.0)
85
+ tins (~> 1.0)
86
+ thor (0.19.1)
87
+ thread_safe (0.3.4)
88
+ tilt (2.0.1)
89
+ tins (1.1.0)
90
+ tzinfo (1.2.1)
91
+ thread_safe (~> 0.1)
92
+ webmock (1.18.0)
93
+ addressable (>= 2.3.6)
94
+ crack (>= 0.3.2)
95
+
96
+ PLATFORMS
97
+ ruby
98
+
99
+ DEPENDENCIES
100
+ ap
101
+ byebug
102
+ coveralls
103
+ haml
104
+ json
105
+ octokit (~> 3.0)
106
+ prophet
107
+ rake
108
+ rdoc
109
+ rspec
110
+ ruby-trello
111
+ sequel
112
+ simplecov
113
+ sqlite3
114
+ webmock
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 jschmid1
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,95 @@
1
+ Reviewlette
2
+ ===========
3
+
4
+ [![Coverage Status](https://img.shields.io/coveralls/jschmid1/reviewlette.svg)](https://coveralls.io/r/jschmid1/reviewlette)
5
+ [![Code Climate](https://codeclimate.com/github/jschmid1/reviewlette.png)](https://codeclimate.com/github/jschmid1/reviewlette)
6
+
7
+ Tool to automatically assign a "Reviewer" to a GitHub Issue and to the attached Trello Card.
8
+
9
+
10
+ What it does:
11
+
12
+ - Finds unassigned issues on GitHub.
13
+ - Assignes a member of your team.
14
+ - Locates the right Card on Trello.
15
+ - Checks if the assignee is on vacation(using tel).
16
+ - Adds the assigned member to the Card.
17
+ - If the Issue/PullRequest is closed or merged move it in the right column.
18
+ - Prints graphs using Morris.js to display statistics(autorefresh every 5 seconds).
19
+
20
+
21
+ ![alt tag](http://h.dropcanvas.com/72fj0/graph.jpg)
22
+
23
+
24
+ ## Installation
25
+
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
+ ```
37
+ gem install reviewlette
38
+ ```
39
+
40
+
41
+ ## Setup
42
+
43
+ #### Name your pullrequest like so:
44
+ #### Review_#23_name_of_review_42 <= trello card number
45
+
46
+ Fill `config/.trello.yml` with your **consumerkey**, **consumersecret**, **oauthtoken** and **board_id**
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)
64
+
65
+
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
+ ---
87
+
88
+ [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
+ [Using ruby-trello as a Trello api wrapper](https://github.com/jeremytregunna/ruby-trello)
93
+
94
+
95
+
@@ -0,0 +1,5 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'reviewlette'
5
+
6
+ Reviewlette.spin
7
+
File without changes
@@ -0,0 +1,202 @@
1
+ require 'reviewlette/trello_connection'
2
+ require 'reviewlette/github_connection'
3
+ require 'reviewlette/database'
4
+ require 'reviewlette/graph_gen'
5
+ require 'reviewlette/vacations'
6
+ require 'yaml'
7
+ require 'octokit'
8
+ require 'trello'
9
+
10
+ class Trello::Card
11
+
12
+ def assignees
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
77
+
78
+ def update_vacations
79
+ @db.get_users_tel_entries.each do |name|
80
+ @vacations = Reviewlette::Vacations.find_vacations(name) #tel_name
81
+ evaluate_vacations(name)
82
+ end
83
+ end
84
+
85
+ def evaluate_vacations(reviewer)
86
+ parse_vacations.each do |check|
87
+ check[1] = check[0] unless check[1] # Rewrite if statement with catch to prevent this error?
88
+ if (check[0]..check[1]).cover?(Date.today)
89
+ @db.set_vacation_flag(reviewer, 'true')
90
+ break
91
+ else
92
+ @db.set_vacation_flag(reviewer, 'false') # hopefully not to_bool?
93
+ 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
+ else
145
+ @logger.warn("Id not found, skipping Issue #{@title} with number #{@number}")
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
163
+ end
164
+ end
165
+
166
+ # Get Trelloname from configfile.
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
190
+
191
+ # TODO: More generic 'Done' and 'in Review' are not present everywhere
192
+ def move_to_list
193
+ if @github_connection.pull_merged?(@repo, @id)
194
+ @column = @trello_connection.find_column('Done')
195
+ @trello_connection.move_card_to_list(@card, @column)
196
+ else
197
+ @column = @trello_connection.find_column('In review')
198
+ @trello_connection.move_card_to_list(@card, @column)
199
+ end
200
+ end
201
+ end
202
+ end