Skip to content

Commit 00c0f67

Browse files
committed
bugs: support obsoleting bugs when not exact version matches
When scanning for existing bugs, detect when the package list isn't an exact match, in which case an obsoleting can be considered by the user. Query the user for his decision and if obsoleting is chosen, after filing the bug, batch update all obsoleted bugs in a single API request to mark them as RESOLVED and with a See Also reference to the new bug. The TOML editing also now includes the obsoletes field for easier manual editing (which enables to manually add obsoletes). Resolves: #206 Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
1 parent 2e0db67 commit 00c0f67

1 file changed

Lines changed: 53 additions & 3 deletions

File tree

src/pkgdev/scripts/pkgdev_bugs.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,15 @@ def parse_atom(pkg: str):
208208

209209

210210
class GraphNode:
211-
__slots__ = ("pkgs", "edges", "bugno", "summary", "cc_arches")
211+
__slots__ = ("pkgs", "edges", "bugno", "summary", "cc_arches", "obsoletes")
212212

213213
def __init__(self, pkgs: tuple[tuple[package, set[str]], ...], bugno=None):
214214
self.pkgs = pkgs
215215
self.edges: set[GraphNode] = set()
216216
self.bugno = bugno
217217
self.summary = ""
218218
self.cc_arches = None
219+
self.obsoletes: set[int] = set()
219220

220221
def __eq__(self, __o: object):
221222
return self is __o
@@ -337,8 +338,35 @@ def file_bug(
337338
self.bugno = int(reply["id"])
338339
if observer is not None:
339340
observer(self)
341+
self.obsolete_bugs(api_key)
340342
return self.bugno
341343

344+
def obsolete_bugs(self, api_key: str):
345+
if not self.obsoletes:
346+
return
347+
assert self.bugno is not None
348+
349+
# Batch all bug IDs into a single PUT request
350+
request_data = dict(
351+
Bugzilla_api_key=api_key,
352+
status="RESOLVED",
353+
resolution="OBSOLETE",
354+
see_also={"add": [f"https://bugs.gentoo.org/{self.bugno}"]},
355+
)
356+
if len(self.obsoletes) > 1:
357+
request_data["ids"] = list(self.obsoletes)
358+
request = urllib.Request(
359+
url=f"https://bugs.gentoo.org/rest/bug/{','.join(map(str, self.obsoletes))}",
360+
data=json.dumps(request_data).encode("utf-8"),
361+
method="PUT",
362+
headers={
363+
"Content-Type": "application/json",
364+
"Accept": "application/json",
365+
},
366+
)
367+
with urllib.urlopen(request, timeout=30) as response:
368+
json.loads(response.read().decode("utf-8"))
369+
342370

343371
class DependencyGraph:
344372
def __init__(self, out: Formatter, err: Formatter, options):
@@ -560,6 +588,7 @@ def output_graph_toml(self):
560588
f'"bug-{i}"' for i, src in bugs.items() if node in src.edges
561589
):
562590
toml.write(f"blocks = [{node_blocks}]\n")
591+
toml.write(f"obsoletes = {sorted(node.obsoletes)}\n")
563592
for pkg, arches in node.pkgs:
564593
try:
565594
match = next(self.modified_repo.itermatch(pkg.versioned_atom))
@@ -600,6 +629,7 @@ def load_graph_toml(self, toml_file: str):
600629
for node_name, data_node in data.items():
601630
new_bugs[node_name].summary = data_node.get("summary", "")
602631
new_bugs[node_name].cc_arches = data_node.get("cc_arches", None)
632+
new_bugs[node_name].obsoletes = set(data_node.get("obsoletes", ()))
603633
for dep in data_node.get("depends", ()):
604634
if isinstance(dep, int):
605635
new_bugs[node_name].edges.add(new_bugs.setdefault(dep, GraphNode((), dep)))
@@ -748,15 +778,35 @@ def scan_existing_bugs(self, api_key: str) -> bool:
748778
if line
749779
)
750780
bug_match = boolean.OrRestriction(*bug_atoms)
781+
exact_match = boolean.OrRestriction(
782+
*(
783+
parse_atom(line.split(" ", 1)[0])
784+
for line in map(str.strip, bug["cf_stabilisation_atoms"].splitlines())
785+
if line
786+
)
787+
)
751788
for node in self.nodes:
752789
if node.bugno is None and all(bug_match.match(pkg[0]) for pkg in node.pkgs):
753-
node.bugno = bug["id"]
790+
is_exact_match = all(exact_match.match(pkg[0]) for pkg in node.pkgs)
754791
self.out.write(
755792
self.out.fg("yellow"),
756-
f"Found https://bugs.gentoo.org/{node.bugno} for node {node}",
793+
f"Found https://bugs.gentoo.org/{bug['id']} for node {node}",
757794
self.out.reset,
795+
" (exact version match)" if is_exact_match else " (atom match)",
758796
)
759797
self.out.write(" -> bug summary: ", bug["summary"])
798+
if is_exact_match:
799+
node.bugno = bug["id"]
800+
else:
801+
if userquery(
802+
"Not an exact match. Do you want to obsolete?",
803+
self.out,
804+
self.err,
805+
default_answer=False,
806+
):
807+
node.obsoletes.add(bug["id"])
808+
else:
809+
node.bugno = bug["id"]
760810
has_output = True
761811
break
762812
return has_output

0 commit comments

Comments
 (0)