From bc947a0e8ac2f03fba0722453ef082ecd4db78c6 Mon Sep 17 00:00:00 2001 From: borislavr Date: Wed, 23 Jul 2025 10:51:02 +0300 Subject: [PATCH 1/7] feat: Remove deprecated Helm Charts Release action and add new charts-values-update-action --- .../README.md | 4 ++-- .../action.yaml | 0 .../charts-values-update-config.yaml} | 0 .../image-versions-replace.py | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename actions/{helm-charts-release => charts-values-update-action}/README.md (96%) rename actions/{helm-charts-release => charts-values-update-action}/action.yaml (100%) rename actions/{helm-charts-release/helm-charts-release-config.yaml => charts-values-update-action/charts-values-update-config.yaml} (100%) rename actions/{helm-charts-release => charts-values-update-action}/image-versions-replace.py (100%) diff --git a/actions/helm-charts-release/README.md b/actions/charts-values-update-action/README.md similarity index 96% rename from actions/helm-charts-release/README.md rename to actions/charts-values-update-action/README.md index 2263fc5e..6ecbe054 100644 --- a/actions/helm-charts-release/README.md +++ b/actions/charts-values-update-action/README.md @@ -82,7 +82,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Release Helm Charts - uses: netcracker/qubership-workflow-hub/actions/helm-charts-release@main + uses: netcracker/qubership-workflow-hub/actions/charts-values-update-action@main with: release-version: '1.0.0' chart-version: '1.0.0' @@ -113,4 +113,4 @@ jobs: - `version`: Template for the image version (e.g., `my-image:${release}`). - `image`: List of image keys to update in `values.yaml`. -> Example: [helm-charts-release-config.yaml](./helm-charts-release-config.yaml). +> Example: [charts-values-update-config.yaml](./charts-values-update-config.yaml). diff --git a/actions/helm-charts-release/action.yaml b/actions/charts-values-update-action/action.yaml similarity index 100% rename from actions/helm-charts-release/action.yaml rename to actions/charts-values-update-action/action.yaml diff --git a/actions/helm-charts-release/helm-charts-release-config.yaml b/actions/charts-values-update-action/charts-values-update-config.yaml similarity index 100% rename from actions/helm-charts-release/helm-charts-release-config.yaml rename to actions/charts-values-update-action/charts-values-update-config.yaml diff --git a/actions/helm-charts-release/image-versions-replace.py b/actions/charts-values-update-action/image-versions-replace.py similarity index 100% rename from actions/helm-charts-release/image-versions-replace.py rename to actions/charts-values-update-action/image-versions-replace.py From 5035ee04b4840970c7f635b612630ab20f5b14a4 Mon Sep 17 00:00:00 2001 From: borislavr Date: Thu, 24 Jul 2025 16:50:07 +0300 Subject: [PATCH 2/7] feat: Enhance image version retrieval with stable version checks and regex support --- .../image-versions-replace.py | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/actions/charts-values-update-action/image-versions-replace.py b/actions/charts-values-update-action/image-versions-replace.py index 64ea7827..800c0414 100644 --- a/actions/charts-values-update-action/image-versions-replace.py +++ b/actions/charts-values-update-action/image-versions-replace.py @@ -2,7 +2,9 @@ # -*- coding: utf-8 -*- import argparse import json +import logging import os +from packaging import version import re import subprocess import yaml @@ -18,15 +20,58 @@ def replacer(match): return pattern.sub(replacer, input_string) +def get_latest_stable_version(versions): + stable_versions = [] + + for v in versions: + try: + ver = version.parse(v) + # Check that version is stable + if not ver.is_prerelease: + stable_versions.append((v, ver)) + except version.InvalidVersion: + continue + + if not stable_versions: + return None + + latest = sorted(stable_versions, key=lambda x: x[1])[-1][0] + return latest + +def get_latest_version_by_regex(versions, pattern_str): + try: + pattern = r'' + pattern_str + compiled_pattern = re.compile(pattern) + except re.error as e: + logging.warning(f"Invalid regular expression '{pattern}': {str(e)}") + raise ValueError(f"Incorrect regular expression: {str(e)}") from None + + matched_versions = [] + + for v in versions: + try: + if compiled_pattern.fullmatch(v): + ver = version.parse(v) + if not ver.is_prerelease: + matched_versions.append((v, ver)) + except version.InvalidVersion: + continue + + if not matched_versions: + return None + + return sorted(matched_versions, key=lambda x: x[1])[-1][0] + def replace_tag_regexp(image_str, tag_re): # Try to find the requested tag for given image_str if tag_re.startswith("#"): try: os.system(f"skopeo login -u $GITHUB_ACTOR -p $GITHUB_TOKEN ghcr.io") + tags = subprocess.run(f"skopeo list-tags docker://{image_str} | jq -r '.Tags[]'", shell=True, text=True, check=True, capture_output=True).stdout.split() if tag_re[1:] == 'latest': - result_tag = subprocess.run(f"skopeo list-tags docker://{image_str} | jq -r '.Tags[]' | grep -e \"^[0-9]*\.[0-9]*\.[0-9]*\" | sort -V | tail -n 1", shell=True, text=True, check=True, capture_output=True).stdout.rstrip() + result_tag = get_latest_stable_version(tags) else: - result_tag = subprocess.run(f"skopeo list-tags docker://{image_str} | jq -r '.Tags[] | select(test(\"^{tag_re[1:]}\"))' | sort -V | tail -n 1", shell=True, text=True, check=True, capture_output=True).stdout.rstrip() + result_tag = get_latest_version_by_regex(tags, tag_re[1:]) return(result_tag) except Exception as e: print(f"Error: {e}") From a5e95691cf715a3be261ab1fc988b278c8eef07e Mon Sep 17 00:00:00 2001 From: borislavr Date: Thu, 24 Jul 2025 17:25:53 +0300 Subject: [PATCH 3/7] feat: Add debug logging for regex pattern in version retrieval --- actions/charts-values-update-action/image-versions-replace.py | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/charts-values-update-action/image-versions-replace.py b/actions/charts-values-update-action/image-versions-replace.py index 800c0414..2ed80ee3 100644 --- a/actions/charts-values-update-action/image-versions-replace.py +++ b/actions/charts-values-update-action/image-versions-replace.py @@ -40,6 +40,7 @@ def get_latest_stable_version(versions): def get_latest_version_by_regex(versions, pattern_str): try: + logging.debug(f"Using regex pattern: {pattern_str}") pattern = r'' + pattern_str compiled_pattern = re.compile(pattern) except re.error as e: From 52bb381b82f3c3536f28b9afc794b9a053fd0398 Mon Sep 17 00:00:00 2001 From: borislavr Date: Thu, 24 Jul 2025 17:29:02 +0300 Subject: [PATCH 4/7] feat: Replace logging with print statements for regex pattern debugging --- .../charts-values-update-action/image-versions-replace.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/actions/charts-values-update-action/image-versions-replace.py b/actions/charts-values-update-action/image-versions-replace.py index 2ed80ee3..348c6546 100644 --- a/actions/charts-values-update-action/image-versions-replace.py +++ b/actions/charts-values-update-action/image-versions-replace.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- import argparse import json -import logging import os from packaging import version import re @@ -40,11 +39,11 @@ def get_latest_stable_version(versions): def get_latest_version_by_regex(versions, pattern_str): try: - logging.debug(f"Using regex pattern: {pattern_str}") + print(f"Using regex pattern: {pattern_str}") pattern = r'' + pattern_str compiled_pattern = re.compile(pattern) except re.error as e: - logging.warning(f"Invalid regular expression '{pattern}': {str(e)}") + print(f"Invalid regular expression '{pattern}': {str(e)}") raise ValueError(f"Incorrect regular expression: {str(e)}") from None matched_versions = [] From 5e8c8634409014216cfb35def1b014688af3e3a5 Mon Sep 17 00:00:00 2001 From: borislavr Date: Thu, 24 Jul 2025 17:39:38 +0300 Subject: [PATCH 5/7] feat: Add error handling for missing tags in replace_tag_regexp function --- actions/charts-values-update-action/image-versions-replace.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actions/charts-values-update-action/image-versions-replace.py b/actions/charts-values-update-action/image-versions-replace.py index 348c6546..897988a7 100644 --- a/actions/charts-values-update-action/image-versions-replace.py +++ b/actions/charts-values-update-action/image-versions-replace.py @@ -72,6 +72,8 @@ def replace_tag_regexp(image_str, tag_re): result_tag = get_latest_stable_version(tags) else: result_tag = get_latest_version_by_regex(tags, tag_re[1:]) + if not result_tag: + raise ValueError(f"No matching tag found for {image_str} with pattern {tag_re}") return(result_tag) except Exception as e: print(f"Error: {e}") From e40c000f3b1265d8d2c262c814e0cd69047a35c7 Mon Sep 17 00:00:00 2001 From: borislavr Date: Thu, 24 Jul 2025 17:51:37 +0300 Subject: [PATCH 6/7] feat: Improve error handling in regex functions with graceful exits --- .../charts-values-update-action/image-versions-replace.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/actions/charts-values-update-action/image-versions-replace.py b/actions/charts-values-update-action/image-versions-replace.py index 897988a7..934e35af 100644 --- a/actions/charts-values-update-action/image-versions-replace.py +++ b/actions/charts-values-update-action/image-versions-replace.py @@ -6,6 +6,7 @@ from packaging import version import re import subprocess +import sys import yaml def replace_env_variables(input_string): @@ -44,7 +45,8 @@ def get_latest_version_by_regex(versions, pattern_str): compiled_pattern = re.compile(pattern) except re.error as e: print(f"Invalid regular expression '{pattern}': {str(e)}") - raise ValueError(f"Incorrect regular expression: {str(e)}") from None + sys.exit(1) + #raise ValueError(f"Incorrect regular expression: {str(e)}") from None matched_versions = [] @@ -73,7 +75,9 @@ def replace_tag_regexp(image_str, tag_re): else: result_tag = get_latest_version_by_regex(tags, tag_re[1:]) if not result_tag: - raise ValueError(f"No matching tag found for {image_str} with pattern {tag_re}") + print(f"No matching tag found for {image_str} with pattern {tag_re}") + #raise ValueError(f"No matching tag found for {image_str} with pattern {tag_re}") + sys.exit(1) return(result_tag) except Exception as e: print(f"Error: {e}") From d2036dbb7a0b1b2a4338f69cbcfa23fbedb364f7 Mon Sep 17 00:00:00 2001 From: borislavr Date: Thu, 24 Jul 2025 18:00:30 +0300 Subject: [PATCH 7/7] docs: Update README to clarify regex syntax for version retrieval --- actions/charts-values-update-action/README.md | 6 +++--- .../charts-values-update-config.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/actions/charts-values-update-action/README.md b/actions/charts-values-update-action/README.md index 6ecbe054..7182cc31 100644 --- a/actions/charts-values-update-action/README.md +++ b/actions/charts-values-update-action/README.md @@ -32,9 +32,9 @@ Can be `replace` or `parse`. Defaults to `parse`. If set to `replace` the action will just replace the versions of docker images with `release-version` value. If set to `parse` the action read provided `config-file` and substitute any environment variables provided in the version part. For example if you have some 3-rd party image in `values.yaml` file and want to manage it's version, you can add repository level variable and use it in the config file: `some-thirg-party-image:${THIRD_PARTY_VERSION}`. -Also if you want the action to find the latest version of some image (supplimentary service for instance), you can set it to something like `#4.*.*` or `#latest`. -In that case the action will find the latest tag of an image which satisfy the regular expression. The regular expression of a tag must start with `#` symbol and follow the `jq` syntax. -**Special word `#latest` will result the latest SemVer tag of the image, not the one which marked with `latest` tag.** +Also if you want the action to find the latest version of some image (supplimentary service for instance), you can set it to something like `#4\.\d+\.\d+` or `#latest`. +In that case the action will find the latest tag of an image which satisfy the regular expression. The regular expression of a tag must start with `#` symbol and follow the Python `re` syntax. +**Special word `#latest` will result the latest SemVer tag of the image ('2.1.0','v4.3.2', etc.), not the one which marked with `latest` tag.** ### `working-directory` diff --git a/actions/charts-values-update-action/charts-values-update-config.yaml b/actions/charts-values-update-action/charts-values-update-config.yaml index 1fd091f5..6146456f 100644 --- a/actions/charts-values-update-action/charts-values-update-config.yaml +++ b/actions/charts-values-update-action/charts-values-update-config.yaml @@ -12,5 +12,5 @@ charts: image: - ghcr.io/netcracker/module1:${release} # This will replace the image version with the release version - ghcr.io/netcracker/module1-service1:${release}-${THIRD_PARTY_VERSION} # This will replace the image version with the release version and append the THIRD_PARTY_VERSION variable - - ghcr.io/netcracker/module1-service2:#5.*.* # This will select the latest tag matching the jq regular expression + - ghcr.io/netcracker/module1-service2:#5\.\d+\.\d+ # This will select the latest tag matching the jq regular expression - ghcr.io/netcracker/module1-service2:#latest # This will select the latest SemVer tag