lita-reviewme 0.4.0 → 0.5.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 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