blob: e1e0221c5ee42b0e9ecefb3dc2a92cbdefcea674 [file] [log] [blame]
#!/usr/bin/env python3
r"""
Exports issues from a list of repositories to individual CSV files.
Uses basic authentication (GitHub username + password) to retrieve issues
from a repository that username has access to. Supports GitHub API v3.
"""
import argparse
import csv
import getpass
import requests
auth = None
states = 'all'
def write_issues(response, csv_out):
r"""
Parses JSON response and writes to CSV.
"""
print(response)
if response.status_code != 200:
raise Exception(response.status_code)
for issue in response.json():
if 'pull_request' not in issue:
labels = ', '.join([l['name'] for l in issue['labels']])
# Below lines to overcome "TypeError: 'NoneType' object has
# no attribute '__getitem__'"
close_date = issue.get('closed_at')
if close_date:
close_date = issue.get('closed_at').split('T')[0]
assignee_resp = issue.get('assignees', 'Not Assigned')
if assignee_resp:
owners = ','.join([assignee_login['login'] for
assignee_login in assignee_resp])
else:
owners = "Not Assigned"
milestone_resp = issue.get('milestone', 'Not Assigned')
if milestone_resp:
milestone_resp = milestone_resp['title'].encode('utf-8')
# Change the following line to write out additional fields
csv_out.writerow([labels.encode('utf-8'),
issue.get('title').encode('utf-8'),
issue.get('state').encode('utf-8'),
issue.get('created_at').split('T')[0],
close_date,
issue.get('html_url').encode('utf-8'),
issue.get('user').get('login').encode('utf-8'),
owners, milestone_resp])
def get_issues_from_github_to_csv(name, response):
r"""
Requests issues from GitHub API and writes to CSV file.
Description of argument(s):
name Name of the GitHub repository
response GitHub repository response
"""
print(name)
print(states)
# Multiple requests are required if response is paged
if 'link' in response.headers:
pages = {rel[6:-1]: url[url.index('<') + 1:-1] for url, rel in
(link.split(';') for link in
response.headers['link'].split(','))}
while 'last' in pages and 'next' in pages:
pages = {rel[6:-1]: url[url.index('<') + 1:-1] for url, rel in
(link.split(';') for link in
response.headers['link'].split(','))}
response = requests.get(pages['next'], auth=auth)
write_issues(response, csv_out)
if pages['next'] == pages['last']:
break
parser = argparse.ArgumentParser(description="Write GitHub repository issues "
"to CSV file.")
parser.add_argument('username', nargs='?', help="GitHub user name, "
"formatted as 'username'")
parser.add_argument('repositories', nargs='+', help="Repository names, "
"formatted as 'basereponame/repo'")
parser.add_argument('--all', action='store_true', help="Returns both open "
"and closed issues.")
args = parser.parse_args()
if args.all:
state = 'all'
username = args.username
password = getpass.getpass("Enter your GitHub Password:")
auth = (username, password)
# To set the csv filename
csvfilename = ""
for repository in args.repositories:
csvfilename_temp = '{}'.format(repository.replace('/', '-'))
csvfilename = csvfilename + csvfilename_temp
csvfilename = csvfilename + '-issues.csv'
with open(csvfilename, 'w') as csvfileout:
csv_out = csv.writer(csvfileout)
csv_out.writerow(['Labels', 'Title', 'State', 'Open Date',
'Close Date', 'URL', 'Author', 'Assignees',
'Milestone'])
for repository in args.repositories:
l_url = 'https://api.github.com/repos/{}/issues?state={}'
l_url = l_url.format(repository, states)
response = requests.get(l_url, auth=auth)
write_issues(response, csv_out)
get_issues_from_github_to_csv(repository, response)
csvfileout.close()