xref: /openbmc/openbmc-test-automation/tools/github_issues_to_csv (revision 9fe1b12e8b0e29a2a745d3a8ff1031b956bd03b9)
1a464a7ceSSivas SRR#!/usr/bin/env python
2a464a7ceSSivas SRR
3a464a7ceSSivas SRRr"""
4a464a7ceSSivas SRRExports issues from a list of repositories to individual CSV files.
5a464a7ceSSivas SRRUses basic authentication (GitHub username + password) to retrieve issues
6a464a7ceSSivas SRRfrom a repository that username has access to. Supports GitHub API v3.
7a464a7ceSSivas SRR"""
8a464a7ceSSivas SRRimport argparse
9a464a7ceSSivas SRRimport csv
10*9fe1b12eSSivas SRRimport getpass
11a464a7ceSSivas SRRimport requests
12a464a7ceSSivas SRR
13a464a7ceSSivas SRRauth = None
14a464a7ceSSivas SRRstates = 'all'
15a464a7ceSSivas SRR
16a464a7ceSSivas SRR
17a464a7ceSSivas SRRdef write_issues(response, csv_out):
18a464a7ceSSivas SRR    r"""
19a464a7ceSSivas SRR    Parses JSON response and writes to CSV.
20a464a7ceSSivas SRR    """
21a464a7ceSSivas SRR    print response
22a464a7ceSSivas SRR    if response.status_code != 200:
23a464a7ceSSivas SRR        raise Exception(response.status_code)
24a464a7ceSSivas SRR    for issue in response.json():
25a464a7ceSSivas SRR        if 'pull_request' not in issue:
26a464a7ceSSivas SRR            labels = ', '.join([l['name'] for l in issue['labels']])
27*9fe1b12eSSivas SRR            date = issue.get('created_at').split('T')[0]
28*9fe1b12eSSivas SRR            # Below lines to overcome "TypeError: 'NoneType' object has
29*9fe1b12eSSivas SRR            # no attribute '__getitem__'"
30*9fe1b12eSSivas SRR
31*9fe1b12eSSivas SRR            assignee_resp = issue.get('assignee', 'Not Assigned')
32*9fe1b12eSSivas SRR            if assignee_resp:
33*9fe1b12eSSivas SRR                assignee_resp = assignee_resp.get('login').encode('utf-8')
34*9fe1b12eSSivas SRR            else:
35*9fe1b12eSSivas SRR                assignee_resp = "Not Assigned"
36*9fe1b12eSSivas SRR
37a464a7ceSSivas SRR            # Change the following line to write out additional fields
38a464a7ceSSivas SRR            csv_out.writerow([labels.encode('utf-8'),
39*9fe1b12eSSivas SRR                             issue.get('title').encode('utf-8'),
40*9fe1b12eSSivas SRR                             issue.get('state').encode('utf-8'),
41a464a7ceSSivas SRR                             date.encode('utf-8'),
42*9fe1b12eSSivas SRR                             issue.get('html_url').encode('utf-8'),
43*9fe1b12eSSivas SRR                             issue.get('user').get('login').encode('utf-8'),
44*9fe1b12eSSivas SRR                             assignee_resp])
45a464a7ceSSivas SRR
46a464a7ceSSivas SRR
47*9fe1b12eSSivas SRRdef get_issues_from_github_to_csv(name):
48a464a7ceSSivas SRR    r"""
49a464a7ceSSivas SRR    Requests issues from GitHub API and writes to CSV file.
50a464a7ceSSivas SRR    """
51a464a7ceSSivas SRR    print name
52a464a7ceSSivas SRR    print states
53a464a7ceSSivas SRR    l_url = 'https://api.github.com/repos/{}/issues?state={}'.format(name,
54a464a7ceSSivas SRR                                                                     states)
55a464a7ceSSivas SRR    print l_url
56a464a7ceSSivas SRR    # 'https://api.github.com/repos/{}/issues?state={}'.format(name, state)
57a464a7ceSSivas SRR    response = requests.get(l_url, auth=auth)
58a464a7ceSSivas SRR
59a464a7ceSSivas SRR    csvfilename = '{}-issues.csv'.format(name.replace('/', '-'))
60a464a7ceSSivas SRR    with open(csvfilename, 'w') as csvfile:
61a464a7ceSSivas SRR        csv_out = csv.writer(csvfile)
62*9fe1b12eSSivas SRR        csv_out.writerow(['Labels', 'Title', 'State', 'Date', 'URL', 'Author',
63*9fe1b12eSSivas SRR                         'Assignee'])
64a464a7ceSSivas SRR        write_issues(response, csv_out)
65a464a7ceSSivas SRR
66a464a7ceSSivas SRR        # Multiple requests are required if response is paged
67a464a7ceSSivas SRR        if 'link' in response.headers:
68a464a7ceSSivas SRR            pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in
69a464a7ceSSivas SRR                     (link.split(';') for link in
70a464a7ceSSivas SRR                      response.headers['link'].split(','))}
71a464a7ceSSivas SRR            while 'last' in pages and 'next' in pages:
72a464a7ceSSivas SRR                pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in
73a464a7ceSSivas SRR                         (link.split(';') for link in
74a464a7ceSSivas SRR                          response.headers['link'].split(','))}
75a464a7ceSSivas SRR                response = requests.get(pages['next'], auth=auth)
76a464a7ceSSivas SRR                write_issues(response, csv_out)
77a464a7ceSSivas SRR                if pages['next'] == pages['last']:
78a464a7ceSSivas SRR                    break
79a464a7ceSSivas SRR
80a464a7ceSSivas SRR        csvfile.close()
81a464a7ceSSivas SRR
82a464a7ceSSivas SRRparser = argparse.ArgumentParser(description="Write GitHub repository issues "
83a464a7ceSSivas SRR                                             "to CSV file.")
84a464a7ceSSivas SRR
85a464a7ceSSivas SRRparser.add_argument('username', nargs='+', help="GitHub user name, "
86a464a7ceSSivas SRR                    "formatted as 'username'")
87a464a7ceSSivas SRR
88a464a7ceSSivas SRRparser.add_argument('repositories', nargs='+', help="Repository names, "
89a464a7ceSSivas SRR                    "formatted as 'basereponame/repo'")
90a464a7ceSSivas SRR
91a464a7ceSSivas SRRparser.add_argument('--all', action='store_true', help="Returns both open "
92a464a7ceSSivas SRR                    "and closed issues.")
93a464a7ceSSivas SRRargs = parser.parse_args()
94a464a7ceSSivas SRR
95a464a7ceSSivas SRRif args.all:
96a464a7ceSSivas SRR    state = 'all'
97a464a7ceSSivas SRR
98a464a7ceSSivas SRRfor argusername in args.username:
99a464a7ceSSivas SRR    username = argusername
100a464a7ceSSivas SRR
101*9fe1b12eSSivas SRRpassword = getpass.getpass("Enter your GitHub Password:")
102a464a7ceSSivas SRR
103a464a7ceSSivas SRRauth = (username, password)
104a464a7ceSSivas SRR
105a464a7ceSSivas SRRfor repository in args.repositories:
106*9fe1b12eSSivas SRR    get_issues_from_github_to_csv(repository)
107