From 1213091cd6504d896ac9df89f6c25ba0b395f532 Mon Sep 17 00:00:00 2001 From: Yuxiang Zhu Date: Wed, 9 Nov 2022 18:23:57 +0800 Subject: [PATCH] Support patch_version defined in assembly config If we have assembly config like this: ```yaml art5142: assembly: type: custom basis: assembly: 4.12.99 patch_version: 99 ``` The release name will become `4.12.99-assembly.art5142`. In case patch_version is not defined, let our automation to look at the chain of assembly inheritance to determine one, e.g. ```yaml art0000: assembly: type: custom basis: assembly: 4.12.88 art0001: assembly: type: custom basis: assembly: art0000 art0002: assembly: type: custom basis: assembly: art0001 ``` The patch_version of art0002 will default to 88 because release 4.12.88 is the closest ancestor of type standard. --- doozerlib/metadata.py | 17 ++++----- doozerlib/rpmcfg.py | 4 +-- doozerlib/runtime.py | 4 +-- doozerlib/util.py | 24 +++++++++++++ tests/test_util.py | 80 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 12 deletions(-) diff --git a/doozerlib/metadata.py b/doozerlib/metadata.py index ea6fe3a32..ec98456c6 100644 --- a/doozerlib/metadata.py +++ b/doozerlib/metadata.py @@ -15,15 +15,15 @@ import dateutil.parser from dockerfile_parse import DockerfileParser +import doozerlib -from .pushd import Dir -from .distgit import ImageDistGitRepo, RPMDistGitRepo -from . import exectools -from . import logutil -from .brew import BuildStates -from .util import isolate_el_version_in_brew_tag, isolate_git_commit_in_release +from doozerlib.pushd import Dir +from doozerlib.distgit import ImageDistGitRepo, RPMDistGitRepo +from doozerlib import exectools, logutil +from doozerlib.brew import BuildStates +from doozerlib.util import isolate_el_version_in_brew_tag, isolate_git_commit_in_release -from .model import Model, Missing +from doozerlib.model import Model, Missing from doozerlib.assembly import assembly_metadata_config, assembly_basis_event @@ -80,7 +80,7 @@ def rebuild(self): class Metadata(object): - def __init__(self, meta_type: str, runtime, data_obj: Dict, commitish: Optional[str] = None, prevent_cloning: Optional[bool] = False): + def __init__(self, meta_type: str, runtime: "doozerlib.Runtime", data_obj: Dict, commitish: Optional[str] = None, prevent_cloning: Optional[bool] = False): """ :param meta_type - a string. Index to the sub-class <'rpm'|'image'>. :param runtime - a Runtime object. @@ -169,6 +169,7 @@ def __init__(self, meta_type: str, runtime, data_obj: Dict, commitish: Optional[ pass else: # Ooof.. it is not defined in the assembly, so we need to find it dynamically. + self.logger.info("A commitish is not explicitly specified for %s. Determining from the latest build...", self.name) build_obj = self.get_latest_build(default=None, el_target=self.determine_rhel_targets()[0]) if build_obj: self.commitish = isolate_git_commit_in_release(build_obj['nvr']) diff --git a/doozerlib/rpmcfg.py b/doozerlib/rpmcfg.py index da33fa94d..e7f46d0c7 100644 --- a/doozerlib/rpmcfg.py +++ b/doozerlib/rpmcfg.py @@ -116,8 +116,8 @@ def _run_modifications(self, specfile: Optional[os.PathLike] = None, cwd: Option "release_name": "", } - if self.runtime.assembly_type in [AssemblyTypes.STANDARD, AssemblyTypes.CANDIDATE, AssemblyTypes.PREVIEW]: - context["release_name"] = util.get_release_name(self.runtime.assembly_type, self.runtime.group, self.runtime.assembly, None) + if self.runtime.assembly_type is not AssemblyTypes.STREAM: + context["release_name"] = util.get_release_name_for_assembly(self.runtime.group, self.runtime.get_releases_config(), self.runtime.assembly) for modification in self.config.content.source.modifications: if self.source_modifier_factory.supports(modification.action): diff --git a/doozerlib/runtime.py b/doozerlib/runtime.py index 95744ed07..0fd9950e6 100644 --- a/doozerlib/runtime.py +++ b/doozerlib/runtime.py @@ -310,8 +310,8 @@ def _get_replace_vars(self, group_config: Model): replace_vars['release_name'] = '' if self.assembly: replace_vars['runtime_assembly'] = self.assembly - if self.assembly_type not in [AssemblyTypes.STREAM, AssemblyTypes.CUSTOM]: - replace_vars['release_name'] = util.get_release_name(self.assembly_type, self.group, self.assembly, release_offset=None) + if self.assembly_type is not AssemblyTypes.STREAM: + replace_vars['release_name'] = util.get_release_name_for_assembly(self.group, self.get_releases_config(), self.assembly) return replace_vars def init_state(self): diff --git a/doozerlib/util.py b/doozerlib/util.py index 956dea99a..653477fcb 100644 --- a/doozerlib/util.py +++ b/doozerlib/util.py @@ -19,6 +19,8 @@ import semver import yaml +from doozerlib.model import Missing, Model + try: from reprlib import repr except ImportError: @@ -819,3 +821,25 @@ def get_release_name(assembly_type: assembly.AssemblyTypes, group_name: str, ass else: raise ValueError(f"Assembly type {assembly_type} is not supported.") return release_name + + +def get_release_name_for_assembly(group_name: str, releases_config: Model, assembly_name: str): + """ Get release name for an assembly. + """ + assembly_type = assembly.assembly_type(releases_config, assembly_name) + patch_version = assembly.assembly_basis(releases_config, assembly_name).get('patch_version') + if assembly_type is assembly.AssemblyTypes.CUSTOM: + patch_version = assembly.assembly_basis(releases_config, assembly_name).get('patch_version') + # If patch_version is not set, go through the chain of assembly inheritance and determine one + current_assembly = assembly_name + while patch_version is None: + parent_assembly = releases_config.releases[current_assembly].assembly.basis.assembly + if parent_assembly is Missing: + break + if assembly.assembly_type(releases_config, parent_assembly) is assembly.AssemblyTypes.STANDARD: + patch_version = int(parent_assembly.rsplit('.', 1)[-1]) + break + current_assembly = parent_assembly + if patch_version is None: + raise ValueError("patch_version is not set in assembly definition and can't be auto-determined through the chain of inheritance.") + return get_release_name(assembly_type, group_name, assembly_name, patch_version) diff --git a/tests/test_util.py b/tests/test_util.py index ae6734c24..bc02237ac 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,6 +1,7 @@ import unittest from doozerlib import util +from doozerlib.model import Model class TestUtil(unittest.TestCase): @@ -163,6 +164,85 @@ def test_isolate_timestamp_in_release(self): expected = None self.assertEqual(actual, expected) + def test_get_release_name_for_assembly(self): + releases_config = Model({ + "releases": { + "4.12.99": { + "assembly": { + "type": "standard", + "basis": { + "assembly": "4.12.98", + } + } + }, + "4.12.98": { + "assembly": { + "type": "standard", + "basis": { + "event": 12345, + } + } + }, + "art0000": { + "assembly": { + "type": "custom", + "basis": { + "assembly": "4.12.99", + } + } + }, + "art0001": { + "assembly": { + "type": "custom", + "basis": { + "assembly": "art0000", + } + } + }, + "art0002": { + "assembly": { + "type": "custom", + "basis": { + "assembly": "art0001", + "patch_version": 23, + } + } + }, + "art0003": { + "assembly": { + "type": "custom", + "basis": { + "assembly": "art0002", + } + } + }, + } + }) + + actual = util.get_release_name_for_assembly("openshift-4.12", releases_config, "4.12.99") + expected = "4.12.99" + self.assertEqual(actual, expected) + + actual = util.get_release_name_for_assembly("openshift-4.12", releases_config, "4.12.98") + expected = "4.12.98" + self.assertEqual(actual, expected) + + actual = util.get_release_name_for_assembly("openshift-4.12", releases_config, "art0000") + expected = "4.12.99-assembly.art0000" + self.assertEqual(actual, expected) + + actual = util.get_release_name_for_assembly("openshift-4.12", releases_config, "art0001") + expected = "4.12.99-assembly.art0001" + self.assertEqual(actual, expected) + + actual = util.get_release_name_for_assembly("openshift-4.12", releases_config, "art0002") + expected = "4.12.23-assembly.art0002" + self.assertEqual(actual, expected) + + actual = util.get_release_name_for_assembly("openshift-4.12", releases_config, "art0003") + expected = "4.12.23-assembly.art0003" + self.assertEqual(actual, expected) + if __name__ == "__main__": unittest.main()