xref: /openbmc/openbmc-test-automation/tools/github_issues_to_csv (revision b4eb9ac191bf7cfb328a9ebc959e350f49a8ede9)
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
28            # Below lines to overcome "TypeError: 'NoneType' object has
29            # no attribute '__getitem__'"
30
31            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')
36            if assignee_resp:
37                owners = ','.join([assignee_login['login'] for
38                                   assignee_login in assignee_resp])
39            else:
40                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')
45
46            # Change the following line to write out additional fields
47            csv_out.writerow([labels.encode('utf-8'),
48                             issue.get('title').encode('utf-8'),
49                             issue.get('state').encode('utf-8'),
50                             issue.get('created_at').split('T')[0],
51                             close_date,
52                             issue.get('html_url').encode('utf-8'),
53                             issue.get('user').get('login').encode('utf-8'),
54                             owners, milestone_resp])
55
56
57def get_issues_from_github_to_csv(name):
58    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)
72        csv_out.writerow(['Labels', 'Title', 'State', 'Open Date',
73                          'Close Date', 'URL', 'Author', 'Assignees',
74                          'Milestone'])
75        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
99parser.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
112password = getpass.getpass("Enter your GitHub Password:")
113
114auth = (username, password)
115
116for repository in args.repositories:
117    get_issues_from_github_to_csv(repository)
118