forked from github/platform-samples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request github#126 from osowskit/master
Add Ruby webhook server to dismiss reviews
- Loading branch information
Showing
4 changed files
with
151 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
source "http://rubygems.org" | ||
|
||
gem "json", "~> 1.8" | ||
gem 'sinatra', '~> 1.3.5' | ||
gem 'rest-client' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
GEM | ||
remote: http://rubygems.org/ | ||
specs: | ||
domain_name (0.5.20161129) | ||
unf (>= 0.0.5, < 1.0.0) | ||
http-cookie (1.0.3) | ||
domain_name (~> 0.5) | ||
json (1.8.6) | ||
mime-types (3.1) | ||
mime-types-data (~> 3.2015) | ||
mime-types-data (3.2016.0521) | ||
netrc (0.11.0) | ||
rack (1.6.5) | ||
rack-protection (1.5.3) | ||
rack | ||
rest-client (2.0.1) | ||
http-cookie (>= 1.0.2, < 2.0) | ||
mime-types (>= 1.16, < 4.0) | ||
netrc (~> 0.8) | ||
sinatra (1.3.6) | ||
rack (~> 1.4) | ||
rack-protection (~> 1.3) | ||
tilt (~> 1.3, >= 1.3.3) | ||
tilt (1.4.1) | ||
unf (0.1.4) | ||
unf_ext | ||
unf_ext (0.0.7.2) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
json (~> 1.8) | ||
rest-client | ||
sinatra (~> 1.3.5) | ||
|
||
BUNDLED WITH | ||
1.14.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Dismiss Review Server | ||
|
||
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/). | ||
|
||
## Configuration | ||
|
||
Follow the [instructions](https://developer.github.com/webhooks/) of setting up a Webhook on GitHub to this server. Set the following environment variables: | ||
- GITHUB_API_TOKEN - (Required) [OAuth token](https://developer.github.com/v3/#authentication) with write access to the repository. | ||
- 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
require 'sinatra' | ||
require 'json' | ||
require 'rest-client' | ||
|
||
$github_api_token = ENV['GITHUB_API_TOKEN'] | ||
$github_secret_token = ENV['SECRET_TOKEN'] | ||
|
||
post '/payload' do | ||
|
||
# Only validate secret token if set | ||
if !$github_secret_token.nil? | ||
payload_body = request.body.read | ||
verify_signature(payload_body) | ||
end | ||
|
||
github_event = request.env['HTTP_X_GITHUB_EVENT'] | ||
if github_event == "push" | ||
request.body.rewind | ||
parsed = JSON.parse(request.body.read) | ||
|
||
# Get branch information | ||
branch_name = parsed['ref'] | ||
removed_slice = branch_name.slice!("refs/heads/") | ||
if removed_slice.nil? | ||
return "Not a branch. Nothing to do." | ||
end | ||
|
||
# Get Repository owner | ||
repo_owner = parsed["repository"]["owner"]["name"] | ||
|
||
# Create URL to look up Pull Requests for this branch | ||
# e.g. https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number} | ||
pulls_url = parsed['repository']['pulls_url'] | ||
|
||
# Pull off the "{/number}" and search for all Pull Requests | ||
# that include the branch | ||
pulls_url_filtered = pulls_url.split('{').first + "?head=#{repo_owner}:#{branch_name}" | ||
pulls = get(pulls_url_filtered) | ||
|
||
# parse pull requests | ||
if pulls.empty? | ||
puts "empty" | ||
else | ||
pulls.each do |pull_request| | ||
|
||
# Get all Reviews for a Pull Request via API | ||
review_url_orig = pull_request["url"] + "/reviews" | ||
reviews = get(review_url_orig) | ||
|
||
reviews.each do |review| | ||
|
||
# Dismiss all Reviews in 'APPROVED' state via API | ||
if review["state"] == "APPROVED" | ||
puts "INFO: found an approved Review" | ||
review_id = review["id"] | ||
dismiss_url = review_url_orig + "/#{review_id}/dismissals" | ||
put(dismiss_url) | ||
end | ||
end.empty? and begin | ||
puts "no reviews" | ||
end | ||
end | ||
end | ||
elsif github_event == "ping" | ||
puts github_event | ||
else | ||
puts github_event | ||
end | ||
"message received" | ||
end | ||
|
||
def put(url) | ||
jdata = JSON.generate({ message: "Auto-dismissing"}) | ||
headers = { | ||
params: | ||
{ | ||
access_token: $github_api_token | ||
}, | ||
accept: "application/vnd.github.black-cat-preview+json" | ||
} | ||
response = RestClient.put(url, jdata, headers) | ||
JSON.parse(response.body) | ||
end | ||
|
||
def get(url) | ||
headers = { | ||
params: { | ||
access_token: $github_api_token | ||
}, | ||
accept: "application/vnd.github.black-cat-preview+json" | ||
} | ||
response = RestClient.get(url, headers) | ||
JSON.parse(response.body) | ||
end | ||
|
||
def verify_signature(payload_body) | ||
signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), ENV['SECRET_TOKEN'], payload_body) | ||
return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE']) | ||
end |