blob: 08ae2b4fe4d8dbb341d714d7717079d156b35834 [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 SRRb4eb9ac2017-03-16 01:13:03 -050027
Sivas SRR9fe1b122017-03-05 22:29:28 -060028 # Below lines to overcome "TypeError: 'NoneType' object has
29 # no attribute '__getitem__'"
30
Sivas SRRb4eb9ac2017-03-16 01:13:03 -050031 close_date = issue.get('closed_at')
32 if close_date:
33 close_date = issue.get('closed_at').split('T')[0]
34
35 assignee_resp = issue.get('assignees', 'Not Assigned')
Sivas SRR9fe1b122017-03-05 22:29:28 -060036 if assignee_resp:
Sivas SRRb4eb9ac2017-03-16 01:13:03 -050037 owners = ','.join([assignee_login['login'] for
38 assignee_login in assignee_resp])
Sivas SRR9fe1b122017-03-05 22:29:28 -060039 else:
Sivas SRRb4eb9ac2017-03-16 01:13:03 -050040 owners = "Not Assigned"
41
42 milestone_resp = issue.get('milestone', 'Not Assigned')
43 if milestone_resp:
44 milestone_resp = milestone_resp['title'].encode('utf-8')
Sivas SRR9fe1b122017-03-05 22:29:28 -060045
Sivas SRRa464a7c2017-02-19 23:35:59 -060046 # Change the following line to write out additional fields
47 csv_out.writerow([labels.encode('utf-8'),
Sivas SRR9fe1b122017-03-05 22:29:28 -060048 issue.get('title').encode('utf-8'),
49 issue.get('state').encode('utf-8'),
Sivas SRRb4eb9ac2017-03-16 01:13:03 -050050 issue.get('created_at').split('T')[0],
51 close_date,
Sivas SRR9fe1b122017-03-05 22:29:28 -060052 issue.get('html_url').encode('utf-8'),
53 issue.get('user').get('login').encode('utf-8'),
Sivas SRRb4eb9ac2017-03-16 01:13:03 -050054 owners, milestone_resp])
Sivas SRRa464a7c2017-02-19 23:35:59 -060055
56
Sivas SRR9fe1b122017-03-05 22:29:28 -060057def get_issues_from_github_to_csv(name):
Sivas SRRa464a7c2017-02-19 23:35:59 -060058 r"""
59 Requests issues from GitHub API and writes to CSV file.
60 """
61 print name
62 print states
63 l_url = 'https://api.github.com/repos/{}/issues?state={}'.format(name,
64 states)
65 print l_url
66 # 'https://api.github.com/repos/{}/issues?state={}'.format(name, state)
67 response = requests.get(l_url, auth=auth)
68
69 csvfilename = '{}-issues.csv'.format(name.replace('/', '-'))
70 with open(csvfilename, 'w') as csvfile:
71 csv_out = csv.writer(csvfile)
Sivas SRRb4eb9ac2017-03-16 01:13:03 -050072 csv_out.writerow(['Labels', 'Title', 'State', 'Open Date',
73 'Close Date', 'URL', 'Author', 'Assignees',
74 'Milestone'])
Sivas SRRa464a7c2017-02-19 23:35:59 -060075 write_issues(response, csv_out)
76
77 # Multiple requests are required if response is paged
78 if 'link' in response.headers:
79 pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in
80 (link.split(';') for link in
81 response.headers['link'].split(','))}
82 while 'last' in pages and 'next' in pages:
83 pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in
84 (link.split(';') for link in
85 response.headers['link'].split(','))}
86 response = requests.get(pages['next'], auth=auth)
87 write_issues(response, csv_out)
88 if pages['next'] == pages['last']:
89 break
90
91 csvfile.close()
92
93parser = argparse.ArgumentParser(description="Write GitHub repository issues "
94 "to CSV file.")
95
96parser.add_argument('username', nargs='+', help="GitHub user name, "
97 "formatted as 'username'")
98
Sivas SRRa464a7c2017-02-19 23:35:59 -060099parser.add_argument('repositories', nargs='+', help="Repository names, "
100 "formatted as 'basereponame/repo'")
101
102parser.add_argument('--all', action='store_true', help="Returns both open "
103 "and closed issues.")
104args = parser.parse_args()
105
106if args.all:
107 state = 'all'
108
109for argusername in args.username:
110 username = argusername
111
Sivas SRR9fe1b122017-03-05 22:29:28 -0600112password = getpass.getpass("Enter your GitHub Password:")
Sivas SRRa464a7c2017-02-19 23:35:59 -0600113
114auth = (username, password)
115
116for repository in args.repositories:
Sivas SRR9fe1b122017-03-05 22:29:28 -0600117 get_issues_from_github_to_csv(repository)