Last active
December 20, 2015 08:19
-
-
Save bilderbuchi/6099727 to your computer and use it in GitHub Desktop.
Issue tracker raw code. not very userfriendly.
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
""" | |
A set of small helper functions for interacting with Github repositories | |
(primarily openFrameworks) via PyGithub. | |
""" | |
import webbrowser, os, inspect | |
from github import Github | |
def get_repo(user='openframeworks', repo='openFrameworks', | |
token='Github_token.txt', timeout=20): | |
"""Return Github authenticated repo, ready for use""" | |
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) | |
with open(os.path.join(currentdir,token)) as token_file: | |
my_token = token_file.readline().rstrip('\n') | |
G = Github(my_token, timeout=timeout) | |
return G.get_user(user).get_repo(repo) | |
def open_in_browser(list_of_urls): | |
"""Offer to open a list of URLs in the browser.""" | |
if list_of_urls: | |
answer = raw_input('Press "y" to open all issues in the browser, other key to quit:\n') | |
if answer.lower() == 'y': | |
print('Opening...') | |
for u in list_of_urls: | |
webbrowser.open(u) | |
print('Done') |
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
#!/usr/bin/python | |
"""Main script for openFrameworks Github issues visualization.""" | |
from github import Github | |
import matplotlib as mpl | |
import matplotlib.pyplot as plt | |
from matplotlib import legend | |
import numpy as np | |
import datetime, dateutil | |
import times # module for saner time management. See http://nvie.com/posts/introducing-times/ | |
import pickle | |
from itertools import chain | |
from sys import exit | |
# hack for relative import of module | |
# you can probably drop this if github_tools.py is in the same directory as this | |
# script (but it's not in my setup) | |
import os,sys,inspect | |
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) | |
parentdir = os.path.dirname(currentdir) | |
sys.path.insert(0,parentdir) | |
import github_tools | |
# TODO: | |
# possibly use a database instead of pickling: https://github.com/pudo/dataset | |
# issue open duration should not be in recarray | |
#link plots | |
# (opendate, 1), (closedate, -1); cat; sort_by_date; cumsum(col2); plot | |
# same for PR | |
# use PyGithub's new "since" for getting fresh commits only | |
# | |
# other plots: | |
# % issues without label | |
# issue longest silent | |
# longest open issue | |
# most issues closed/opened per week/7day window | |
# % without any comment | |
# most bugs squashed | |
#Github/PyGithub objects are Capitalized! | |
############################################################################### | |
#CONFIGURATION | |
fetch=True # fetch data from github or load from json-serialized file | |
#fetch=False | |
mpl.rc('axes',grid=True, axisbelow=True) | |
mpl.rc('grid',linestyle='-', color='lightgray') | |
mpl.rc('figure', dpi=90) | |
#------------------------------------------------------------------------------------- | |
datefmt = "%Y-%m-%dT%H:%M:%SZ" #2012-05-19T00:28:09Z | |
event_datefmt = "%Y-%m-%d" | |
tmp=[['2008-09-04', '2008-09-09'],['2011-01-10', '2011-01-14'],['2012-02-20', '2012-02-27'],['2013-08-08', '2013-08-14']] | |
OFEventTitles=['OFLab Linz', 'DevCon Pittsburgh', 'DevCon Detroit', 'DevCon Yamaguchi'] | |
OFEvents=[[datetime.datetime.strptime(x,event_datefmt) for x in y] for y in tmp] | |
############################################################################### | |
# Load all we need from Github. Create raw list data | |
if fetch: | |
print 'Fetching fresh data from Github' | |
Repo = github_tools.get_repo() | |
print 'OF has ' + str(Repo.open_issues) + ' open issues.' | |
print('\nGetting issues') | |
Open_Issues=Repo.get_issues(state='open') | |
Closed_Issues=Repo.get_issues(state='closed') | |
print 'Issues received' | |
print('\nGetting tags') | |
Tags=Repo.get_tags() | |
print('Tags received') | |
print('\nGetting commits') | |
Commits=Repo.get_commits() | |
# TODO: find a better/faster way to query this. probably via local git repo | |
print('Commits received') | |
# --------------------------------------------------------------------------- | |
print '\nCreating issues recarray' | |
# unicode strings as objects, otherwise string length is 0! | |
issues_dtype=[('number', int), ('state', object), ('created_at', object), ('closed_at', object), ('duration_open', object)] | |
# create new, empty recarray: | |
issues_recarray=np.recarray((0,),dtype=issues_dtype) | |
for i in chain(Closed_Issues,Open_Issues): | |
issues_recarray.resize(issues_recarray.shape[0]+1) | |
if i.closed_at: | |
closedate=i.closed_at | |
else: | |
closedate=datetime.datetime.now() | |
entry=(i.number, i.state, i.created_at, i.closed_at, closedate-i.created_at) | |
issues_recarray[-1]=entry | |
issues_recarray.sort(order='number') | |
print '%s issues on record' % issues_recarray.shape[0] | |
print '\nCreating commits recarray' | |
commits_dtype=[('sha', object), ('commit_date', object), ('author_date', object)] | |
commits_recarray=np.recarray((0,), dtype=commits_dtype) | |
for c in Commits: | |
commits_recarray.resize(commits_recarray.shape[0]+1) | |
commits_recarray[-1]=(c.sha, c.commit.committer.date, c.commit.author.date) | |
print '%s commits received' % commits_recarray.shape[0] | |
print('\nCreating tags recarray') | |
tags_dtype=[('date', object), ('name', object)] | |
tags_recarray=np.recarray((0,), dtype=tags_dtype) | |
for t in Tags: | |
tags_recarray.resize(tags_recarray.shape[0]+1) | |
tags_recarray[-1]=(t.commit.commit.committer.date, t.name) | |
print '%s tags received' % tags_recarray.shape[0] | |
# --------------------------------------------------------------------------- | |
print "\nSaving data" | |
with open('issues_recarray.pickle', 'wb') as fp: | |
pickle.dump(issues_recarray, fp) | |
with open('commits_recarray.pickle', 'wb') as fp: | |
pickle.dump(commits_recarray, fp) | |
with open('tags_recarray.pickle', 'wb') as fp: | |
pickle.dump(tags_recarray, fp) | |
print "Data saved!\n" | |
############################################################################### | |
# Load lists from file | |
else: | |
print '\nLoading existing data from files' | |
with open('issues_recarray.pickle', 'rb') as fp: | |
issues_recarray = pickle.load(fp) | |
with open('commits_recarray.pickle', 'rb') as fp: | |
commits_recarray = pickle.load(fp) | |
with open('tags_recarray.pickle', 'rb') as fp: | |
tags_recarray = pickle.load(fp) | |
print 'Files loaded!\n' | |
############################################################################### | |
# Process objects. | |
open_issue_count=np.vstack((issues_recarray.created_at, np.ones((len(issues_recarray.created_at))) )) | |
open_issue_count=np.hstack(( open_issue_count, np.vstack((issues_recarray.closed_at[issues_recarray.state == 'closed'], -1*np.ones((len(issues_recarray.closed_at[issues_recarray.state == 'closed']))))) )).T | |
open_issue_count=open_issue_count[open_issue_count[:,0].argsort()] | |
open_issue_count=np.column_stack((open_issue_count, np.cumsum(open_issue_count[:,1], axis=0))) | |
#alternatively, use np.newaxis to get a proper 2D array | |
#print str(np.shape(open_issue_count)) | |
xbegin = min([min(commits_recarray.author_date), min(issues_recarray.created_at)]) | |
xend = datetime.datetime.now() | |
print "Data range: %s days\n" % str((xend-xbegin).days) | |
bin_edges=[xbegin] + dateutil.rrule.rrule(dateutil.rrule.WEEKLY, dtstart = xbegin,byweekday=dateutil.rrule.MO).between(xbegin, xend, inc=False) + [xend] | |
bin_edges=mpl.dates.date2num(bin_edges) | |
#TODO: Calculate average, stddev, max of time-to-fix, open time. | |
############################################################################### | |
#Plot figure | |
fig = plt.figure(figsize=(380/25.4, 200/25.4)) | |
ax = fig.add_subplot(211) | |
plt.title('OF issue tracker statistics - created ' + str(xend.date())) | |
# | |
for t in xrange(tags_recarray.shape[0]): | |
ax.axvline(tags_recarray.date[t],color='y',alpha=0.5) | |
plt.annotate(tags_recarray.name[t], xy=(tags_recarray.date[t], 0.90) ,xycoords=("data", "axes fraction"), ha='right', va='top') | |
for e in xrange(len(OFEventTitles)): | |
ax.axvspan(OFEvents[e][0],OFEvents[e][1],color='y',alpha=0.5) | |
plt.annotate(OFEventTitles[e], xy=(OFEvents[e][0], 0.97) ,xycoords=("data", "axes fraction"), ha='right', va='top') | |
ax.plot(open_issue_count[:,0],open_issue_count[:,2],label='open issues', color='k', alpha=0.8) | |
ax.hist([mpl.dates.date2num(issues_recarray.created_at), mpl.dates.date2num(issues_recarray.closed_at[issues_recarray.state == 'closed'])], histtype='barstacked',bins=bin_edges,label=['created issues','closed issues'], color=['red', 'green'],alpha=0.8) | |
ax.legend(loc='center left') | |
locator=mpl.dates.AutoDateLocator(maxticks=15) | |
ax.xaxis.set_major_locator(locator) | |
ax.xaxis.set_major_formatter(mpl.dates.AutoDateFormatter(locator)) | |
ax.xaxis.grid(False) | |
ax.set_xlim(left=xbegin) | |
ax.tick_params(axis='x', direction='out') | |
# --------------------------------------------------------------------------- | |
ax2 = fig.add_subplot(212, sharex=ax) | |
plt.title('OF commit statistics') | |
for t in xrange(tags_recarray.shape[0]): | |
ax2.axvline(tags_recarray.date[t],color='y',alpha=0.5) | |
plt.annotate(tags_recarray.name[t], xy=(tags_recarray.date[t], 0.90) ,xycoords=("data", "axes fraction"), ha='right', va='top') | |
for e in xrange(len(OFEventTitles)): | |
ax2.axvspan(OFEvents[e][0],OFEvents[e][1],color='y',alpha=0.5) | |
plt.annotate(OFEventTitles[e], xy=(OFEvents[e][0], 0.97) ,xycoords=("data", "axes fraction"), ha='right', va='top') | |
ax2.hist(mpl.dates.date2num(commits_recarray.author_date),bins=bin_edges,label='master commits authored',color='blue',alpha=0.5) | |
ax2.legend(loc='best') | |
ax2.xaxis.set_major_locator(locator) | |
ax2.xaxis.set_major_formatter(mpl.dates.AutoDateFormatter(locator)) | |
ax2.xaxis.grid(False) | |
ax2.set_xlim(left=xbegin) | |
ax2.tick_params(axis='x', direction='out') | |
fig.autofmt_xdate() | |
plt.tight_layout() | |
plt.show() | |
fig.savefig('./autosave/OF_repo_viz_'+str(xend.date())+'.png') | |
print '\nFinished!' | |
############################################################################### |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment