diff --git a/artcommon/artcommonlib/constants.py b/artcommon/artcommonlib/constants.py index 7bc1b280b..5161844e5 100644 --- a/artcommon/artcommonlib/constants.py +++ b/artcommon/artcommonlib/constants.py @@ -3,3 +3,4 @@ RHCOS_RELEASES_BASE_URL = "https://releases-rhcos-art.apps.ocp-virt.prod.psi.redhat.com/storage/releases" BREW_HUB = "https://brewhub.engineering.redhat.com/brewhub" BREW_DOWNLOAD_URL = "https://download.eng.bos.redhat.com/brewroot" +RELEASE_SCHEDULES = "https://pp.engineering.redhat.com/api/v7/releases" diff --git a/artcommon/artcommonlib/util.py b/artcommon/artcommonlib/util.py index 72ea48190..d75fc3c25 100644 --- a/artcommon/artcommonlib/util.py +++ b/artcommon/artcommonlib/util.py @@ -1,5 +1,8 @@ -import re from typing import OrderedDict, Optional +from datetime import datetime +from artcommonlib.constants import RELEASE_SCHEDULES +import requests +import re def remove_prefix(s: str, prefix: str) -> str: @@ -85,6 +88,58 @@ def merge_objects(a, b): return c +def is_future_release_date(date_str): + """ + If the input date is in future then return True elase False + """ + try: + target_date = datetime.strptime(date_str, "%Y-%m-%d") + except ValueError: + return False + current_date = datetime.now() + if target_date > current_date: + return True + else: + return False + + +def get_assembly_release_date(assembly, group): + """ + Get assembly release release date from release schedule API + """ + assembly_release_date = None + release_schedules = requests.get(f'{RELEASE_SCHEDULES}/{group}.z/?fields=all_ga_tasks', headers={'Accept': 'application/json'}) + for release in release_schedules.json()['all_ga_tasks']: + if assembly in release['name']: + assembly_release_date = datetime.strptime(release['date_start'], "%Y-%m-%d").strftime("%Y-%b-%d") + break + return assembly_release_date + + +def get_inflight(assembly, group): + """ + Get inflight release name from current assembly release + """ + inflight_release = None + assembly_release_date = get_assembly_release_date(assembly, group) + if not assembly_release_date: + raise ValueError(f'Assembly release date not found for {assembly}') + major, minor = get_ocp_version_from_group(group) + release_schedules = requests.get(f'{RELEASE_SCHEDULES}/openshift-{major}.{minor-1}.z/?fields=all_ga_tasks', headers={'Accept': 'application/json'}) + for release in release_schedules.json()['all_ga_tasks']: + is_future = is_future_release_date(release['date_start']) + if is_future: + days_diff = abs((datetime.strptime(assembly_release_date, "%Y-%m-%d") - datetime.strptime(release['date_start'], "%Y-%m-%d")).days) + if days_diff <= 5: # if next Y-1 release and assembly release in the same week + match = re.search(r'\d+\.\d+\.\d+', release['name']) + if match: + inflight_release = match.group() + break + else: + raise ValueError(f"Didn't find in_inflight release in {release['name']}") + return inflight_release + + def isolate_rhel_major_from_version(version: str) -> Optional[int]: """ E.g. '9.2' => 9 @@ -94,3 +149,13 @@ def isolate_rhel_major_from_version(version: str) -> Optional[int]: if match: return int(match[1]) return None + + +def get_ocp_version_from_group(group): + """ + Extract ocp version from group value openshift-4.15 --> 4, 15 + """ + match = re.fullmatch(r"openshift-(\d+).(\d+)", group) + if not match: + raise ValueError(f"Invalid group name: {group}") + return int(match[1]), int(match[2]) diff --git a/pyartcd/pyartcd/pipelines/build_microshift.py b/pyartcd/pyartcd/pipelines/build_microshift.py index 576619e05..f20e39e35 100644 --- a/pyartcd/pyartcd/pipelines/build_microshift.py +++ b/pyartcd/pyartcd/pipelines/build_microshift.py @@ -13,6 +13,7 @@ import click from artcommonlib.arch_util import brew_arch_for_go_arch +from artcommonlib.util import get_ocp_version_from_group from doozerlib.assembly import AssemblyTypes from doozerlib.util import isolate_nightly_name_components from ghapi.all import GhApi @@ -54,10 +55,7 @@ def __init__(self, runtime: Runtime, group: str, assembly: str, payloads: Tuple[ self.slack_client.bind_channel(group) # determines OCP version - match = re.fullmatch(r"openshift-(\d+).(\d+)", group) - if not match: - raise ValueError(f"Invalid group name: {group}") - self._ocp_version = (int(match[1]), int(match[2])) + self._ocp_version = get_ocp_version_from_group(group) # sets environment variables for Elliott and Doozer self._elliott_env_vars = os.environ.copy() diff --git a/pyartcd/pyartcd/pipelines/gen_assembly.py b/pyartcd/pyartcd/pipelines/gen_assembly.py index 5e9df56fe..62800ddba 100644 --- a/pyartcd/pyartcd/pipelines/gen_assembly.py +++ b/pyartcd/pyartcd/pipelines/gen_assembly.py @@ -9,7 +9,7 @@ import click from ghapi.all import GhApi -from artcommonlib.util import split_git_url, merge_objects +from artcommonlib.util import split_git_url, merge_objects, get_inflight from pyartcd import exectools, constants, jenkins from pyartcd.cli import cli, click_coroutine, pass_runtime from pyartcd.git import GitRepository @@ -43,7 +43,7 @@ def __init__(self, runtime: Runtime, group: str, assembly: str, data_path: str, self.auto_trigger_build_sync = auto_trigger_build_sync self.custom = custom self.arches = arches - self.in_flight = in_flight + self.in_flight = in_flight if in_flight else get_inflight(assembly, group) self.previous_list = previous_list self.auto_previous = auto_previous self.pre_ga_mode = pre_ga_mode @@ -91,7 +91,7 @@ async def run(self): pr = await self._create_or_update_pull_request(assembly_definition) # Sends a slack message - message = f"Hi @release-artists , please review assembly definition for {self.assembly}: {pr.html_url}" + message = f"Hi @release-artists , please review assembly definition for {self.assembly}: {pr.html_url}\n\nthe inflight release is {self.in_flight}" await self._slack_client.say(message, slack_thread) except Exception as err: diff --git a/pyartcd/pyartcd/pipelines/prepare_release.py b/pyartcd/pyartcd/pipelines/prepare_release.py index 6c8921204..4decebb52 100644 --- a/pyartcd/pyartcd/pipelines/prepare_release.py +++ b/pyartcd/pyartcd/pipelines/prepare_release.py @@ -16,6 +16,7 @@ from ruamel.yaml import YAML from tenacity import retry, stop_after_attempt, wait_fixed +from artcommonlib.util import get_assembly_release_date from doozerlib.assembly import AssemblyTypes from elliottlib.assembly import assembly_group_config from elliottlib.errata import set_blocking_advisory, get_blocking_advisories @@ -85,7 +86,7 @@ def __init__( if default_advisories: raise ValueError("default_advisories cannot be set for a non-stream assembly.") - self.release_date = date + self.release_date = date if date else get_assembly_release_date(assembly, group) self.package_owner = package_owner or self.runtime.config["advisory"]["package_owner"] self._slack_client = slack_client self.working_dir = self.runtime.working_dir.absolute() @@ -148,6 +149,7 @@ async def run(self): for ad in advisories: if advisories[ad] < 0: advisories[ad] = self.create_advisory(advisory_type=advisory_type, art_advisory_key=ad) + await self._slack_client.say_in_thread(f"Advisories created with release date {self.release_date}") await self.set_advisory_dependencies(advisories) @@ -711,7 +713,7 @@ async def verify_attached_operators(self, *advisories: List[int], gather_depende help="The name of an assembly to rebase & build for. e.g. 4.9.1") @click.option("--name", metavar="RELEASE_NAME", help="release name (e.g. 4.6.42)") -@click.option("--date", metavar="YYYY-MMM-DD", required=True, +@click.option("--date", metavar="YYYY-MMM-DD", help="Expected release date (e.g. 2020-11-25)") @click.option("--package-owner", metavar='EMAIL', help="Advisory package owner; Must be an individual email address; May be anyone who wants random advisory spam") diff --git a/pyartcd/pyartcd/pipelines/rebuild.py b/pyartcd/pyartcd/pipelines/rebuild.py index a69bfdeee..eef93d324 100644 --- a/pyartcd/pyartcd/pipelines/rebuild.py +++ b/pyartcd/pyartcd/pipelines/rebuild.py @@ -15,6 +15,7 @@ import yaml from aioredlock import LockError from doozerlib.assembly import AssemblyTypes +from artcommonlib.util import get_ocp_version_from_group from pyartcd import constants, exectools, locks, jenkins from pyartcd.cli import cli, click_coroutine, pass_runtime from pyartcd.record import parse_record_log @@ -52,10 +53,7 @@ def __init__(self, runtime: Runtime, group: str, assembly: str, self.ocp_build_data_url = ocp_build_data_url # determines OCP version - match = re.fullmatch(r"openshift-(\d+).(\d+)", group) - if not match: - raise ValueError(f"Invalid group name: {group}") - self._ocp_version = (int(match[1]), int(match[2])) + self._ocp_version = get_ocp_version_from_group(group) # sets environment variables for Doozer self._doozer_env_vars = os.environ.copy() diff --git a/pyartcd/tests/pipelines/test_gen_assembly.py b/pyartcd/tests/pipelines/test_gen_assembly.py index b0565fb8d..e607d8e6e 100644 --- a/pyartcd/tests/pipelines/test_gen_assembly.py +++ b/pyartcd/tests/pipelines/test_gen_assembly.py @@ -13,7 +13,7 @@ def test_get_nightlies(self, cmd_gather_async: AsyncMock): runtime = MagicMock() pipeline = GenAssemblyPipeline(runtime, "openshift-4.12", "4.12.99", "https://example.com/ocp-build-data.git", nightlies=(), allow_pending=False, allow_rejected=False, - allow_inconsistency=False, custom=False, arches=(), in_flight=None, + allow_inconsistency=False, custom=False, arches=(), in_flight="4.11.88", previous_list=(), auto_previous=True, auto_trigger_build_sync=False, pre_ga_mode="none") actual = asyncio.run(pipeline._get_nightlies()) @@ -97,7 +97,7 @@ def test_create_or_update_pull_request(self, git_repo: MagicMock, yaml: MagicMoc }}) pipeline = GenAssemblyPipeline(runtime, "openshift-4.12", "4.12.99", "https://example.com/ocp-build-data.git", nightlies=(), allow_pending=False, allow_rejected=False, - allow_inconsistency=False, custom=False, arches=(), in_flight=None, + allow_inconsistency=False, custom=False, arches=(), in_flight="4.11.88", previous_list=(), auto_previous=True, auto_trigger_build_sync=False, pre_ga_mode="none") pipeline._working_dir = Path("/path/to/working") @@ -147,7 +147,7 @@ async def test_run(self, get_nightlies: AsyncMock, _gen_assembly_from_releases: pipeline = GenAssemblyPipeline(runtime, "openshift-4.12", "4.12.99", "https://example.com/ocp-build-data.git", nightlies=(), allow_pending=False, allow_rejected=False, - allow_inconsistency=False, custom=False, arches=(), in_flight=None, + allow_inconsistency=False, custom=False, arches=(), in_flight="4.11.88", previous_list=(), auto_previous=True, auto_trigger_build_sync=False, pre_ga_mode="none") pipeline._working_dir = Path("/path/to/working")