diff options
-rw-r--r-- | src/pkgdev/scripts/pkgdev_bugs.py | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/src/pkgdev/scripts/pkgdev_bugs.py b/src/pkgdev/scripts/pkgdev_bugs.py index cb1bf0c..4cf726a 100644 --- a/src/pkgdev/scripts/pkgdev_bugs.py +++ b/src/pkgdev/scripts/pkgdev_bugs.py @@ -5,6 +5,7 @@ import urllib.request as urllib from collections import defaultdict from functools import partial from itertools import chain +from urllib.parse import urlencode from pkgcheck import const as pkgcheck_const from pkgcheck.addons import ArchesAddon, init_addon @@ -13,6 +14,7 @@ from pkgcheck.checks import visibility from pkgcheck.scripts import argparse_actions from pkgcore.ebuild.atom import atom from pkgcore.ebuild.ebuild_src import package +from pkgcore.ebuild.errors import MalformedAtom from pkgcore.ebuild.misc import sort_keywords from pkgcore.repository import multiplex from pkgcore.restrictions import boolean, packages, values @@ -127,6 +129,16 @@ def _get_suggested_keywords(repo, pkg: package): return frozenset({x for x in match_keywords if "-" not in x}) +def parse_atom(pkg: str): + try: + return atom(pkg) + except MalformedAtom as exc: + try: + return atom(f"={pkg}") + except MalformedAtom: + raise exc + + class GraphNode: __slots__ = ("pkgs", "edges", "bugno") @@ -267,7 +279,7 @@ class DependencyGraph: combined = boolean.AndRestriction(*set().union(*problems.values())) match = self.find_best_match(combined, pkgset) yield match, set(problems.keys()) - except ValueError: + except (ValueError, IndexError): results: dict[package, set[str]] = defaultdict(set) for keyword, deps in problems.items(): match = self.find_best_match(deps, pkgset) @@ -310,6 +322,8 @@ class DependencyGraph: dot.write("\trankdir=LR;\n") for node in self.nodes: node_text = "\\n".join(node.lines()) + if node.bugno is not None: + node_text += f"\\nbug #{node.bugno}" dot.write(f'\t{node.dot_edge}[label="{node_text}"];\n') for other in node.edges: dot.write(f"\t{node.dot_edge} -> {other.dot_edge};\n") @@ -385,6 +399,46 @@ class DependencyGraph: found_someone = True break + def scan_existing_bugs(self, api_key: str): + params = urlencode( + { + "Bugzilla_api_key": api_key, + "include_fields": "id,cf_stabilisation_atoms", + "component": "Stabilization", + "resolution": "---", + "f1": "cf_stabilisation_atoms", + "o1": "anywords", + "v1": {pkg[0].unversioned_atom for node in self.nodes for pkg in node.pkgs}, + }, + doseq=True, + ) + request = urllib.Request( + url="https://bugs.gentoo.org/rest/bug?" + params, + method="GET", + headers={ + "Content-Type": "application/json", + "Accept": "application/json", + }, + ) + with urllib.urlopen(request, timeout=30) as response: + reply = json.loads(response.read().decode("utf-8")) + for bug in reply["bugs"]: + bug_atoms = ( + parse_atom(line.split(" ", 1)[0]).unversioned_atom + for line in map(str.strip, bug["cf_stabilisation_atoms"].splitlines()) + if line + ) + bug_match = boolean.OrRestriction(*bug_atoms) + for node in self.nodes: + if node.bugno is None and all(bug_match.match(pkg[0]) for pkg in node.pkgs): + node.bugno = bug["id"] + self.out.write( + self.out.fg("yellow"), + f"Found https://bugs.gentoo.org/{node.bugno} for node {node}", + self.out.reset, + ) + break + def file_bugs(self, api_key: str, auto_cc_arches: frozenset[str]): def observe(node: GraphNode): self.out.write( @@ -411,6 +465,9 @@ def main(options, out: Formatter, err: Formatter): for node in d.nodes: node.cleanup_keywords(search_repo) + if userquery("Check for open bugs matching current graph?", out, err, default_answer=False): + d.scan_existing_bugs(options.api_key) + if options.dot is not None: d.output_dot(options.dot) out.write(out.fg("green"), f"Dot file written to {options.dot}", out.reset) |