Created
May 20, 2013 20:02
-
-
Save smerritt/5615053 to your computer and use it in GitHub Desktop.
OpenStack review stats. Started life as http://173.203.107.207/~soren/stats/stats.py.txt, then I went and hacked it up a bunch to do what I wanted.
This file contains hidden or 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
#!/usr/bin/python | |
from collections import defaultdict | |
import calendar | |
import datetime | |
import json | |
import operator | |
import optparse | |
import paramiko | |
from pprint import pprint | |
from tabulate import tabulate | |
import sys | |
optparser = optparse.OptionParser() | |
optparser.add_option('-p', '--project', default='swift', help='Project to generate stats for') | |
optparser.add_option('-d', '--days', type='int', default=30, help='Number of days to consider') | |
optparser.add_option('-c', '--cutoff', type='int', default=1, metavar='N', help='Only show reviewers with at least N reviews') | |
options, args = optparser.parse_args() | |
client = paramiko.SSHClient() | |
client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |
client.load_system_host_keys() | |
client.connect('review.openstack.org', port=29418, key_filename='/Users/torgomatic/.ssh/id_rsa', username='torgomatic') | |
# allow for stackforge/X as well | |
if '/' not in options.project: | |
project = "openstack/" + options.project | |
else: | |
project = options.project | |
stdin, stdout, stderr = client.exec_command('gerrit query project:%s --all-approvals --patch-sets --format JSON' % project) | |
changes = [] | |
for l in stdout: | |
changes += [json.loads(l)] | |
reviews = [] | |
for change in changes: | |
#print json.dumps(change, sort_keys=True, indent=4) | |
for patchset in change.get('patchSets', []): | |
for review in patchset.get('approvals', []): | |
reviews += [review] | |
cut_off = datetime.datetime.now() - datetime.timedelta(days=options.days) | |
ts = calendar.timegm(cut_off.timetuple()) | |
reviews = filter(lambda x:x['grantedOn'] > ts, reviews) | |
def round_to_day(ts): | |
SECONDS_PER_DAY = 60*60*24 | |
return (ts / (SECONDS_PER_DAY)) * SECONDS_PER_DAY | |
scores_by_reviewer = defaultdict(lambda: defaultdict(int)) | |
scores = defaultdict(int) | |
for review in reviews: | |
if review.get('type') != "CRVW": | |
continue | |
reviewer = review['by'].get('username', 'unknown') | |
score = int(review["value"]) | |
scores_by_reviewer[reviewer][score] += 1 | |
scores[score] += 1 | |
table = [] | |
total_reviews = 0 | |
for reviewer, scores in scores_by_reviewer.iteritems(): | |
total = sum(scores.values()) | |
total_reviews += total | |
row = [reviewer, | |
total, | |
scores[-2], | |
scores[-1], | |
scores[1], | |
scores[2]] | |
grumpiness = float(sum((scores[-2], scores[-1]))) / total | |
row.append("%0.1f%%" % (grumpiness * 100)) | |
table.append(row) | |
table.sort(key=operator.itemgetter(1), reverse=True) | |
print tabulate(table, ["Reviewer", "Total Reviews (%d)" % total_reviews, "-2", "-1", "1", "2", "Grumpiness"]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment