xref: /openbmc/openbmc-test-automation/tools/github_issues_to_csv (revision 249fbcc0be4641e2d43987badc764e1f73a6ebeb)
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"""
8*249fbcc0SSridevi Ramesh
9a464a7ceSSivas SRRimport argparse
10a464a7ceSSivas SRRimport csv
119fe1b12eSSivas SRRimport getpass
1220f38712SPatrick Williams
13a464a7ceSSivas SRRimport requests
14a464a7ceSSivas SRR
15a464a7ceSSivas SRRauth = None
1620f38712SPatrick Williamsstates = "all"
17a464a7ceSSivas SRR
18a464a7ceSSivas SRR
19a464a7ceSSivas SRRdef write_issues(response, csv_out):
20a464a7ceSSivas SRR    r"""
21a464a7ceSSivas SRR    Parses JSON response and writes to CSV.
22a464a7ceSSivas SRR    """
2365dbeaadSvinaybs6    print(response)
24a464a7ceSSivas SRR    if response.status_code != 200:
25a464a7ceSSivas SRR        raise Exception(response.status_code)
26a464a7ceSSivas SRR    for issue in response.json():
2720f38712SPatrick Williams        if "pull_request" not in issue:
284ebb3281SGeorge Keishing            labels = ", ".join([label["name"] for label in issue["labels"]])
29b4eb9ac1SSivas SRR
309fe1b12eSSivas SRR            # Below lines to overcome "TypeError: 'NoneType' object has
319fe1b12eSSivas SRR            # no attribute '__getitem__'"
329fe1b12eSSivas SRR
3320f38712SPatrick Williams            close_date = issue.get("closed_at")
34b4eb9ac1SSivas SRR            if close_date:
3520f38712SPatrick Williams                close_date = issue.get("closed_at").split("T")[0]
36b4eb9ac1SSivas SRR
3720f38712SPatrick Williams            assignee_resp = issue.get("assignees", "Not Assigned")
389fe1b12eSSivas SRR            if assignee_resp:
3920f38712SPatrick Williams                owners = ",".join(
4020f38712SPatrick Williams                    [
4120f38712SPatrick Williams                        assignee_login["login"]
4220f38712SPatrick Williams                        for assignee_login in assignee_resp
4320f38712SPatrick Williams                    ]
4420f38712SPatrick Williams                )
459fe1b12eSSivas SRR            else:
46b4eb9ac1SSivas SRR                owners = "Not Assigned"
47b4eb9ac1SSivas SRR
4820f38712SPatrick Williams            milestone_resp = issue.get("milestone", "Not Assigned")
49b4eb9ac1SSivas SRR            if milestone_resp:
5020f38712SPatrick Williams                milestone_resp = milestone_resp["title"].encode("utf-8")
519fe1b12eSSivas SRR
52a464a7ceSSivas SRR            # Change the following line to write out additional fields
5320f38712SPatrick Williams            csv_out.writerow(
5420f38712SPatrick Williams                [
5520f38712SPatrick Williams                    labels.encode("utf-8"),
5620f38712SPatrick Williams                    issue.get("title").encode("utf-8"),
5720f38712SPatrick Williams                    issue.get("state").encode("utf-8"),
5820f38712SPatrick Williams                    issue.get("created_at").split("T")[0],
59b4eb9ac1SSivas SRR                    close_date,
6020f38712SPatrick Williams                    issue.get("html_url").encode("utf-8"),
6120f38712SPatrick Williams                    issue.get("user").get("login").encode("utf-8"),
6220f38712SPatrick Williams                    owners,
6320f38712SPatrick Williams                    milestone_resp,
6420f38712SPatrick Williams                ]
6520f38712SPatrick Williams            )
66a464a7ceSSivas SRR
67a464a7ceSSivas SRR
680419fb0aSSivas SRRdef get_issues_from_github_to_csv(name, response):
69a464a7ceSSivas SRR    r"""
70a464a7ceSSivas SRR    Requests issues from GitHub API and writes to CSV file.
710419fb0aSSivas SRR    Description of argument(s):
720419fb0aSSivas SRR    name  Name of the GitHub repository
730419fb0aSSivas SRR    response  GitHub repository response
74a464a7ceSSivas SRR    """
7565dbeaadSvinaybs6    print(name)
7665dbeaadSvinaybs6    print(states)
77a464a7ceSSivas SRR
78a464a7ceSSivas SRR    # Multiple requests are required if response is paged
7920f38712SPatrick Williams    if "link" in response.headers:
8020f38712SPatrick Williams        pages = {
8120f38712SPatrick Williams            rel[6:-1]: url[url.index("<") + 1 : -1]
8220f38712SPatrick Williams            for url, rel in (
8320f38712SPatrick Williams                link.split(";") for link in response.headers["link"].split(",")
8420f38712SPatrick Williams            )
8520f38712SPatrick Williams        }
8620f38712SPatrick Williams        while "last" in pages and "next" in pages:
8720f38712SPatrick Williams            pages = {
8820f38712SPatrick Williams                rel[6:-1]: url[url.index("<") + 1 : -1]
8920f38712SPatrick Williams                for url, rel in (
9020f38712SPatrick Williams                    link.split(";")
9120f38712SPatrick Williams                    for link in response.headers["link"].split(",")
9220f38712SPatrick Williams                )
9320f38712SPatrick Williams            }
9420f38712SPatrick Williams            response = requests.get(pages["next"], auth=auth)
95a464a7ceSSivas SRR            write_issues(response, csv_out)
9620f38712SPatrick Williams            if pages["next"] == pages["last"]:
97a464a7ceSSivas SRR                break
98a464a7ceSSivas SRR
99a464a7ceSSivas SRR
10020f38712SPatrick Williamsparser = argparse.ArgumentParser(
10120f38712SPatrick Williams    description="Write GitHub repository issues to CSV file."
10220f38712SPatrick Williams)
103a464a7ceSSivas SRR
10420f38712SPatrick Williamsparser.add_argument(
10520f38712SPatrick Williams    "username", nargs="?", help="GitHub user name, formatted as 'username'"
10620f38712SPatrick Williams)
107a464a7ceSSivas SRR
10820f38712SPatrick Williamsparser.add_argument(
10920f38712SPatrick Williams    "repositories",
11020f38712SPatrick Williams    nargs="+",
11120f38712SPatrick Williams    help="Repository names, formatted as 'basereponame/repo'",
11220f38712SPatrick Williams)
113a464a7ceSSivas SRR
11420f38712SPatrick Williamsparser.add_argument(
11520f38712SPatrick Williams    "--all", action="store_true", help="Returns both open and closed issues."
11620f38712SPatrick Williams)
1170419fb0aSSivas SRR
118a464a7ceSSivas SRRargs = parser.parse_args()
119a464a7ceSSivas SRR
120a464a7ceSSivas SRRif args.all:
12120f38712SPatrick Williams    state = "all"
122a464a7ceSSivas SRR
1230419fb0aSSivas SRRusername = args.username
124a464a7ceSSivas SRR
1259fe1b12eSSivas SRRpassword = getpass.getpass("Enter your GitHub Password:")
126a464a7ceSSivas SRR
127a464a7ceSSivas SRRauth = (username, password)
128a464a7ceSSivas SRR
1290419fb0aSSivas SRR# To set the csv filename
1300419fb0aSSivas SRRcsvfilename = ""
131a464a7ceSSivas SRRfor repository in args.repositories:
13220f38712SPatrick Williams    csvfilename_temp = "{}".format(repository.replace("/", "-"))
1330419fb0aSSivas SRR    csvfilename = csvfilename + csvfilename_temp
13420f38712SPatrick Williamscsvfilename = csvfilename + "-issues.csv"
13520f38712SPatrick Williamswith open(csvfilename, "w") as csvfileout:
1360419fb0aSSivas SRR    csv_out = csv.writer(csvfileout)
13720f38712SPatrick Williams    csv_out.writerow(
13820f38712SPatrick Williams        [
13920f38712SPatrick Williams            "Labels",
14020f38712SPatrick Williams            "Title",
14120f38712SPatrick Williams            "State",
14220f38712SPatrick Williams            "Open Date",
14320f38712SPatrick Williams            "Close Date",
14420f38712SPatrick Williams            "URL",
14520f38712SPatrick Williams            "Author",
14620f38712SPatrick Williams            "Assignees",
14720f38712SPatrick Williams            "Milestone",
14820f38712SPatrick Williams        ]
14920f38712SPatrick Williams    )
1500419fb0aSSivas SRR    for repository in args.repositories:
15120f38712SPatrick Williams        l_url = "https://api.github.com/repos/{}/issues?state={}"
1520419fb0aSSivas SRR        l_url = l_url.format(repository, states)
1530419fb0aSSivas SRR        response = requests.get(l_url, auth=auth)
1540419fb0aSSivas SRR        write_issues(response, csv_out)
1550419fb0aSSivas SRR        get_issues_from_github_to_csv(repository, response)
1560419fb0aSSivas SRRcsvfileout.close()
157