forked from trezor/trezor-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
github_issues_to_csv.py
133 lines (119 loc) · 4.12 KB
/
github_issues_to_csv.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"""
Taken from https://gist.github.com/patrickfuller/e2ea8a94badc5b6967ef3ca0a9452a43 and modified.
Currently writes all issues that have some Weight.
"""
import argparse
import csv
import requests
import os.path
token = None
path = os.path.dirname(os.path.realpath(__file__))
filename = path + "/github_issues_to_csv.ignore"
if os.path.exists(filename):
with open(filename, "r") as config:
content = config.read()
if len(content) == 40:
token = content
else:
raise ValueError("Invalid config file")
PRIORITIES = ("P1", "P2", "P3", "P4")
SEVERITIES = ("S1", "S2", "S3", "S4")
WEIGHTS = ("W0", "W1/2", "W1", "W2", "W3", "W5", "W8", "W13", "W20", "W40", "W100")
def write_issues(r, csvout):
"""Parses JSON response and writes to CSV."""
if r.status_code != 200:
raise Exception(r.status_code)
for issue in r.json():
if "pull_request" not in issue:
priority = ""
severity = ""
weight = ""
labels = []
for l in issue["labels"]:
if l["name"][:2] in PRIORITIES:
priority = l["name"]
elif l["name"][:2] in SEVERITIES:
severity = l["name"]
elif l["name"] in WEIGHTS:
weight = l["name"][1:]
if weight == "1/2":
weight = "0.5"
else:
labels.append(l["name"])
if not weight:
continue
labels = ", ".join(labels)
date = issue["created_at"].split("T")[0]
milestone = issue["milestone"]["title"] if issue["milestone"] else ""
assignee = issue["assignee"]["login"] if issue["assignee"] else ""
csvout.writerow(
[
issue["title"],
issue["number"],
issue["html_url"],
issue["state"],
assignee,
milestone,
priority,
severity,
weight,
labels,
]
)
def get_issues(name):
"""Requests issues from GitHub API and writes to CSV file."""
url = f"https://api.github.com/repos/{name}/issues?state=all"
if token is not None:
headers = {"Authorization": "token " + token}
else:
headers = None
r = requests.get(url, headers=headers)
csvfilename = f"{name.replace('/', '-')}-issues.csv"
with open(csvfilename, "w", newline="") as csvfile:
csvout = csv.writer(csvfile)
csvout.writerow(
[
"Title",
"Number",
"URL",
"State",
"Assignee",
"Milestone",
"Priority",
"Severity",
"Weight",
"Labels",
]
)
write_issues(r, csvout)
# Multiple requests are required if response is paged
if "link" in r.headers:
pages = {
rel[6:-1]: url[url.index("<") + 1 : -1]
for url, rel in (
link.split(";") for link in r.headers["link"].split(",")
)
}
while "last" in pages and "next" in pages:
pages = {
rel[6:-1]: url[url.index("<") + 1 : -1]
for url, rel in (
link.split(";") for link in r.headers["link"].split(",")
)
}
r = requests.get(pages["next"], headers=headers)
write_issues(r, csvout)
if pages["next"] == pages["last"]:
break
parser = argparse.ArgumentParser(
description="Write GitHub repository issues " "to CSV file."
)
parser.add_argument(
"repositories", nargs="+", help="Repository names, " "formatted as 'username/repo'"
)
parser.add_argument(
"--all", action="store_true", help="Returns both open " "and closed issues."
)
args = parser.parse_args()
for repository in args.repositories:
get_issues(repository)