Skip to content

Commit 58f2120

Browse files
authored
Feat: Add a utility function to compare builds between errata (#305)
- Introduced `ErratumBuilds` model to parse and store build data from ET API. - Added `get_erratum_builds()` to fetch builds for a given erratum ID. - Implemented `errata_have_same_file_lists()` to check if two errata ship the same subpackages.
1 parent 331b24a commit 58f2120

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

supervisor/errata_utils.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing_extensions import Literal
1111

1212
from bs4 import BeautifulSoup, Tag # type: ignore
13-
from pydantic import BaseModel
13+
from pydantic import BaseModel, RootModel
1414
from requests_gssapi import HTTPSPNEGOAuth
1515

1616
from .constants import DATETIME_MIN_UTC
@@ -157,6 +157,55 @@ def get_erratum_for_link(link: str, full: bool = False) -> Erratum | FullErratum
157157
return get_erratum(erratum_id, full=full)
158158

159159

160+
class ErratumBuilds(RootModel):
161+
# Map variant and architecture to a set of subpackage names
162+
# we ship for that architecture
163+
# {
164+
# "AppStream": {
165+
# "SRPMS": {"libtiff"}
166+
# "aarch64": {"libtiff", "libtiff-devel", ...}
167+
# }
168+
# }
169+
root: dict[str, dict[str, set[str]]]
170+
171+
172+
def variant_to_base_variant(variant: str) -> str:
173+
return variant.split("-")[0]
174+
175+
176+
def nvr_to_package_name(nvr: str) -> str:
177+
return nvr.rsplit("-", 2)[0]
178+
179+
180+
def get_erratum_builds(id: int | str) -> ErratumBuilds:
181+
data = ET_api_get(f"erratum/{id}/builds_list")
182+
183+
if len(data) != 1:
184+
raise ValueError("Expected JSON object to have a single product version key.")
185+
detail = next(iter(data.values()))
186+
187+
builds = detail.get("builds", [])
188+
if len(builds) != 1:
189+
raise ValueError("Expected a single build in the 'builds' list.")
190+
191+
build = builds[0]
192+
if len(build) != 1:
193+
raise ValueError("Expected build to have a single NVR key.")
194+
build_detail = next(iter(build.values()))
195+
196+
variant_arch = build_detail["variant_arch"]
197+
198+
file_list_map = {
199+
variant_to_base_variant(variant): {
200+
arch: set([nvr_to_package_name(rpm["filename"]) for rpm in rmps])
201+
for arch, rmps in arches.items()
202+
}
203+
for variant, arches in variant_arch.items()
204+
}
205+
206+
return ErratumBuilds(root=file_list_map)
207+
208+
160209
class RHELVersion(BaseModel):
161210
major: int
162211
minor: int
@@ -381,6 +430,19 @@ def get_erratum_build_nvr(erratum_id: str | int, package_name: str) -> str | Non
381430
return None
382431

383432

433+
def errata_have_same_file_lists(errata_id1: int | str, errata_id2: int | str):
434+
"""Check if the given errata have the same file lists
435+
436+
After stripping package versions and RHEL release versions,
437+
do the two errata ship the same subpackages for each
438+
variant and architecture?
439+
440+
Throws an exception if either errata has more than one build
441+
attached to it.
442+
"""
443+
return get_erratum_builds(errata_id1) == get_erratum_builds(errata_id2)
444+
445+
384446
class RuleParseError(Exception):
385447
pass
386448

0 commit comments

Comments
 (0)