xref: /openbmc/openbmc-test-automation/tools/github_issues_to_csv (revision e7e9171e96b36ae0214bb577bf7cf74b3f6a8359)
1*e7e9171eSGeorge Keishing#!/usr/bin/env python3
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    """
2165dbeaadSvinaybs6    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']])
27b4eb9ac1SSivas SRR
289fe1b12eSSivas SRR            # Below lines to overcome "TypeError: 'NoneType' object has
299fe1b12eSSivas SRR            # no attribute '__getitem__'"
309fe1b12eSSivas SRR
31b4eb9ac1SSivas SRR            close_date = issue.get('closed_at')
32b4eb9ac1SSivas SRR            if close_date:
33b4eb9ac1SSivas SRR                close_date = issue.get('closed_at').split('T')[0]
34b4eb9ac1SSivas SRR
35b4eb9ac1SSivas SRR            assignee_resp = issue.get('assignees', 'Not Assigned')
369fe1b12eSSivas SRR            if assignee_resp:
37b4eb9ac1SSivas SRR                owners = ','.join([assignee_login['login'] for
38b4eb9ac1SSivas SRR                                   assignee_login in assignee_resp])
399fe1b12eSSivas SRR            else:
40b4eb9ac1SSivas SRR                owners = "Not Assigned"
41b4eb9ac1SSivas SRR
42b4eb9ac1SSivas SRR            milestone_resp = issue.get('milestone', 'Not Assigned')
43b4eb9ac1SSivas SRR            if milestone_resp:
44b4eb9ac1SSivas 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'),
50b4eb9ac1SSivas SRR                              issue.get('created_at').split('T')[0],
51b4eb9ac1SSivas SRR                              close_date,
529fe1b12eSSivas SRR                              issue.get('html_url').encode('utf-8'),
539fe1b12eSSivas SRR                              issue.get('user').get('login').encode('utf-8'),
54b4eb9ac1SSivas SRR                              owners, milestone_resp])
55a464a7ceSSivas SRR
56a464a7ceSSivas SRR
570419fb0aSSivas SRRdef get_issues_from_github_to_csv(name, response):
58a464a7ceSSivas SRR    r"""
59a464a7ceSSivas SRR    Requests issues from GitHub API and writes to CSV file.
600419fb0aSSivas SRR    Description of argument(s):
610419fb0aSSivas SRR    name  Name of the GitHub repository
620419fb0aSSivas SRR    response  GitHub repository response
63a464a7ceSSivas SRR    """
6465dbeaadSvinaybs6    print(name)
6565dbeaadSvinaybs6    print(states)
66a464a7ceSSivas SRR
67a464a7ceSSivas SRR    # Multiple requests are required if response is paged
68a464a7ceSSivas SRR    if 'link' in response.headers:
69a464a7ceSSivas SRR        pages = {rel[6:-1]: url[url.index('<') + 1:-1] for url, rel in
70a464a7ceSSivas SRR                 (link.split(';') for link in
71a464a7ceSSivas SRR                  response.headers['link'].split(','))}
72a464a7ceSSivas SRR        while 'last' in pages and 'next' in pages:
73a464a7ceSSivas SRR            pages = {rel[6:-1]: url[url.index('<') + 1:-1] for url, rel in
74a464a7ceSSivas SRR                     (link.split(';') for link in
75a464a7ceSSivas SRR                      response.headers['link'].split(','))}
76a464a7ceSSivas SRR            response = requests.get(pages['next'], auth=auth)
77a464a7ceSSivas SRR            write_issues(response, csv_out)
78a464a7ceSSivas SRR            if pages['next'] == pages['last']:
79a464a7ceSSivas SRR                break
80a464a7ceSSivas SRR
81a464a7ceSSivas SRR
82a464a7ceSSivas SRRparser = argparse.ArgumentParser(description="Write GitHub repository issues "
83a464a7ceSSivas SRR                                             "to CSV file.")
84a464a7ceSSivas SRR
850419fb0aSSivas 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.")
930419fb0aSSivas SRR
94a464a7ceSSivas SRRargs = parser.parse_args()
95a464a7ceSSivas SRR
96a464a7ceSSivas SRRif args.all:
97a464a7ceSSivas SRR    state = 'all'
98a464a7ceSSivas SRR
990419fb0aSSivas SRRusername = args.username
100a464a7ceSSivas SRR
1019fe1b12eSSivas SRRpassword = getpass.getpass("Enter your GitHub Password:")
102a464a7ceSSivas SRR
103a464a7ceSSivas SRRauth = (username, password)
104a464a7ceSSivas SRR
1050419fb0aSSivas SRR# To set the csv filename
1060419fb0aSSivas SRRcsvfilename = ""
107a464a7ceSSivas SRRfor repository in args.repositories:
1080419fb0aSSivas SRR    csvfilename_temp = '{}'.format(repository.replace('/', '-'))
1090419fb0aSSivas SRR    csvfilename = csvfilename + csvfilename_temp
1100419fb0aSSivas SRRcsvfilename = csvfilename + '-issues.csv'
11165dbeaadSvinaybs6with open(csvfilename, 'w') as csvfileout:
1120419fb0aSSivas SRR    csv_out = csv.writer(csvfileout)
1130419fb0aSSivas SRR    csv_out.writerow(['Labels', 'Title', 'State', 'Open Date',
1140419fb0aSSivas SRR                      'Close Date', 'URL', 'Author', 'Assignees',
1150419fb0aSSivas SRR                      'Milestone'])
1160419fb0aSSivas SRR    for repository in args.repositories:
1170419fb0aSSivas SRR        l_url = 'https://api.github.com/repos/{}/issues?state={}'
1180419fb0aSSivas SRR        l_url = l_url.format(repository, states)
1190419fb0aSSivas SRR        response = requests.get(l_url, auth=auth)
1200419fb0aSSivas SRR        write_issues(response, csv_out)
1210419fb0aSSivas SRR        get_issues_from_github_to_csv(repository, response)
1220419fb0aSSivas SRRcsvfileout.close()
123