blob: a8dd6b3b12d4891dd749679e32ebf51319cd8cbe [file] [log] [blame]
Sivas SRRa464a7c2017-02-19 23:35:59 -06001#!/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
Sivas SRR9fe1b122017-03-05 22:29:28 -060010import getpass
Sivas SRRa464a7c2017-02-19 23:35:59 -060011import 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']])
Sivas SRR9fe1b122017-03-05 22:29:28 -060027 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
Sivas SRRa464a7c2017-02-19 23:35:59 -060037 # Change the following line to write out additional fields
38 csv_out.writerow([labels.encode('utf-8'),
Sivas SRR9fe1b122017-03-05 22:29:28 -060039 issue.get('title').encode('utf-8'),
40 issue.get('state').encode('utf-8'),
Sivas SRRa464a7c2017-02-19 23:35:59 -060041 date.encode('utf-8'),
Sivas SRR9fe1b122017-03-05 22:29:28 -060042 issue.get('html_url').encode('utf-8'),
43 issue.get('user').get('login').encode('utf-8'),
44 assignee_resp])
Sivas SRRa464a7c2017-02-19 23:35:59 -060045
46
Sivas SRR9fe1b122017-03-05 22:29:28 -060047def get_issues_from_github_to_csv(name):
Sivas SRRa464a7c2017-02-19 23:35:59 -060048 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)
Sivas SRR9fe1b122017-03-05 22:29:28 -060062 csv_out.writerow(['Labels', 'Title', 'State', 'Date', 'URL', 'Author',
63 'Assignee'])
Sivas SRRa464a7c2017-02-19 23:35:59 -060064 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
Sivas SRRa464a7c2017-02-19 23:35:59 -060088parser.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
Sivas SRR9fe1b122017-03-05 22:29:28 -0600101password = getpass.getpass("Enter your GitHub Password:")
Sivas SRRa464a7c2017-02-19 23:35:59 -0600102
103auth = (username, password)
104
105for repository in args.repositories:
Sivas SRR9fe1b122017-03-05 22:29:28 -0600106 get_issues_from_github_to_csv(repository)