Skip to content

Instantly share code, notes, and snippets.

@sadikovi
Created April 19, 2017 00:06
Show Gist options
  • Save sadikovi/0c5f5de2b3c0abd91d39a7b878f1adea to your computer and use it in GitHub Desktop.
Save sadikovi/0c5f5de2b3c0abd91d39a7b878f1adea to your computer and use it in GitHub Desktop.
Review script
#!/usr/bin/python
import json
import os
import time
import urllib2
# env vars that script requires
GITHUB_TOKEN="GITHUB_TOKEN"
GITHUB_USER="GITHUB_USER"
# constants for organization/repository, case-insensitive
GITHUB_ORG = "cognevo"
GITHUB_REPO = "acta"
def get_user_token():
user = os.environ.get(GITHUB_USER)
token = os.environ.get(GITHUB_TOKEN)
if not user and not token:
raise ValueError("""
Could not find username and token to access Github API.
== Please set following environment variables ==
export %s=your_username
export %s=your_auth_token
Refer to Github OAuth page to learn more about auth tokens
""" % (GITHUB_USER, GITHUB_TOKEN))
if not user:
raise ValueError("""
Could not find Github username.
== Please set following environment variable for username ==
export %s=your_username
""" % (GITHUB_USER,))
if not token:
raise ValueError("""
Could not find Github auth token.
== Please set following environment variable for token ==
export %s=your_auth_token
""" % (GITHUB_TOKEN,))
return (user, token)
def curl(url, timeout=30, safe=True, headers=[]):
"""
Return JSON response for requested URL, can also set timeout for requests.
"""
try:
opener = urllib2.build_opener()
opener.addheaders = headers + [('User-Agent', 'Mozilla/5.0')]
fileobject = opener.open(url, timeout=timeout)
return json.loads(fileobject.read())
except BaseException as err:
if safe:
return None
else:
raise err
def open_prs(token):
"""
Fetch all open pull requests for provided organization and repository.
"""
return curl("https://api.github.com/repos/%s/%s/pulls?state=open&access_token=%s" % \
(GITHUB_ORG, GITHUB_REPO, token), safe=False)
def is_for_review(pr, username, token):
"""
Return True, if pull request object is for review or not. Checks description and comments, and
review requests to make sure that current user is mentioned. Also when found stop phrase, marks
pull request as already reviewed by user.
:return: (x, y), where x is need to review and y is forced review
"""
if not pr:
print 'LOG: No PR found'
return False
# if user is an author of pull request it is assumed that he/she cannot review it
if pr['user']['login'] == username:
print 'LOG: User %s is an author of pr %s' % (username, pr['number'])
return (False, False)
# fetch all review requests to check if current user is on the list
url = 'https://api.github.com/repos/%s/%s/pulls/%s/requested_reviewers?access_token=%s&per_page=100' % \
(GITHUB_ORG, GITHUB_REPO, pr['number'], token)
# this returns only active reviewers
reviewers = curl(url, headers=[('Accept', 'application/vnd.github.black-cat-preview+json')])
for reviewer in reviewers:
if reviewer and reviewer['login'] == username:
# review is pending and expected from this user
print 'LOG: Found pending review for %s' % (pr['number'],)
return (True, True)
# at this point we do not know if review has been already done, or mentioned
# we need to browse comments to find out
url = 'https://api.github.com/repos/%s/%s/pulls/%s/reviews?access_token=%s&per_page=100' % \
(GITHUB_ORG, GITHUB_REPO, pr['number'], token)
reviews = curl(url, headers=[('Accept', 'application/vnd.github.black-cat-preview+json')])
for review in reviews:
# if there is at least one comment from this user with non-empty body, pr is considered to
# be reviewed
if review['user']['login'] == username and review['body'] != '':
print 'LOG: User %s has already reviewed pr %s' % (username, pr['number'])
return (False, False)
# get latest comments on pull request and parse messages
url = 'https://api.github.com/repos/%s/%s/issues/%s/comments?access_token=%s&per_page=100' % \
(GITHUB_ORG, GITHUB_REPO, pr['number'], token)
comments = curl(url)
# Check if this user is mentioned in pull request description
is_asked_review = (username in pr['body'] and 'review' in pr['body'], False)
for comment in comments:
if comment['user']['login'] == username and 'mark review' in comment['body']:
# pr has already been reviewed
print 'LOG: User %s marked pr %s as reviewed with "mark review"' % (username, pr['number'])
return (False, False)
if username in comment['body'] and 'review' in comment['body']:
print 'LOG: User %s is asked to review pr %s with comment %s' % \
(username, pr['number'], comment['body'])
is_asked_review = (True, False)
return is_asked_review
def main():
"""
Main function to start application.
"""
start = time.time()
(username, token) = get_user_token()
print "Fetching pull requests info for user %s" % (username,)
prs = open_prs(token)
for pr in prs:
(is_review, is_forced) = is_for_review(pr, username, token)
if is_review:
print '[+] Please review pr %s, (link: %s)' % (pr['number'], pr['html_url'])
if is_forced:
print ' - Review requested'
else:
print " - Asked to review via comment, 'mark review' to make pull request reviewed"
end = time.time()
print 'Done, took %s sec' % ((end - start),)
if __name__ == "__main__":
main()
@sadikovi
Copy link
Author

Should make it into daemon process with cache.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment