lita-reviewme 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 314ab18b6586a16c2e317fbfb50ca9e1f3b7c945
4
- data.tar.gz: 7fbc8906b146f332eac6e2330999240dccb7948e
3
+ metadata.gz: 6e3fdda3bc11c48f465520ed585c287264467a1c
4
+ data.tar.gz: af62cdf96b2d1166cab08a71ac6137682a9479ae
5
5
  SHA512:
6
- metadata.gz: b1f6090dd447abfbdd171e99e25b65cadadf33c277ecc3ff8f27da70fcf98effd75c2a5474b1de87ed1c6323641d0affdcaa69e4b7f2c43a7579cd532a943b3a
7
- data.tar.gz: 74dc37d914c77454f1637dacf758aa3ccd8cd11ffe1235e4b795ff68ca305b4ff290d5e6a2710e8c01bb1de5ee03f0a475c36c05b260c2d1bb6fdbd5783ce829
6
+ metadata.gz: efd26c673f8006d63fb2487aecc38a2b43493be6db51112eaa412b539d936e0e72188cc4d2ea2ef955ac27e78393f2d2592aee10a9d2b842b78f7af4d6b950c6
7
+ data.tar.gz: d43e40943e95309b76f69a70256b26b7e89ad5fd42ec0956320ce07c6e4ef20891322a5028fc00b1553ddf6d39ea9f62a4985316a2d48673deddc0b385db657d
@@ -4,6 +4,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.5.0] - 2017-06-28
8
+
9
+ ### Added
10
+ - [#55] [#56] - Integration with Github Reviews
11
+
12
+ ### Changed
13
+ - [#54] - Use `:default` option for configuration defaults.
14
+
7
15
  ## [0.4.0] - 2017-02-10
8
16
 
9
17
  ### Added
@@ -42,7 +50,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
42
50
  ### Added
43
51
  - Start versioning gem.
44
52
 
45
- [Unreleased]: https://github.com/iamvery/lita-reviewme/compare/v0.4.0...HEAD
53
+ [Unreleased]: https://github.com/iamvery/lita-reviewme/compare/v0.5.0...HEAD
54
+ [0.5.0]: https://github.com/iamvery/lita-reviewme/compare/v0.4.0...v0.5.0
46
55
  [0.4.0]: https://github.com/iamvery/lita-reviewme/compare/v0.3.1...v0.4.0
47
56
  [0.3.1]: https://github.com/iamvery/lita-reviewme/compare/v0.3.0...v0.3.1
48
57
  [0.3.0]: https://github.com/iamvery/lita-reviewme/compare/v0.2.0...v0.3.0
@@ -52,3 +61,6 @@ This project adheres to [Semantic Versioning](http://semver.org/).
52
61
 
53
62
  [#41]: https://github.com/iamvery/lita-reviewme/pull/41
54
63
  [#36]: https://github.com/iamvery/lita-reviewme/pull/36
64
+ [#54]: https://github.com/iamvery/lita-reviewme/pull/54
65
+ [#55]: https://github.com/iamvery/lita-reviewme/pull/55
66
+ [#56]: https://github.com/iamvery/lita-reviewme/pull/56
data/README.md CHANGED
@@ -52,6 +52,17 @@ config.handlers.reviewme.github_comment_template = lamda do |reviewer, pull_requ
52
52
  end
53
53
  ```
54
54
 
55
+ Your bot can assign a reviewer by adding a comment to the requested PR (default) or by [requesting a review](https://github.com/blog/2291-introducing-review-requests) (or both).
56
+
57
+ ```
58
+ # your bot's lita_config.rb
59
+ #
60
+ # Note:
61
+ # The following configuration will enable review requests and disable comments
62
+ config.handlers.reviewme.github_request_review = true # default (false)
63
+ config.handlers.reviewme.github_comment = false # default (true)
64
+ ```
65
+
55
66
  ## Usage
56
67
 
57
68
  ### See who is in the review rotation.
@@ -0,0 +1,68 @@
1
+ require 'delegate'
2
+
3
+ module Lita
4
+ module Reviewme
5
+ class Github
6
+ class UnknownOwner < StandardError; end
7
+ class CannotPostComment < StandardError; end
8
+
9
+ extend Forwardable
10
+
11
+ attr_reader :config, :repo, :pr_id
12
+
13
+ delegate [
14
+ :github_access_token,
15
+ :github_comment_template,
16
+ :github_comment,
17
+ :github_request_review,
18
+ ] => :config
19
+
20
+ def initialize(config, repo, pr_id)
21
+ @config = config
22
+ @repo = repo
23
+ @pr_id = pr_id
24
+ end
25
+
26
+ def owner
27
+ pull_request.user.login
28
+ rescue Octokit::Error
29
+ raise UnknownOwner
30
+ end
31
+
32
+ def assign(reviewer)
33
+ request_review(reviewer) if github_request_review
34
+ add_comment(reviewer) if github_comment
35
+ rescue Octokit::Error
36
+ raise CannotPostComment
37
+ end
38
+
39
+ private
40
+
41
+ def client
42
+ @client ||= Octokit::Client.new(access_token: github_access_token)
43
+ end
44
+
45
+ def pull_request
46
+ @pull_request ||= client.pull_request(repo, pr_id)
47
+ end
48
+
49
+ def request_review(reviewer)
50
+ options = { accept: 'application/vnd.github.black-cat-preview' }
51
+
52
+ client.request_pull_request_review(repo, pr_id, [reviewer], options)
53
+ end
54
+
55
+ def add_comment(reviewer)
56
+ client.add_comment(repo, pr_id, comment(reviewer))
57
+ end
58
+
59
+ def comment(reviewer)
60
+ if github_comment_template.respond_to?(:call)
61
+ github_comment_template.call(reviewer, pull_request)
62
+ else
63
+ github_comment_template % { reviewer: "@#{reviewer}" }
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,13 +1,18 @@
1
1
  require 'octokit'
2
+ require 'lita-reviewme/github'
2
3
 
3
4
  module Lita
4
5
  module Handlers
5
6
  class Reviewme < Handler
7
+ InvalidConfig = Class.new(StandardError)
8
+
6
9
  REDIS_LIST = "reviewers"
7
10
  DEFAULT_GITHUB_MSG = ":eyes: %{reviewer}"
8
11
 
9
12
  config :github_access_token
10
- config :github_comment_template
13
+ config :github_comment_template, default: DEFAULT_GITHUB_MSG
14
+ config :github_request_review, default: false
15
+ config :github_comment, default: true
11
16
 
12
17
  route(
13
18
  /add (.+) to reviews/i,
@@ -51,7 +56,7 @@ module Lita
51
56
 
52
57
  route(
53
58
  %r{review <?(?<url>(https://)?github.com/(?<repo>.+)/(pull|issues)/(?<id>\d+))>?}i,
54
- :comment_on_github,
59
+ :review_on_github,
55
60
  command: true,
56
61
  help: { "review https://github.com/user/repo/pull/123" => "adds comment to GH issue requesting review" },
57
62
  )
@@ -86,28 +91,23 @@ module Lita
86
91
  response.reply(reviewer.to_s)
87
92
  end
88
93
 
89
- def comment_on_github(response, room: get_room(response))
90
- repo = response.match_data[:repo]
91
- id = response.match_data[:id]
94
+ def review_on_github(response, room: get_room(response))
95
+ validate_config
96
+ github = Lita::Reviewme::Github.new(config, response.match_data[:repo], response.match_data[:id])
92
97
 
93
- reviewer = next_reviewer(room)
94
- begin
95
- pull_request = github_client.pull_request(repo, id)
96
- owner = pull_request.user.login
97
- reviewer = next_reviewer(room) if owner == reviewer
98
- rescue Octokit::Error
99
- response.reply("Unable to check who issued the pull request. Sorry if you end up being assigned your own PR!")
100
- end
101
- return response.reply('Sorry, no reviewers found') unless reviewer
102
- comment = github_comment(reviewer, pull_request)
103
-
104
- begin
105
- github_client.add_comment(repo, id, comment)
98
+ if reviewer = next_reviewer(room, github.owner)
99
+ github.assign(reviewer)
106
100
  response.reply("#{reviewer} should be on it...")
107
- rescue Octokit::Error
108
- url = response.match_data[:url]
109
- response.reply("I couldn't post a comment. (Are the permissions right?) #{chat_mention(reviewer, url)}")
101
+ else
102
+ response.reply('Sorry, no reviewers found')
110
103
  end
104
+ rescue Lita::Reviewme::Github::UnknownOwner
105
+ response.reply("Unable to check who issued the pull request. Sorry if you end up being assigned your own PR!")
106
+ rescue Lita::Reviewme::Github::CannotPostComment
107
+ url = response.match_data[:url]
108
+ response.reply("I couldn't post a comment or request a reviewer. (Are the permissions right?) #{chat_mention(reviewer, url)}")
109
+ rescue InvalidConfig => error
110
+ response.reply(error.message)
111
111
  end
112
112
 
113
113
  def mention_reviewer(response, room: get_room(response))
@@ -118,22 +118,23 @@ module Lita
118
118
 
119
119
  private
120
120
 
121
- def next_reviewer(room)
122
- ns_redis(room.id).rpoplpush(REDIS_LIST, REDIS_LIST)
121
+ def validate_config
122
+ if !config.github_comment and !config.github_request_review
123
+ raise InvalidConfig, 'I am configured to neither leave a comment nor start a review. Check config.handlers.reviewme in lita_config.rb.'
124
+ end
123
125
  end
124
126
 
125
- def github_comment(reviewer, pull_request)
126
- msg = config.github_comment_template || DEFAULT_GITHUB_MSG
127
+ def next_reviewer(room, owner = nil)
128
+ reviewer = ns_redis(room.id).rpoplpush(REDIS_LIST, REDIS_LIST)
129
+ return unless reviewer
127
130
 
128
- if msg.respond_to?(:call) # its a proc
129
- msg.call(reviewer, pull_request)
130
- else
131
- msg % { reviewer: "@#{reviewer}" }
131
+ if reviewer == owner
132
+ return if ns_redis(room.id).llen(REDIS_LIST) == 1
133
+
134
+ reviewer = next_reviewer(room, owner)
132
135
  end
133
- end
134
136
 
135
- def github_client
136
- @github_client ||= Octokit::Client.new(access_token: config.github_access_token)
137
+ reviewer
137
138
  end
138
139
 
139
140
  def chat_mention(reviewer, url)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "lita-reviewme"
3
- spec.version = "0.4.0"
3
+ spec.version = "0.5.0"
4
4
  spec.authors = ["Jay Hayes"]
5
5
  spec.email = ["ur@iamvery.com"]
6
6
  spec.description = %q{A lita handler that helps with code review}
@@ -0,0 +1,91 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Reviewme::Github do
4
+ let(:repo) { "gh_user/repo" }
5
+ let(:id) { "123" }
6
+ let(:user) { OpenStruct.new(login: 'iamvery') }
7
+ let(:title) { 'PR Title' }
8
+ let(:pull_request) { OpenStruct.new(user: user, title: title) }
9
+ let(:github_comment_template) { ":eyes: %{reviewer}" }
10
+ let(:github_comment) { true }
11
+ let(:github_request_review) { false }
12
+
13
+ let(:config) do
14
+ OpenStruct.new(
15
+ github_access_token: 'access-token',
16
+ github_comment_template: github_comment_template,
17
+ github_comment: github_comment,
18
+ github_request_review: github_request_review
19
+ )
20
+ end
21
+
22
+ before do
23
+ allow_any_instance_of(Octokit::Client).to receive(:pull_request)
24
+ .and_return(pull_request)
25
+ end
26
+
27
+ subject { described_class.new(config, repo, id) }
28
+
29
+ describe "ownership" do
30
+ it "comes from the pull request" do
31
+ expect(subject.owner).to eq('iamvery')
32
+ end
33
+
34
+ describe "unexpected error" do
35
+ class User
36
+ def login
37
+ raise Octokit::Error
38
+ end
39
+ end
40
+
41
+ let(:user) { User.new }
42
+
43
+ it "raises an exception" do
44
+ expect { subject.owner }.to raise_error(Lita::Reviewme::Github::UnknownOwner)
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "assignment" do
50
+ describe "via review request" do
51
+ let(:github_comment) { false }
52
+ let(:github_request_review) { true }
53
+
54
+ it "uses the request review api" do
55
+ expect_any_instance_of(Octokit::Client).to receive(:request_pull_request_review)
56
+ .with(repo, id, ['iamvery'], { accept: "application/vnd.github.black-cat-preview" })
57
+
58
+ subject.assign('iamvery')
59
+ end
60
+ end
61
+
62
+ describe "via comment api" do
63
+ describe "with a string" do
64
+ it "evaluates template" do
65
+ expect_any_instance_of(Octokit::Client).to receive(:add_comment)
66
+ .with(repo, id, ":eyes: @iamvery")
67
+
68
+ subject.assign('iamvery')
69
+ end
70
+ end
71
+
72
+ describe "with a proc" do
73
+ let(:github_comment_template) do
74
+ lambda do |reviewer, pull_request|
75
+ "hey @#{reviewer}, this is from a lambda! :tada: #{title}"
76
+ end
77
+ end
78
+
79
+ it "executes a proc if specified in `config.github_comment_template`" do
80
+ expected_msg = "hey @iamvery, this is from a lambda! :tada: #{title}"
81
+
82
+ expect_any_instance_of(Octokit::Client).to receive(:add_comment)
83
+ .with(repo, id, expected_msg)
84
+
85
+ subject.assign('iamvery')
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+
@@ -8,9 +8,9 @@ describe Lita::Handlers::Reviewme, lita_handler: true do
8
8
  it { is_expected.to route_command("remove reviewer iamvery").to :remove_reviewer }
9
9
  it { is_expected.to route_command("reviewers").to :display_reviewers }
10
10
  it { is_expected.to route_command("review me").to :generate_assignment }
11
- it { is_expected.to route_command("review https://github.com/user/repo/pull/123").to :comment_on_github }
12
- it { is_expected.to route_command("review <https://github.com/user/repo/pull/123>").to :comment_on_github }
13
- it { is_expected.to route_command("review https://github.com/user/repo/issues/123").to :comment_on_github }
11
+ it { is_expected.to route_command("review https://github.com/user/repo/pull/123").to :review_on_github }
12
+ it { is_expected.to route_command("review <https://github.com/user/repo/pull/123>").to :review_on_github }
13
+ it { is_expected.to route_command("review https://github.com/user/repo/issues/123").to :review_on_github }
14
14
  it { is_expected.to route_command("review https://bitbucket.org/user/repo/pull-requests/123").to :mention_reviewer }
15
15
  it { is_expected.to route_command("review <https://bitbucket.org/user/repo/pull-requests/123>").to :mention_reviewer }
16
16
 
@@ -52,7 +52,7 @@ describe Lita::Handlers::Reviewme, lita_handler: true do
52
52
  end
53
53
  end
54
54
 
55
- describe "#comment_on_github" do
55
+ describe "#review_on_github" do
56
56
  let(:repo) { "gh_user/repo" }
57
57
  let(:id) { "123" }
58
58
  let(:pr) do
@@ -63,10 +63,12 @@ describe Lita::Handlers::Reviewme, lita_handler: true do
63
63
  # Prevent hitting the network for PR info.
64
64
  allow_any_instance_of(Octokit::Client).to receive(:pull_request)
65
65
  .and_return(pr)
66
+
67
+ @default_github_comment_template = subject.config.github_comment_template
66
68
  end
67
69
 
68
70
  after do
69
- subject.config.github_comment_template = nil
71
+ subject.config.github_comment_template = @default_github_comment_template
70
72
  end
71
73
 
72
74
  it "posts comment on github" do
@@ -120,6 +122,16 @@ describe Lita::Handlers::Reviewme, lita_handler: true do
120
122
  expect(reply).to eq("iamvery should be on it...")
121
123
  end
122
124
 
125
+ it "doesn't get stuck if requester is only reviewer" do
126
+ expect_any_instance_of(Octokit::Client).to receive(:pull_request)
127
+ .with(repo, id).and_return(pr)
128
+
129
+ send_command("add #{pr.user.login} to reviews")
130
+ send_command("review https://github.com/#{repo}/pull/#{id}")
131
+
132
+ expect(reply).to eq('Sorry, no reviewers found')
133
+ end
134
+
123
135
  it "skips assigning to the GitHub PR owner" do
124
136
  expect_any_instance_of(Octokit::Client).to receive(:pull_request)
125
137
  .with(repo, id).and_return(pr)
@@ -144,7 +156,48 @@ describe Lita::Handlers::Reviewme, lita_handler: true do
144
156
  send_command("add iamvery to reviews")
145
157
  send_command("review #{url}")
146
158
 
147
- expect(reply).to eq("I couldn't post a comment. (Are the permissions right?) iamvery: :eyes: #{url}")
159
+ expect(reply).to eq("I couldn't post a comment or request a reviewer. (Are the permissions right?) iamvery: :eyes: #{url}")
160
+ end
161
+
162
+ describe "review requests" do
163
+ before do
164
+ subject.config.github_comment = false
165
+ subject.config.github_request_review = true
166
+ end
167
+
168
+ after do
169
+ subject.config.github_comment = true
170
+ subject.config.github_request_review = false
171
+ end
172
+
173
+ it "requests a review if enabled" do
174
+ expect_any_instance_of(Octokit::Client).to receive(:request_pull_request_review)
175
+ .with(repo, id, ['iamvery'], { accept: "application/vnd.github.black-cat-preview" })
176
+
177
+ send_command("add iamvery to reviews")
178
+ send_command("review https://github.com/#{repo}/pull/#{id}")
179
+
180
+ expect(reply).to eq("iamvery should be on it...")
181
+ end
182
+ end
183
+
184
+ describe "invalid configuration" do
185
+ before do
186
+ subject.config.github_comment = false
187
+ subject.config.github_request_review = false
188
+ end
189
+
190
+ after do
191
+ subject.config.github_comment = true
192
+ subject.config.github_request_review = false
193
+ end
194
+
195
+ it "raises error because bot can't do anything" do
196
+ send_command("add iamvery to reviews")
197
+ send_command("review https://github.com/#{repo}/pull/#{id}")
198
+
199
+ expect(reply).to eq("I am configured to neither leave a comment nor start a review. Check config.handlers.reviewme in lita_config.rb.")
200
+ end
148
201
  end
149
202
  end
150
203
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita-reviewme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jay Hayes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-10 00:00:00.000000000 Z
11
+ date: 2017-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lita
@@ -115,9 +115,11 @@ files:
115
115
  - README.md
116
116
  - Rakefile
117
117
  - lib/lita-reviewme.rb
118
+ - lib/lita-reviewme/github.rb
118
119
  - lib/lita/handlers/reviewme.rb
119
120
  - lita-reviewme.gemspec
120
121
  - locales/en.yml
122
+ - spec/lita-reviewme/github_spec.rb
121
123
  - spec/lita/handlers/reviewme_spec.rb
122
124
  - spec/spec_helper.rb
123
125
  homepage: https://github.com/iamvery/lita-reviewme
@@ -141,10 +143,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
143
  version: '0'
142
144
  requirements: []
143
145
  rubyforge_project:
144
- rubygems_version: 2.5.2
146
+ rubygems_version: 2.6.12
145
147
  signing_key:
146
148
  specification_version: 4
147
149
  summary: A lita handler that helps with code review
148
150
  test_files:
151
+ - spec/lita-reviewme/github_spec.rb
149
152
  - spec/lita/handlers/reviewme_spec.rb
150
153
  - spec/spec_helper.rb