xref: /openbmc/openbmc-test-automation/tools/github_issues_to_csv (revision b4eb9ac191bf7cfb328a9ebc959e350f49a8ede9)
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
109fe1b12eSSivas 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*b4eb9ac1SSivas SRR
289fe1b12eSSivas SRR            # Below lines to overcome "TypeError: 'NoneType' object has
299fe1b12eSSivas SRR            # no attribute '__getitem__'"
309fe1b12eSSivas SRR
31*b4eb9ac1SSivas SRR            close_date = issue.get('closed_at')
32*b4eb9ac1SSivas SRR            if close_date:
33*b4eb9ac1SSivas SRR                close_date = issue.get('closed_at').split('T')[0]
34*b4eb9ac1SSivas SRR
35*b4eb9ac1SSivas SRR            assignee_resp = issue.get('assignees', 'Not Assigned')
369fe1b12eSSivas SRR            if assignee_resp:
37*b4eb9ac1SSivas SRR                owners = ','.join([assignee_login['login'] for
38*b4eb9ac1SSivas SRR                                   assignee_login in assignee_resp])
399fe1b12eSSivas SRR            else:
40*b4eb9ac1SSivas SRR                owners = "Not Assigned"
41*b4eb9ac1SSivas SRR
42*b4eb9ac1SSivas SRR            milestone_resp = issue.get('milestone', 'Not Assigned')
43*b4eb9ac1SSivas SRR            if milestone_resp:
44*b4eb9ac1SSivas SRR                milestone_resp = milestone_resp['title'].encode('utf-8')
459fe1b12eSSivas SRR
46a464a7ceSSivas SRR            # Change the following line to write out additional fields
47a464a7ceSSivas SRR            csv_out.writerow([labels.encode('utf-8'),
489fe1b12eSSivas SRR                             issue.get('title').encode('utf-8'),
499fe1b12eSSivas SRR                             issue.get('state').encode('utf-8'),
50*b4eb9ac1SSivas SRR                             issue.get('created_at').split('T')[0],
51*b4eb9ac1SSivas SRR                             close_date,
529fe1b12eSSivas SRR                             issue.get('html_url').encode('utf-8'),
539fe1b12eSSivas SRR                             issue.get('user').get('login').encode('utf-8'),
54*b4eb9ac1SSivas SRR                             owners, milestone_resp])
55a464a7ceSSivas SRR
56a464a7ceSSivas SRR
579fe1b12eSSivas SRRdef get_issues_from_github_to_csv(name):
58a464a7ceSSivas SRR    r"""
59a464a7ceSSivas SRR    Requests issues from GitHub API and writes to CSV file.
60a464a7ceSSivas SRR    """
61a464a7ceSSivas SRR    print name
62a464a7ceSSivas SRR    print states
63a464a7ceSSivas SRR    l_url = 'https://api.github.com/repos/{}/issues?state={}'.format(name,
64a464a7ceSSivas SRR                                                                     states)
65a464a7ceSSivas SRR    print l_url
66a464a7ceSSivas SRR    # 'https://api.github.com/repos/{}/issues?state={}'.format(name, state)
67a464a7ceSSivas SRR    response = requests.get(l_url, auth=auth)
68a464a7ceSSivas SRR
69a464a7ceSSivas SRR    csvfilename = '{}-issues.csv'.format(name.replace('/', '-'))
70a464a7ceSSivas SRR    with open(csvfilename, 'w') as csvfile:
71a464a7ceSSivas SRR        csv_out = csv.writer(csvfile)
72*b4eb9ac1SSivas SRR        csv_out.writerow(['Labels', 'Title', 'State', 'Open Date',
73*b4eb9ac1SSivas SRR                          'Close Date', 'URL', 'Author', 'Assignees',
74*b4eb9ac1SSivas SRR                          'Milestone'])
75a464a7ceSSivas SRR        write_issues(response, csv_out)
76a464a7ceSSivas SRR
77a464a7ceSSivas SRR        # Multiple requests are required if response is paged
78a464a7ceSSivas SRR        if 'link' in response.headers:
79a464a7ceSSivas SRR            pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in
80a464a7ceSSivas SRR                     (link.split(';') for link in
81a464a7ceSSivas SRR                      response.headers['link'].split(','))}
82a464a7ceSSivas SRR            while 'last' in pages and 'next' in pages:
83a464a7ceSSivas SRR                pages = {rel[6:-1]: url[url.index('<')+1:-1] for url, rel in
84a464a7ceSSivas SRR                         (link.split(';') for link in
85a464a7ceSSivas SRR                          response.headers['link'].split(','))}
86a464a7ceSSivas SRR                response = requests.get(pages['next'], auth=auth)
87a464a7ceSSivas SRR                write_issues(response, csv_out)
88a464a7ceSSivas SRR                if pages['next'] == pages['last']:
89a464a7ceSSivas SRR                    break
90a464a7ceSSivas SRR
91a464a7ceSSivas SRR        csvfile.close()
92a464a7ceSSivas SRR
93a464a7ceSSivas SRRparser = argparse.ArgumentParser(description="Write GitHub repository issues "
94a464a7ceSSivas SRR                                             "to CSV file.")
95a464a7ceSSivas SRR
96a464a7ceSSivas SRRparser.add_argument('username', nargs='+', help="GitHub user name, "
97a464a7ceSSivas SRR                    "formatted as 'username'")
98a464a7ceSSivas SRR
99a464a7ceSSivas SRRparser.add_argument('repositories', nargs='+', help="Repository names, "
100a464a7ceSSivas SRR                    "formatted as 'basereponame/repo'")
101a464a7ceSSivas SRR
102a464a7ceSSivas SRRparser.add_argument('--all', action='store_true', help="Returns both open "
103a464a7ceSSivas SRR                    "and closed issues.")
104a464a7ceSSivas SRRargs = parser.parse_args()
105a464a7ceSSivas SRR
106a464a7ceSSivas SRRif args.all:
107a464a7ceSSivas SRR    state = 'all'
108a464a7ceSSivas SRR
109a464a7ceSSivas SRRfor argusername in args.username:
110a464a7ceSSivas SRR    username = argusername
111a464a7ceSSivas SRR
1129fe1b12eSSivas SRRpassword = getpass.getpass("Enter your GitHub Password:")
113a464a7ceSSivas SRR
114a464a7ceSSivas SRRauth = (username, password)
115a464a7ceSSivas SRR
116a464a7ceSSivas SRRfor repository in args.repositories:
1179fe1b12eSSivas SRR    get_issues_from_github_to_csv(repository)
118