1*a464a7ceSSivas SRR#!/usr/bin/env python 2*a464a7ceSSivas SRR 3*a464a7ceSSivas SRRr""" 4*a464a7ceSSivas SRRExports issues from a list of repositories to individual CSV files. 5*a464a7ceSSivas SRRUses basic authentication (GitHub username + password) to retrieve issues 6*a464a7ceSSivas SRRfrom a repository that username has access to. Supports GitHub API v3. 7*a464a7ceSSivas SRR""" 8*a464a7ceSSivas SRRimport argparse 9*a464a7ceSSivas SRRimport csv 10*a464a7ceSSivas SRRfrom getpass import getpass 11*a464a7ceSSivas SRRimport requests 12*a464a7ceSSivas SRR 13*a464a7ceSSivas SRRauth = None 14*a464a7ceSSivas SRRstates = 'all' 15*a464a7ceSSivas SRR 16*a464a7ceSSivas SRR 17*a464a7ceSSivas SRRdef write_issues(response, csv_out): 18*a464a7ceSSivas SRR r""" 19*a464a7ceSSivas SRR Parses JSON response and writes to CSV. 20*a464a7ceSSivas SRR """ 21*a464a7ceSSivas SRR print response 22*a464a7ceSSivas SRR if response.status_code != 200: 23*a464a7ceSSivas SRR raise Exception(response.status_code) 24*a464a7ceSSivas SRR for issue in response.json(): 25*a464a7ceSSivas SRR if 'pull_request' not in issue: 26*a464a7ceSSivas SRR labels = ', '.join([l['name'] for l in issue['labels']]) 27*a464a7ceSSivas SRR date = issue['created_at'].split('T')[0] 28*a464a7ceSSivas SRR # Change the following line to write out additional fields 29*a464a7ceSSivas SRR csv_out.writerow([labels.encode('utf-8'), 30*a464a7ceSSivas SRR issue['title'].encode('utf-8'), 31*a464a7ceSSivas SRR issue['state'].encode('utf-8'), 32*a464a7ceSSivas SRR date.encode('utf-8'), 33*a464a7ceSSivas SRR issue['html_url'].encode('utf-8'), 34*a464a7ceSSivas SRR issue['user']['login'].encode('utf-8')]) 35*a464a7ceSSivas SRR 36*a464a7ceSSivas SRR 37*a464a7ceSSivas SRRdef get_github_issues(name): 38*a464a7ceSSivas SRR r""" 39*a464a7ceSSivas SRR Requests issues from GitHub API and writes to CSV file. 40*a464a7ceSSivas SRR """ 41*a464a7ceSSivas SRR print name 42*a464a7ceSSivas SRR print states 43*a464a7ceSSivas SRR l_url = 'https://api.github.com/repos/{}/issues?state={}'.format(name, 44*a464a7ceSSivas SRR states) 45*a464a7ceSSivas SRR print l_url 46*a464a7ceSSivas SRR # 'https://api.github.com/repos/{}/issues?state={}'.format(name, state) 47*a464a7ceSSivas SRR response = requests.get(l_url, auth=auth) 48*a464a7ceSSivas SRR 49*a464a7ceSSivas SRR csvfilename = '{}-issues.csv'.format(name.replace('/', '-')) 50*a464a7ceSSivas SRR with open(csvfilename, 'w') as csvfile: 51*a464a7ceSSivas SRR csv_out = csv.writer(csvfile) 52*a464a7ceSSivas SRR csv_out.writerow(['Labels', 'Title', 'State', 'Date', 'URL', 'Author']) 53*a464a7ceSSivas SRR write_issues(response, csv_out) 54*a464a7ceSSivas SRR 55*a464a7ceSSivas SRR # Multiple requests are required if response is paged 56*a464a7ceSSivas SRR if 'link' in response.headers: 57*a464a7ceSSivas SRR pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in 58*a464a7ceSSivas SRR (link.split(';') for link in 59*a464a7ceSSivas SRR response.headers['link'].split(','))} 60*a464a7ceSSivas SRR while 'last' in pages and 'next' in pages: 61*a464a7ceSSivas SRR pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in 62*a464a7ceSSivas SRR (link.split(';') for link in 63*a464a7ceSSivas SRR response.headers['link'].split(','))} 64*a464a7ceSSivas SRR response = requests.get(pages['next'], auth=auth) 65*a464a7ceSSivas SRR write_issues(response, csv_out) 66*a464a7ceSSivas SRR if pages['next'] == pages['last']: 67*a464a7ceSSivas SRR break 68*a464a7ceSSivas SRR 69*a464a7ceSSivas SRR csvfile.close() 70*a464a7ceSSivas SRR 71*a464a7ceSSivas SRRparser = argparse.ArgumentParser(description="Write GitHub repository issues " 72*a464a7ceSSivas SRR "to CSV file.") 73*a464a7ceSSivas SRR 74*a464a7ceSSivas SRRparser.add_argument('username', nargs='+', help="GitHub user name, " 75*a464a7ceSSivas SRR "formatted as 'username'") 76*a464a7ceSSivas SRR 77*a464a7ceSSivas SRRparser.add_argument('password', nargs='+', help="GitHub username password, " 78*a464a7ceSSivas SRR "formatted as 'password'") 79*a464a7ceSSivas SRR 80*a464a7ceSSivas SRRparser.add_argument('repositories', nargs='+', help="Repository names, " 81*a464a7ceSSivas SRR "formatted as 'basereponame/repo'") 82*a464a7ceSSivas SRR 83*a464a7ceSSivas SRRparser.add_argument('--all', action='store_true', help="Returns both open " 84*a464a7ceSSivas SRR "and closed issues.") 85*a464a7ceSSivas SRRargs = parser.parse_args() 86*a464a7ceSSivas SRR 87*a464a7ceSSivas SRRif args.all: 88*a464a7ceSSivas SRR state = 'all' 89*a464a7ceSSivas SRR 90*a464a7ceSSivas SRRfor argusername in args.username: 91*a464a7ceSSivas SRR username = argusername 92*a464a7ceSSivas SRR 93*a464a7ceSSivas SRRfor argpassword in args.password: 94*a464a7ceSSivas SRR password = argpassword 95*a464a7ceSSivas SRR 96*a464a7ceSSivas SRRauth = (username, password) 97*a464a7ceSSivas SRR 98*a464a7ceSSivas SRRfor repository in args.repositories: 99*a464a7ceSSivas SRR get_github_issues(repository) 100