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