@@ -208,14 +208,15 @@ def parse_atom(pkg: str):
208208
209209
210210class 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
343371class 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