| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python | 
 | 2 |  | 
 | 3 | r""" | 
 | 4 | Exports issues from a list of repositories to individual CSV files. | 
 | 5 | Uses basic authentication (GitHub username + password) to retrieve issues | 
 | 6 | from a repository that username has access to. Supports GitHub API v3. | 
 | 7 | """ | 
 | 8 | import argparse | 
 | 9 | import csv | 
| Sivas SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 10 | import getpass | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 11 | import requests | 
 | 12 |  | 
 | 13 | auth = None | 
 | 14 | states = 'all' | 
 | 15 |  | 
 | 16 |  | 
 | 17 | def 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 SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 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 |  | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 37 |             # Change the following line to write out additional fields | 
 | 38 |             csv_out.writerow([labels.encode('utf-8'), | 
| Sivas SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 39 |                              issue.get('title').encode('utf-8'), | 
 | 40 |                              issue.get('state').encode('utf-8'), | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 41 |                              date.encode('utf-8'), | 
| Sivas SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 42 |                              issue.get('html_url').encode('utf-8'), | 
 | 43 |                              issue.get('user').get('login').encode('utf-8'), | 
 | 44 |                              assignee_resp]) | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 45 |  | 
 | 46 |  | 
| Sivas SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 47 | def get_issues_from_github_to_csv(name): | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 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) | 
| Sivas SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 62 |         csv_out.writerow(['Labels', 'Title', 'State', 'Date', 'URL', 'Author', | 
 | 63 |                          'Assignee']) | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 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 |  | 
 | 82 | parser = argparse.ArgumentParser(description="Write GitHub repository issues " | 
 | 83 |                                              "to CSV file.") | 
 | 84 |  | 
 | 85 | parser.add_argument('username', nargs='+', help="GitHub user name, " | 
 | 86 |                     "formatted as 'username'") | 
 | 87 |  | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 88 | parser.add_argument('repositories', nargs='+', help="Repository names, " | 
 | 89 |                     "formatted as 'basereponame/repo'") | 
 | 90 |  | 
 | 91 | parser.add_argument('--all', action='store_true', help="Returns both open " | 
 | 92 |                     "and closed issues.") | 
 | 93 | args = parser.parse_args() | 
 | 94 |  | 
 | 95 | if args.all: | 
 | 96 |     state = 'all' | 
 | 97 |  | 
 | 98 | for argusername in args.username: | 
 | 99 |     username = argusername | 
 | 100 |  | 
| Sivas SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 101 | password = getpass.getpass("Enter your GitHub Password:") | 
| Sivas SRR | a464a7c | 2017-02-19 23:35:59 -0600 | [diff] [blame] | 102 |  | 
 | 103 | auth = (username, password) | 
 | 104 |  | 
 | 105 | for repository in args.repositories: | 
| Sivas SRR | 9fe1b12 | 2017-03-05 22:29:28 -0600 | [diff] [blame] | 106 |     get_issues_from_github_to_csv(repository) |