Skip to content
This repository was archived by the owner on Apr 29, 2024. It is now read-only.

Commit 93224fb

Browse files
committed
Add script for getting core bugs
1 parent 8ceeabe commit 93224fb

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

Diff for: tools/scripts/top_core_bugs.py

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import html
2+
import logging
3+
import urllib
4+
from typing import Any, Mapping, MutableMapping, Optional
5+
6+
import requests
7+
8+
from helpers import github, issue
9+
10+
Bug = Mapping[str, Any]
11+
12+
logging.basicConfig()
13+
logger = logging.getLogger()
14+
logger.setLevel(logging.DEBUG)
15+
16+
17+
def get_kb_bugs() -> set[int]:
18+
resp = requests.get("https://bugzilla.mozilla.org/rest/bug?product=Web+Compatibility&Component=Knowledge+Base&include_fields=id")
19+
resp.raise_for_status()
20+
return {item["id"] for item in resp.json()["bugs"]}
21+
22+
23+
def get_bug_list() -> list[Bug]:
24+
resp = requests.get("https://bugzilla.mozilla.org/rest/bug?f1=see_also&f2=component&n2=1&o1=anywordssubstr&o2=anywordssubstr&classification=Components&product=Core&resolution=---&v1=webcompat&v2=Privacy&limit=0&include_fields=id,component,see_also,priority,severity,summary,blocks")
25+
resp.raise_for_status()
26+
return resp.json()["bugs"]
27+
28+
29+
def webcompat_link(see_also: str) -> Optional[str]:
30+
try:
31+
url = urllib.parse.urlparse(see_also)
32+
except Exception:
33+
return None
34+
if url.hostname == "webcompat.com":
35+
bug_id = url.path.rsplit("/", 1)[1]
36+
return f"https://github.com/webcompat/web-bugs/issues/{bug_id}"
37+
if url.hostname == "github.com" and url.path.startswith("/webcompat/web-bugs/issues/"):
38+
return f"{url.scheme}://{url.hostname}{url.path}"
39+
return None
40+
41+
42+
def bug_link(dest_id: int) -> str:
43+
return f"<a href=https://bugzilla.mozilla.org/show_bug.cgi?id={dest_id}>{dest_id}</a>"
44+
45+
46+
def html_list(list_items: list[str]) -> str:
47+
if list_items:
48+
return "<ul>" + "".join(f"<li>{item}" for item in list_items) + "</ul>"
49+
return ""
50+
51+
52+
def format_as_html(bugs: list[Bug]) -> str:
53+
rv = ["<!doctype html>",
54+
"<title>Core Bugs with WebCompat Links</title>",
55+
"<h1>Core Bugs with WebCompat Links</h1>",
56+
f"<p>Found {len(bugs)} bugs"]
57+
for offset in range(4):
58+
rv.extend([f"<h2 id=group{offset + 1}>Group {offset + 1}</h2>",
59+
"<table>",
60+
"<tr><th>id<th>Summary<th>Component<th>Severity<th>Webcompat Links<th>Issue Priority Score<th>Max Issue Severity<th>KB Entries"])
61+
for bug in bugs[offset::4]:
62+
kb_links = html_list([bug_link(item) for item in bug["kb_entries"]])
63+
webcompat_links = []
64+
for (link, issue) in zip(bug["webcompat_links"], bug["issues"]):
65+
priority, severity = get_severity_priority(issue)
66+
webcompat_links.append(f"<a href={link}>{link}</a> [P{priority} S{severity}]")
67+
webcompat_details = f"<details>{html_list(webcompat_links)}</details>" if webcompat_links else ""
68+
rv.append(f"<tr><td>{bug_link(bug['id'])}<td>{html.escape(bug['summary'])}<td>{bug['component']}<td>{bug['severity']}<td>{len(bug['webcompat_links'])}{webcompat_details}<td>{bug['score'][0]}<td>{-bug['score'][1]}<td>{kb_links}")
69+
rv.append("</table>")
70+
return "\n".join(rv)
71+
72+
73+
def bug_score(bug):
74+
bug_severity = int(bug["severity"][1]) if bug["severity"][0] == "S" else 5
75+
issue_score = []
76+
severity_score = 4
77+
priority_score = 0
78+
for issue in bug["issues"]:
79+
issue_priority, issue_severity = get_severity_priority(issue)
80+
priority_score += 10 ** (4 - issue_priority)
81+
severity_score = min(severity_score, issue_severity)
82+
return (priority_score, -severity_score, len(bug["webcompat_links"]), -bug_severity)
83+
84+
85+
severity_map = {"critical": 2, "important": 3, "minor": 4}
86+
87+
88+
def get_severity_priority(gh_issue):
89+
priority = 4
90+
severity = 4
91+
for label in gh_issue.labels:
92+
if label.startswith("diagnosis-priority-"):
93+
priority = int(label[-1])
94+
elif label.startswith("severity"):
95+
severity = severity_map[label.rsplit("-", 1)[1]]
96+
return (priority, severity)
97+
98+
99+
def main():
100+
bug_cache = {}
101+
kb_bugs = get_kb_bugs()
102+
bugs = get_bug_list()
103+
bugs = [bug for bug in bugs if "Layout" in bug["component"]]
104+
gh_client = github.GitHub()
105+
for bug in bugs:
106+
bug["webcompat_links"] = []
107+
bug["issues"] = []
108+
for item in bug.get("see_also", []):
109+
link = webcompat_link(item)
110+
if link is not None:
111+
bug["webcompat_links"].append(link)
112+
issue_id = link.rsplit("/", 1)[1]
113+
bug["issues"].append(issue.WebcompatIssue.from_dict(gh_client.fetch_issue_by_number("webcompat", "web-bugs", issue_id, timeline=False)))
114+
bug["kb_entries"] = [item for item in bug["blocks"] if item in kb_bugs]
115+
bug["score"] = bug_score(bug)
116+
bugs.sort(key=lambda bug: bug["score"], reverse=True)
117+
print(format_as_html(bugs))
118+
119+
120+
if __name__ == "__main__":
121+
main()

0 commit comments

Comments
 (0)