xref: /openbmc/openbmc-test-automation/tools/github_issues_to_csv (revision 20f38712b324e61a94e174017c487a0af4b373e1)
1e7e9171eSGeorge 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
11*20f38712SPatrick Williams
12a464a7ceSSivas SRRimport requests
13a464a7ceSSivas SRR
14a464a7ceSSivas SRRauth = None
15*20f38712SPatrick Williamsstates = "all"
16a464a7ceSSivas SRR
17a464a7ceSSivas SRR
18a464a7ceSSivas SRRdef write_issues(response, csv_out):
19a464a7ceSSivas SRR    r"""
20a464a7ceSSivas SRR    Parses JSON response and writes to CSV.
21a464a7ceSSivas SRR    """
2265dbeaadSvinaybs6    print(response)
23a464a7ceSSivas SRR    if response.status_code != 200:
24a464a7ceSSivas SRR        raise Exception(response.status_code)
25a464a7ceSSivas SRR    for issue in response.json():
26*20f38712SPatrick Williams        if "pull_request" not in issue:
27*20f38712SPatrick Williams            labels = ", ".join([lable["name"] for lable in issue["labels"]])
28b4eb9ac1SSivas SRR
299fe1b12eSSivas SRR            # Below lines to overcome "TypeError: 'NoneType' object has
309fe1b12eSSivas SRR            # no attribute '__getitem__'"
319fe1b12eSSivas SRR
32*20f38712SPatrick Williams            close_date = issue.get("closed_at")
33b4eb9ac1SSivas SRR            if close_date:
34*20f38712SPatrick Williams                close_date = issue.get("closed_at").split("T")[0]
35b4eb9ac1SSivas SRR
36*20f38712SPatrick Williams            assignee_resp = issue.get("assignees", "Not Assigned")
379fe1b12eSSivas SRR            if assignee_resp:
38*20f38712SPatrick Williams                owners = ",".join(
39*20f38712SPatrick Williams                    [
40*20f38712SPatrick Williams                        assignee_login["login"]
41*20f38712SPatrick Williams                        for assignee_login in assignee_resp
42*20f38712SPatrick Williams                    ]
43*20f38712SPatrick Williams                )
449fe1b12eSSivas SRR            else:
45b4eb9ac1SSivas SRR                owners = "Not Assigned"
46b4eb9ac1SSivas SRR
47*20f38712SPatrick Williams            milestone_resp = issue.get("milestone", "Not Assigned")
48b4eb9ac1SSivas SRR            if milestone_resp:
49*20f38712SPatrick Williams                milestone_resp = milestone_resp["title"].encode("utf-8")
509fe1b12eSSivas SRR
51a464a7ceSSivas SRR            # Change the following line to write out additional fields
52*20f38712SPatrick Williams            csv_out.writerow(
53*20f38712SPatrick Williams                [
54*20f38712SPatrick Williams                    labels.encode("utf-8"),
55*20f38712SPatrick Williams                    issue.get("title").encode("utf-8"),
56*20f38712SPatrick Williams                    issue.get("state").encode("utf-8"),
57*20f38712SPatrick Williams                    issue.get("created_at").split("T")[0],
58b4eb9ac1SSivas SRR                    close_date,
59*20f38712SPatrick Williams                    issue.get("html_url").encode("utf-8"),
60*20f38712SPatrick Williams                    issue.get("user").get("login").encode("utf-8"),
61*20f38712SPatrick Williams                    owners,
62*20f38712SPatrick Williams                    milestone_resp,
63*20f38712SPatrick Williams                ]
64*20f38712SPatrick Williams            )
65a464a7ceSSivas SRR
66a464a7ceSSivas SRR
670419fb0aSSivas SRRdef get_issues_from_github_to_csv(name, response):
68a464a7ceSSivas SRR    r"""
69a464a7ceSSivas SRR    Requests issues from GitHub API and writes to CSV file.
700419fb0aSSivas SRR    Description of argument(s):
710419fb0aSSivas SRR    name  Name of the GitHub repository
720419fb0aSSivas SRR    response  GitHub repository response
73a464a7ceSSivas SRR    """
7465dbeaadSvinaybs6    print(name)
7565dbeaadSvinaybs6    print(states)
76a464a7ceSSivas SRR
77a464a7ceSSivas SRR    # Multiple requests are required if response is paged
78*20f38712SPatrick Williams    if "link" in response.headers:
79*20f38712SPatrick Williams        pages = {
80*20f38712SPatrick Williams            rel[6:-1]: url[url.index("<") + 1 : -1]
81*20f38712SPatrick Williams            for url, rel in (
82*20f38712SPatrick Williams                link.split(";") for link in response.headers["link"].split(",")
83*20f38712SPatrick Williams            )
84*20f38712SPatrick Williams        }
85*20f38712SPatrick Williams        while "last" in pages and "next" in pages:
86*20f38712SPatrick Williams            pages = {
87*20f38712SPatrick Williams                rel[6:-1]: url[url.index("<") + 1 : -1]
88*20f38712SPatrick Williams                for url, rel in (
89*20f38712SPatrick Williams                    link.split(";")
90*20f38712SPatrick Williams                    for link in response.headers["link"].split(",")
91*20f38712SPatrick Williams                )
92*20f38712SPatrick Williams            }
93*20f38712SPatrick Williams            response = requests.get(pages["next"], auth=auth)
94a464a7ceSSivas SRR            write_issues(response, csv_out)
95*20f38712SPatrick Williams            if pages["next"] == pages["last"]:
96a464a7ceSSivas SRR                break
97a464a7ceSSivas SRR
98a464a7ceSSivas SRR
99*20f38712SPatrick Williamsparser = argparse.ArgumentParser(
100*20f38712SPatrick Williams    description="Write GitHub repository issues to CSV file."
101*20f38712SPatrick Williams)
102a464a7ceSSivas SRR
103*20f38712SPatrick Williamsparser.add_argument(
104*20f38712SPatrick Williams    "username", nargs="?", help="GitHub user name, formatted as 'username'"
105*20f38712SPatrick Williams)
106a464a7ceSSivas SRR
107*20f38712SPatrick Williamsparser.add_argument(
108*20f38712SPatrick Williams    "repositories",
109*20f38712SPatrick Williams    nargs="+",
110*20f38712SPatrick Williams    help="Repository names, formatted as 'basereponame/repo'",
111*20f38712SPatrick Williams)
112a464a7ceSSivas SRR
113*20f38712SPatrick Williamsparser.add_argument(
114*20f38712SPatrick Williams    "--all", action="store_true", help="Returns both open and closed issues."
115*20f38712SPatrick Williams)
1160419fb0aSSivas SRR
117a464a7ceSSivas SRRargs = parser.parse_args()
118a464a7ceSSivas SRR
119a464a7ceSSivas SRRif args.all:
120*20f38712SPatrick Williams    state = "all"
121a464a7ceSSivas SRR
1220419fb0aSSivas SRRusername = args.username
123a464a7ceSSivas SRR
1249fe1b12eSSivas SRRpassword = getpass.getpass("Enter your GitHub Password:")
125a464a7ceSSivas SRR
126a464a7ceSSivas SRRauth = (username, password)
127a464a7ceSSivas SRR
1280419fb0aSSivas SRR# To set the csv filename
1290419fb0aSSivas SRRcsvfilename = ""
130a464a7ceSSivas SRRfor repository in args.repositories:
131*20f38712SPatrick Williams    csvfilename_temp = "{}".format(repository.replace("/", "-"))
1320419fb0aSSivas SRR    csvfilename = csvfilename + csvfilename_temp
133*20f38712SPatrick Williamscsvfilename = csvfilename + "-issues.csv"
134*20f38712SPatrick Williamswith open(csvfilename, "w") as csvfileout:
1350419fb0aSSivas SRR    csv_out = csv.writer(csvfileout)
136*20f38712SPatrick Williams    csv_out.writerow(
137*20f38712SPatrick Williams        [
138*20f38712SPatrick Williams            "Labels",
139*20f38712SPatrick Williams            "Title",
140*20f38712SPatrick Williams            "State",
141*20f38712SPatrick Williams            "Open Date",
142*20f38712SPatrick Williams            "Close Date",
143*20f38712SPatrick Williams            "URL",
144*20f38712SPatrick Williams            "Author",
145*20f38712SPatrick Williams            "Assignees",
146*20f38712SPatrick Williams            "Milestone",
147*20f38712SPatrick Williams        ]
148*20f38712SPatrick Williams    )
1490419fb0aSSivas SRR    for repository in args.repositories:
150*20f38712SPatrick Williams        l_url = "https://api.github.com/repos/{}/issues?state={}"
1510419fb0aSSivas SRR        l_url = l_url.format(repository, states)
1520419fb0aSSivas SRR        response = requests.get(l_url, auth=auth)
1530419fb0aSSivas SRR        write_issues(response, csv_out)
1540419fb0aSSivas SRR        get_issues_from_github_to_csv(repository, response)
1550419fb0aSSivas SRRcsvfileout.close()
156