Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 169 lines (131 sloc) 5.4 KB
#!/usr/bin/env python
import collections
import datetime
import getpass
import json
import re
import time
import requests
AUTOCLOSE_MESSAGE = """\
### This is an automated comment
Thank you for reporting a problem with this exercise. This issue has been \
open for over a week and unfortunately no one has had a chance to look at it \
yet.
We get close to 100 new issues reported each day, many of which are not real \
bugs, but simply students having difficulty with the math. Unfortunately this \
means that even with the assistance of our awesome volunteers, we can't \
always go through and address each issue individually. Consequently, this \
issue is being automatically closed.
If you're still experiencing a problem, please report it again! We always \
keep an eye on the ratio of users reporting a problem to users successfully \
using an exercise, so reporting a problem--even if we can't individually \
address it--really helps.\
"""
def fetch_issues(github_auth):
issues = []
url = ("https://api.github.com/repos/Khan/khan-exercises/issues?"
"per_page=100")
while url:
print "fetching", url
r = requests.get(url, auth=github_auth)
r.raise_for_status()
time.sleep(1)
issues.extend(r.json())
match = re.match(r'<(.*?)>; rel="next"', r.headers['Link'] or '')
url = match.group(1) if match else None
return issues
def fetch_issue_comments(issue, github_auth):
print "fetching comments for issue #%(number)s" % issue
r = requests.get("https://api.github.com/repos/Khan/khan-exercises/issues/"
"%s/comments?per_page=100" % issue['number'],
auth=github_auth)
r.raise_for_status()
time.sleep(1)
return r.json()
def close_issue(issue, github_auth):
"""Attempt to close an issue and return whether it succeeded."""
closed_issue = issue.copy()
closed_issue['state'] = 'closed'
r = requests.post("https://api.github.com/repos/Khan/khan-exercises/"
"issues/%s" % issue['number'],
data=json.dumps(closed_issue), auth=github_auth)
try:
r.raise_for_status()
time.sleep(1)
return True
except requests.HTTPError:
# TODO(alpert): Catch IOError or something?
return False
def post_issue_comment(issue, comment_text, github_auth):
"""Attempt to post an issue comment and return whether it succeeded."""
closed_issue = issue.copy()
closed_issue['state'] = 'closed'
r = requests.post("https://api.github.com/repos/Khan/khan-exercises/"
"issues/%s/comments" % issue['number'],
data=json.dumps({'body': comment_text}), auth=github_auth)
try:
r.raise_for_status()
time.sleep(1)
return True
except requests.HTTPError:
# TODO(alpert): Catch IOError or something?
return False
def close_old_issues(close_before, github_auth):
notabug_taggers = collections.Counter()
realbug_taggers = collections.Counter()
all_issues = fetch_issues(github_auth)
for issue in all_issues:
# Only close issues created by KhanBugz
if issue['user']['login'] != "KhanBugz":
continue
issue_created = datetime.datetime.strptime(
issue['created_at'], "%Y-%m-%dT%H:%M:%SZ")
if issue['comments']:
comments = fetch_issue_comments(issue, github_auth)
# Reverse so the last realbug/notabug comment wins
for comment in reversed(comments):
user = comment['user']['login']
body = comment['body'].lower()
if 'realbug' in body:
realbug_taggers[user] += 1
break
elif 'notabug' in body:
notabug_taggers[user] += 1
if close_issue(issue, github_auth):
print "closed issue %s (%s)" % (issue['number'], user)
else:
print "error closing issue %s (%s)" % (issue['number'],
user)
break
elif issue_created < close_before:
if post_issue_comment(issue, AUTOCLOSE_MESSAGE, github_auth):
print "added comment to old issue %s" % issue['number']
else:
print "error adding comment to old issue %s" % issue['number']
if close_issue(issue, github_auth):
print "closed old issue %s" % issue['number']
else:
print "error closing old issue %s" % issue['number']
return notabug_taggers, realbug_taggers
if __name__ == '__main__':
close_before = datetime.datetime.today() - datetime.timedelta(days=8)
print
print "This script will close all issues opened by KhanBugz"
print "with 'notabug' (case-insensitive) in a comment or opened"
print "before", close_before.date(), "with no comments."
print
default_user = "KhanBugz"
github_user = (raw_input("GitHub username [%s]: " % default_user)
or default_user)
github_pass = getpass.getpass()
print
github_auth = (github_user, github_pass)
notabug_taggers, realbug_taggers = close_old_issues(
close_before, github_auth)
print "notabug taggers:"
for tagger in notabug_taggers:
print notabug_taggers[tagger], tagger
print
print "realbug taggers:"
for tagger in realbug_taggers:
print realbug_taggers[tagger], tagger