77from pydantic import BaseModel , Field
88from specfile import Specfile
99from specfile .utils import EVR
10- from specfile .value_parser import EnclosedMacroSubstitution , MacroSubstitution , ValueParser
10+ from specfile .value_parser import EnclosedMacroSubstitution , MacroSubstitution , Node , ValueParser
1111
1212from beeai_framework .context import RunContext
1313from beeai_framework .emitter import Emitter
@@ -165,12 +165,48 @@ async def _get_latest_higher_stream_build(package: str, candidate_tag: str) -> E
165165 return EVR (epoch = build ["epoch" ] or 0 , version = build ["version" ], release = build ["release" ])
166166
167167 @staticmethod
168- async def _bump_or_reset_release (spec_path : Path , rebase : bool ) -> None :
168+ def _parse_release (release : str ) -> list [Node ]:
169+ return list (ValueParser .flatten (ValueParser .parse (release )))
170+
171+ @staticmethod
172+ def _find_macro (name : str , nodes : list [Node ]) -> int | None :
173+ for index , node in reversed (list (enumerate (nodes ))):
174+ if (
175+ isinstance (node , (MacroSubstitution , EnclosedMacroSubstitution ))
176+ and node .name == name
177+ ):
178+ return index
179+ return None
180+
181+ @classmethod
182+ async def _bump_or_reset_release (cls , spec_path : Path , rebase : bool ) -> None :
169183 with Specfile (spec_path ) as spec :
170- if rebase and not spec .has_autorelease :
171- spec .release = "1"
184+ current_release = spec .raw_release
185+ nodes = cls ._parse_release (current_release )
186+
187+ autorelease_index = cls ._find_macro ("autorelease" , nodes )
188+ dist_index = cls ._find_macro ("dist" , nodes )
189+ if autorelease_index is not None :
190+ # revert to plain %autorelease
191+ release = "%autorelease"
192+ else :
193+ if dist_index is None :
194+ prefix = current_release
195+ suffix = ""
196+ else :
197+ prefix = "" .join (str (n ) for n in nodes [: dist_index ])
198+ suffix = "" .join (str (n ) for n in nodes [dist_index + 1 :])
199+ if m := re .match (r"^(\d+)(.*)$" , prefix ):
200+ # increase or reset the main numeric part
201+ release = str (1 if rebase else int (m .group (1 )) + 1 ) + m .group (2 )
172202 else :
173- spec .bump_release ()
203+ release = prefix + ".1"
204+ release += "%{?dist}"
205+ if not re .match (r"^\.\d+$" , suffix ):
206+ release += suffix
207+
208+ with Specfile (spec_path ) as spec :
209+ spec .raw_release = release
174210
175211 @classmethod
176212 async def _set_zstream_release (
@@ -184,19 +220,10 @@ async def _set_zstream_release(
184220 higher_stream_base_release , _ = latest_higher_stream_build .release .rsplit (".el" , maxsplit = 1 )
185221 with Specfile (spec_path ) as spec :
186222 current_release = spec .raw_release
187- nodes = list (ValueParser .flatten (ValueParser .parse (current_release )))
188-
189- def find_macro (name ):
190- for index , node in reversed (list (enumerate (nodes ))):
191- if (
192- isinstance (node , (MacroSubstitution , EnclosedMacroSubstitution ))
193- and node .name == name
194- ):
195- return index
196- return None
223+ nodes = cls ._parse_release (current_release )
197224
198- autorelease_index = find_macro ("autorelease" )
199- dist_index = find_macro ("dist" )
225+ autorelease_index = cls . _find_macro ("autorelease" , nodes )
226+ dist_index = cls . _find_macro ("dist" , nodes )
200227 if autorelease_index is not None :
201228 if rebase :
202229 # %autorelease present, rebase, reset the release
0 commit comments