Skip to content

Commit 7090ff0

Browse files
author
Tom Osowski
authored
Merge pull request #126 from osowskit/master
Add Ruby webhook server to dismiss reviews
2 parents 0ffe990 + b75d2ac commit 7090ff0

File tree

4 files changed

+151
-0
lines changed

4 files changed

+151
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
source "http://rubygems.org"
2+
3+
gem "json", "~> 1.8"
4+
gem 'sinatra', '~> 1.3.5'
5+
gem 'rest-client'
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
GEM
2+
remote: http://rubygems.org/
3+
specs:
4+
domain_name (0.5.20161129)
5+
unf (>= 0.0.5, < 1.0.0)
6+
http-cookie (1.0.3)
7+
domain_name (~> 0.5)
8+
json (1.8.6)
9+
mime-types (3.1)
10+
mime-types-data (~> 3.2015)
11+
mime-types-data (3.2016.0521)
12+
netrc (0.11.0)
13+
rack (1.6.5)
14+
rack-protection (1.5.3)
15+
rack
16+
rest-client (2.0.1)
17+
http-cookie (>= 1.0.2, < 2.0)
18+
mime-types (>= 1.16, < 4.0)
19+
netrc (~> 0.8)
20+
sinatra (1.3.6)
21+
rack (~> 1.4)
22+
rack-protection (~> 1.3)
23+
tilt (~> 1.3, >= 1.3.3)
24+
tilt (1.4.1)
25+
unf (0.1.4)
26+
unf_ext
27+
unf_ext (0.0.7.2)
28+
29+
PLATFORMS
30+
ruby
31+
32+
DEPENDENCIES
33+
json (~> 1.8)
34+
rest-client
35+
sinatra (~> 1.3.5)
36+
37+
BUNDLED WITH
38+
1.14.4
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Dismiss Review Server
2+
3+
A ruby server that listens for GitHub webhook `push` events, based on [the documentation](https://developer.github.com/webhooks/configuring/#writing-the-server), that will dismiss any `APPROVED` [Pull Request Reviews](https://help.github.com/articles/about-pull-request-reviews/).
4+
5+
## Configuration
6+
7+
Follow the [instructions](https://developer.github.com/webhooks/) of setting up a Webhook on GitHub to this server. Set the following environment variables:
8+
- GITHUB_API_TOKEN - (Required) [OAuth token](https://developer.github.com/v3/#authentication) with write access to the repository.
9+
- SECRET_TOKEN - (Optional) [Shared secret token](https://developer.github.com/webhooks/securing/#validating-payloads-from-github) between the GitHub Webhook and this application. Leave this unset if not using a secret token.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
require 'sinatra'
2+
require 'json'
3+
require 'rest-client'
4+
5+
$github_api_token = ENV['GITHUB_API_TOKEN']
6+
$github_secret_token = ENV['SECRET_TOKEN']
7+
8+
post '/payload' do
9+
10+
# Only validate secret token if set
11+
if !$github_secret_token.nil?
12+
payload_body = request.body.read
13+
verify_signature(payload_body)
14+
end
15+
16+
github_event = request.env['HTTP_X_GITHUB_EVENT']
17+
if github_event == "push"
18+
request.body.rewind
19+
parsed = JSON.parse(request.body.read)
20+
21+
# Get branch information
22+
branch_name = parsed['ref']
23+
removed_slice = branch_name.slice!("refs/heads/")
24+
if removed_slice.nil?
25+
return "Not a branch. Nothing to do."
26+
end
27+
28+
# Get Repository owner
29+
repo_owner = parsed["repository"]["owner"]["name"]
30+
31+
# Create URL to look up Pull Requests for this branch
32+
# e.g. https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}
33+
pulls_url = parsed['repository']['pulls_url']
34+
35+
# Pull off the "{/number}" and search for all Pull Requests
36+
# that include the branch
37+
pulls_url_filtered = pulls_url.split('{').first + "?head=#{repo_owner}:#{branch_name}"
38+
pulls = get(pulls_url_filtered)
39+
40+
# parse pull requests
41+
if pulls.empty?
42+
puts "empty"
43+
else
44+
pulls.each do |pull_request|
45+
46+
# Get all Reviews for a Pull Request via API
47+
review_url_orig = pull_request["url"] + "/reviews"
48+
reviews = get(review_url_orig)
49+
50+
reviews.each do |review|
51+
52+
# Dismiss all Reviews in 'APPROVED' state via API
53+
if review["state"] == "APPROVED"
54+
puts "INFO: found an approved Review"
55+
review_id = review["id"]
56+
dismiss_url = review_url_orig + "/#{review_id}/dismissals"
57+
put(dismiss_url)
58+
end
59+
end.empty? and begin
60+
puts "no reviews"
61+
end
62+
end
63+
end
64+
elsif github_event == "ping"
65+
puts github_event
66+
else
67+
puts github_event
68+
end
69+
"message received"
70+
end
71+
72+
def put(url)
73+
jdata = JSON.generate({ message: "Auto-dismissing"})
74+
headers = {
75+
params:
76+
{
77+
access_token: $github_api_token
78+
},
79+
accept: "application/vnd.github.black-cat-preview+json"
80+
}
81+
response = RestClient.put(url, jdata, headers)
82+
JSON.parse(response.body)
83+
end
84+
85+
def get(url)
86+
headers = {
87+
params: {
88+
access_token: $github_api_token
89+
},
90+
accept: "application/vnd.github.black-cat-preview+json"
91+
}
92+
response = RestClient.get(url, headers)
93+
JSON.parse(response.body)
94+
end
95+
96+
def verify_signature(payload_body)
97+
signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), ENV['SECRET_TOKEN'], payload_body)
98+
return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE'])
99+
end

0 commit comments

Comments
 (0)