Files
test/tools/triage/issues_module_listing.py
2024-09-23 10:31:58 +10:00

165 lines
5.2 KiB
Python
Executable File

#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
"""
# This script prints the numbers of open issues per module.
Example usage:
python ./issues_module_listing.py --severity High
"""
import argparse
import dataclasses
import sys
from datetime import date
from gitea_utils import gitea_json_issues_search
IS_ATTY = sys.stdout.isatty()
@dataclasses.dataclass
class ModuleInfo:
name: str
labelid: str
buglist: list[str] = dataclasses.field(default_factory=list)
buglist_full: list[str] = dataclasses.field(default_factory=list)
# Label names and IDs are taken from https://projects.blender.org/blender/blender/labels.
modules = {
"Module/Animation & Rigging": ModuleInfo(name="Animation & Rigging", labelid="268"),
"Module/Core": ModuleInfo(name="Core", labelid="269"),
"Module/Grease Pencil": ModuleInfo(name="Grease Pencil", labelid="273"),
"Module/Modeling": ModuleInfo(name="Modeling", labelid="274"),
"Module/Nodes & Physics": ModuleInfo(name="Nodes & Physics", labelid="275"),
"Module/Pipeline, Assets & IO": ModuleInfo(name="Pipeline, Assets & I/O", labelid="276"),
"Module/Platforms, Builds & Tests": ModuleInfo(name="Platforms, Builds, Test & Devices", labelid="278"),
"Module/Python API": ModuleInfo(name="Python API", labelid="279"),
"Module/Render & Cycles": ModuleInfo(name="Render & Cycles", labelid="280"),
"Module/Sculpt, Paint & Texture": ModuleInfo(name="Sculpt, Paint & Texture", labelid="281"),
"Module/User Interface": ModuleInfo(name="User Interface", labelid="283"),
"Module/VFX & Video": ModuleInfo(name="VFX & Video", labelid="284"),
"Module/Viewport & EEVEE": ModuleInfo(name="Viewport & EEVEE", labelid="272"),
}
base_url = (
"https://projects.blender.org/blender/blender/"
"issues?q=&type=all&sort=&state=open&labels="
)
total_url = (
"https://projects.blender.org/blender/blender/"
"issues?q=&type=all&sort=&state=open&labels=285%2c-297%2c-298%2c-299%2c-301"
)
severity_labelid = {
"Low": "286",
"Normal": "287",
"High": "285",
"Unbreak Now!": "288"
}
def compile_list(severity: str) -> None:
label = f"Severity/{severity}"
issues_json = gitea_json_issues_search(
type="issues",
state="open",
labels=label,
verbose=True,
)
# Create a dictionary of format {module_id: module_name}
module_label_ids = {}
for module_name in modules:
module_label_ids[modules[module_name].labelid] = module_name
uncategorized_reports = []
issues_json_sorted = sorted(issues_json, key=lambda x: x["number"])
for issue in issues_json_sorted:
html_url = issue["html_url"]
number = issue["number"]
created_at = issue["created_at"].rsplit('T', 1)[0]
title = issue["title"]
# Check reports module assignment and fill in data.
for label_iter in issue["labels"]:
label_id = str(label_iter["id"])
if label_id not in module_label_ids:
continue
current_module_name = module_label_ids[label_id]
if current_module_name != label_iter["name"]:
new_label_name = label_iter["name"]
print(f"ALERT: The name of label of '{current_module_name}' changed.")
print(f"The new name is '{new_label_name}'.")
if IS_ATTY:
input("Press enter to continue: \n")
modules[current_module_name].buglist.append(f"[#{number}]({html_url})")
modules[current_module_name].buglist_full.append(f"* [{title}]({html_url}) - {created_at}\n")
break
else:
uncategorized_reports.append(f"[#{number}]({html_url})")
# Print statistics
print(f"Open {severity} Severity bugs as of {date.today()}:\n")
# Module overview with numbers
total = 0
for module in modules.values():
buglist_str = (", ".join(module.buglist))
buglist_len = len(module.buglist)
total += buglist_len
full_url = base_url + severity_labelid[severity] + "%2c" + module.labelid
if not module.buglist or severity != "High":
print(f"- [{module.name}]({full_url}): *{buglist_len}*")
else:
print(f"- [{module.name}]({full_url}): *{buglist_len}* _{buglist_str}_")
print()
print(f"[Total]({total_url}): {total}")
print()
print("Uncategorized:", ", ".join(uncategorized_reports))
print()
# Module overview with titles and creation date
for module in modules.values():
buglist_full_str = ("".join(module.buglist_full))
buglist_full_len = len(module.buglist_full)
if buglist_full_len != 0:
print(f"{module.name}:")
print(f"{buglist_full_str}")
def main() -> None:
parser = argparse.ArgumentParser(
description="Print statistics on open bug reports per module",
epilog="This script is used to help module teams",
)
parser.add_argument(
"--severity",
dest="severity",
default="High",
type=str,
required=False,
choices=severity_labelid.keys(),
help="Severity level of reports",
)
args = parser.parse_args()
compile_list(args.severity)
if __name__ == "__main__":
main()