From ed861d9e2fcd0462037b2db333aec9e0aac7f678 Mon Sep 17 00:00:00 2001
From: Pierre Smeyers <pierre.smeyers@gmail.com>
Date: Mon, 9 Jan 2023 18:51:31 +0100
Subject: [PATCH] feat(package): support publish snapshot (untested) version

---
 README.md                    | 19 +++++++++++++++++
 kicker.json                  | 13 ++++++++++++
 templates/gitlab-ci-helm.yml | 41 ++++++++++++++++++++++++++++++------
 3 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index 0d76c4e..9b837fa 100644
--- a/README.md
+++ b/README.md
@@ -329,6 +329,7 @@ This job [packages](https://helm.sh/docs/helm/helm_package/) the Helm chart. It
 | Name                                | description                                   | default value                     |
 | ----------------------------------- | --------------------------------------------- | --------------------------------- |
 | `HELM_PACKAGE_ARGS`                 | The Helm [command with options](https://helm.sh/docs/helm/helm_package/) to perform the packaging (_without dynamic arguments such as the chart path_)   | `package --dependency-update` |
+| `HELM_PUBLISH_SNAPSHOT_ENABLED`     | Set to `true` to enable publishing the snapshot (untested) chart during the packaging step | _none_ (disabled) |
 | `HELM_SEMREL_RELEASE_DISABLED`      | Set to `true` to disable usage of `semantic-release` release info for helm package (see next chapter) | _none_ (enabled) |
 
 #### `semantic-release` integration
@@ -339,6 +340,22 @@ If no next version info is determined by `semantic-release`, the package will be
 
 Note: You can disable the `semantic-release` integration described herebefore the `HELM_SEMREL_RELEASE_DISABLED` variable.
 
+#### Chart version management
+
+Depending on the branch and the step in the CI/CD pipeline, the chart will be packaged with a different version.
+
+The general version format will be `<x.y.z>-<label>`:
+
+* `<x.y.z>`: 
+    * if [semantic-release integration](#semantic-release-integration) is enabled: uses the version determined by `semantic-release`, 
+    * otherwise uses the version from the chart file
+* `<label>`:
+    * on the production branch (`main` or `master` by default), no trailing label is used
+    * on any other branch, `$CI_COMMIT_REF_SLUG` is used as trailing label<br/>
+    _(ex: `review-feature-12` on branch `review/feature-12`)_
+    * :warning: when `HELM_PUBLISH_SNAPSHOT_ENABLED` is enabled, the chart is additionally packaged (and published) with a label suffixed with `snapshot`<br/>
+    _(ex: `snapshot` on production branch and `review-feature-12-snapshot` on branch `review/feature-12`)_
+
 ### `helm-publish` job
 
 This job publishes the packaged chart to a [chart repository](https://helm.sh/docs/topics/chart_repository/) or [OCI-based registry](https://helm.sh/docs/topics/registries/). It uses the following variables:
@@ -349,8 +366,10 @@ This job publishes the packaged chart to a [chart repository](https://helm.sh/do
 | :lock: `HELM_PUBLISH_USER`          | Helm registry username                       | `$CI_REGISTRY_USER`     |
 | :lock: `HELM_PUBLISH_PASSWORD`      | Helm registry password                       | `$CI_REGISTRY_PASSWORD` |
 | `HELM_PUBLISH_URL`                  | The URL of the Helm repository to publish your Helm package.<br/>Supports both [chart repository](https://helm.sh/docs/topics/chart_repository/) or [OCI-based registry](https://helm.sh/docs/topics/registries/) (url must be prefixed with `oci://`) | `oci://$CI_REGISTRY/$CI_PROJECT_PATH/charts` ([GitLab's container registry](https://docs.gitlab.com/ee/user/packages/container_registry/)) |
+| `HELM_PUBLISH_ON`                   | Defines on which branch(es) the publish job shall be enabled (`prod` to enable on production branch only, `protected` to enable on protected references and `all` to enable on all Git references) | `prod`                  |
 | `HELM_CM_PUSH_PLUGIN_VERSION`       | cm-push plugin version to install (only when using `push` method with a regular chart [repository](https://helm.sh/docs/topics/chart_repository/)) | _none_ (latest) |
 
+
 #### Supported publish methods
 
 The Helm publish supports several methods, configurable with the `$HELM_PUBLISH_URL` variable:
diff --git a/kicker.json b/kicker.json
index 555fced..57d366b 100644
--- a/kicker.json
+++ b/kicker.json
@@ -167,6 +167,12 @@
           "default": "package --dependency-update",
           "advanced": true
         },
+        {
+          "name": "HELM_PUBLISH_SNAPSHOT_ENABLED",
+          "description": "Set to `true` to enable publishing the snapshot (untested) chart during the packaging step",
+          "type": "boolean",
+          "advanced": true
+        },
         {
           "name": "HELM_SEMREL_RELEASE_DISABLED",
           "description": "Disable semantic-release integration",
@@ -205,6 +211,13 @@
           "default": "$CI_REGISTRY_PASSWORD",
           "secret": true
         },
+        {
+          "name": "HELM_PUBLISH_ON",
+          "description": "Defines on which branch(es) the publish job shall be enabled",
+          "default": "prod",
+          "type": "enum",
+          "values": ["prod", "protected", "all"]
+        },
         {
           "name": "HELM_CM_PUSH_PLUGIN_VERSION",
           "description": "cm-push plugin version to install (only when using `push` method with a regular chart [repository](https://helm.sh/docs/topics/chart_repository/)",
diff --git a/templates/gitlab-ci-helm.yml b/templates/gitlab-ci-helm.yml
index 3613ad9..76d7583 100644
--- a/templates/gitlab-ci-helm.yml
+++ b/templates/gitlab-ci-helm.yml
@@ -107,6 +107,7 @@ variables:
 
   HELM_BASE_APP_NAME: "$CI_PROJECT_NAME"
   HELM_REVIEW_ENVIRONMENT_SCHEME: "https"
+  HELM_PUBLISH_ON: "prod"
 
   # default production ref name (pattern)
   PROD_REF: '/^(master|main)$/'
@@ -559,7 +560,7 @@ stages:
   }
 
   function helm_package() {
-    # semantic-release integration
+    # determine chart version to publish (semantic-release integration)
     if [[ "${SEMREL_INFO_ON}" && "${DOCKER_SEMREL_RELEASE_DISABLED}" != "true" ]]
     then
       if [[ -z "${SEMREL_INFO_NEXT_VERSION}" ]]
@@ -567,20 +568,44 @@ stages:
         log_warn "[semantic-release] no new version to release: skip"
         exit 0
       else
-        log_info "[semantic-release] use computed next version: \\e[1;94m${SEMREL_INFO_NEXT_VERSION}\\e[0m"
-        helm_version_opts="--version ${SEMREL_INFO_NEXT_VERSION}"
+        log_info "[semantic-release] use computed next version: \\e[33;1m${SEMREL_INFO_NEXT_VERSION}\\e[0m"
+        base_version="${SEMREL_INFO_NEXT_VERSION}"
       fi
+    else
+      base_version=$(awk -F':' '/^version:/ {print $2}' "$HELM_CHART_DIR/Chart.yaml")
+      base_version=${base_version// /}
+    fi
+
+    # also determine version label
+    prod_ref_expr=${PROD_REF#/}
+    prod_ref_expr=${prod_ref_expr%/}
+    if [[ "$CI_COMMIT_REF_NAME" =~ $prod_ref_expr ]]
+    then
+      version_label=""
+    else
+      version_label="-$CI_COMMIT_REF_SLUG"
     fi
 
     add_helm_repositories
 
     # helm package
+    log_info "packaging chart with version: \\e[33;1m${base_version}${version_label}\\e[0m"
     # shellcheck disable=SC2086
-    helm ${TRACE+--debug} $HELM_PACKAGE_ARGS $helm_version_opts $HELM_CHART_DIR --destination helm_packages
+    helm ${TRACE+--debug} $HELM_PACKAGE_ARGS --version ${base_version}${version_label} $HELM_CHART_DIR --destination helm_packages
+
+    if [[ "$HELM_PUBLISH_SNAPSHOT_ENABLED" == "true" ]]
+    then
+      log_info "snapshot enabled: also package and publish chart with version: \\e[33;1m${base_version}${version_label}-snapshot\\e[0m"
+      mkdir -p /tmp/helm_snapshot
+      # shellcheck disable=SC2086
+      helm ${TRACE+--debug} $HELM_PACKAGE_ARGS --version ${base_version}${version_label}-snapshot $HELM_CHART_DIR --destination /tmp/helm_snapshot
+      snapshot_package=$(ls -1 /tmp/helm_snapshot/*.tgz 2>/dev/null || echo "")
+      helm_publish "$snapshot_package"
+    fi
   }
 
   function helm_publish() {
-    helm_package=$(ls -1 ./helm_packages/*.tgz 2>/dev/null || echo "")
+    helm_package=${1:-$(ls -1 ./helm_packages/*.tgz 2>/dev/null || echo "")}
     if [[ -z "$helm_package" ]]; then
       log_error "No package found to deploy"
       exit 1
@@ -894,7 +919,11 @@ helm-publish:
   script:
     - helm_publish
   rules:
-    - if: '$HELM_PUBLISH_URL == null || $HELM_PUBLISH_URL == "" || $CI_COMMIT_REF_NAME !~ $PROD_REF || $HELM_PUBLISH_METHOD == "disabled"'
+    - if: '$HELM_PUBLISH_URL == null || $HELM_PUBLISH_URL == "" || $HELM_PUBLISH_METHOD == "disabled"'
+      when: never
+    - if: '$HELM_PUBLISH_ON == "prod" && $CI_COMMIT_REF_NAME !~ $PROD_REF'
+      when: never
+    - if: '$HELM_PUBLISH_ON == "protected" && $CI_COMMIT_REF_PROTECTED != "true"'
       when: never
     - if: '$AUTODEPLOY_TO_PROD == "true"'
       exists:
-- 
GitLab