From 8113f3e8c3cfd4250c9105fc523cb2e01f9c5b41 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 7 Jul 2026 19:21:48 +0100 Subject: [PATCH] Ensure Helm Pages publishes release chart --- .github/workflows/helm-pages.yml | 70 +++++++++++++++++++ .../subsystems/deployment-installability.md | 5 ++ .../installtests/build_release_assets_test.go | 5 ++ .../release_promotion_policy_test.py | 5 ++ 4 files changed, 85 insertions(+) diff --git a/.github/workflows/helm-pages.yml b/.github/workflows/helm-pages.yml index e5fecb784..48add590b 100644 --- a/.github/workflows/helm-pages.yml +++ b/.github/workflows/helm-pages.yml @@ -236,6 +236,76 @@ jobs: CR_RELEASE_NAME_TEMPLATE: "helm-chart-{{ .Version }}" CR_MAKE_RELEASE_LATEST: false + - name: Ensure chart release and pages index + env: + GITHUB_TOKEN: ${{ github.token }} + VERSION: ${{ steps.version.outputs.version }} + REPOSITORY: ${{ github.repository }} + RELEASE_TAG: ${{ steps.version.outputs.release_tag }} + run: | + set -euo pipefail + + CHART="pulse-${VERSION}.tgz" + CHART_PATH="dist/${CHART}" + CHART_RELEASE="helm-chart-${VERSION}" + CHART_RELEASE_URL="https://github.com/${REPOSITORY}/releases/download/${CHART_RELEASE}" + RELEASE_SHA="$(git rev-list -n 1 "${RELEASE_TAG}")" + + mkdir -p dist + helm package deploy/helm/pulse \ + --version "${VERSION}" \ + --app-version "${VERSION}" \ + --destination dist + + if gh release view "${CHART_RELEASE}" >/dev/null 2>&1; then + gh release upload "${CHART_RELEASE}" "${CHART_PATH}" --clobber + else + gh release create "${CHART_RELEASE}" "${CHART_PATH}" \ + --target "${RELEASE_SHA}" \ + --title "Helm chart ${VERSION}" \ + --notes "Helm chart for Pulse ${VERSION}." \ + --prerelease \ + --latest=false + fi + gh release edit "${CHART_RELEASE}" --prerelease --latest=false + + workdir="$(mktemp -d)" + cleanup() { + git worktree remove -f "${workdir}/gh-pages" >/dev/null 2>&1 || true + rm -rf "${workdir}" + } + trap cleanup EXIT + + git fetch origin gh-pages + git worktree add "${workdir}/gh-pages" origin/gh-pages + git -C "${workdir}/gh-pages" checkout -B gh-pages origin/gh-pages + + index_work="${workdir}/index" + mkdir -p "${index_work}" + cp "${CHART_PATH}" "${index_work}/${CHART}" + if [ -f "${workdir}/gh-pages/index.yaml" ]; then + cp "${workdir}/gh-pages/index.yaml" "${index_work}/index.yaml" + helm repo index "${index_work}" \ + --url "${CHART_RELEASE_URL}" \ + --merge "${index_work}/index.yaml" + else + helm repo index "${index_work}" --url "${CHART_RELEASE_URL}" + fi + cp "${index_work}/index.yaml" "${workdir}/gh-pages/index.yaml" + + if ! grep -q "version: ${VERSION}" "${workdir}/gh-pages/index.yaml"; then + echo "::error::Helm pages index is missing version ${VERSION}" + exit 1 + fi + + git -C "${workdir}/gh-pages" add index.yaml + if git -C "${workdir}/gh-pages" diff --cached --quiet; then + echo "Helm pages index already contains ${VERSION}" + else + git -C "${workdir}/gh-pages" commit -m "Update Helm chart index for ${VERSION}" + git -C "${workdir}/gh-pages" push origin HEAD:gh-pages + fi + - name: Mark Helm chart release as pre-release (avoid latest override) env: GITHUB_TOKEN: ${{ github.token }} diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index a839f3603..1e00ddac9 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -679,6 +679,11 @@ TLS floor in the dynamic config. `release` and `workflow_dispatch` triggers, and its chart-version resolver must prefer inputs over the release-event tag when inputs are present so all three entry paths converge on the same identity. + `helm-pages.yml` must not treat chart-releaser's "no chart changes + detected" no-op as a successful Pages publication for a newly published + release version. A successful Pages workflow must create or update the + `helm-chart-` release asset and assert that `gh-pages/index.yaml` + contains `version: ` before the workflow exits green. After pushing the OCI chart, `publish-helm-chart.yml` must prove the pushed chart is readable from GHCR without registry credentials by logging out of `ghcr.io` and running `helm show chart` against the versioned chart diff --git a/scripts/installtests/build_release_assets_test.go b/scripts/installtests/build_release_assets_test.go index 132872031..8cb7707c0 100644 --- a/scripts/installtests/build_release_assets_test.go +++ b/scripts/installtests/build_release_assets_test.go @@ -862,6 +862,11 @@ func TestDeploymentDefaultsPinVersionedImagesAndHelmDocsChecksum(t *testing.T) { `HELM_DOCS_ARCHIVE="helm-docs_${HELM_DOCS_VERSION}_Linux_x86_64.tar.gz"`, `HELM_DOCS_SHA256="a8cf72ada34fad93285ba2a452b38bdc5bd52cc9a571236244ec31022928d6cc"`, `sha256sum --check --`, + `name: Ensure chart release and pages index`, + `gh release create "${CHART_RELEASE}" "${CHART_PATH}"`, + `helm repo index "${index_work}"`, + `git -C "${workdir}/gh-pages" push origin HEAD:gh-pages`, + `grep -q "version: ${VERSION}"`, } for _, needle := range required { if !strings.Contains(helmPages, needle) { diff --git a/scripts/release_control/release_promotion_policy_test.py b/scripts/release_control/release_promotion_policy_test.py index 7bdddf7b4..c5d21d651 100644 --- a/scripts/release_control/release_promotion_policy_test.py +++ b/scripts/release_control/release_promotion_policy_test.py @@ -839,6 +839,11 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertNotIn("git pull --rebase origin main", helm_pages) self.assertNotIn("git push origin main", helm_pages) self.assertNotIn("kind load docker-image", helm_pages) + self.assertIn("Ensure chart release and pages index", helm_pages) + self.assertIn('gh release create "${CHART_RELEASE}" "${CHART_PATH}"', helm_pages) + self.assertIn('helm repo index "${index_work}"', helm_pages) + self.assertIn('git -C "${workdir}/gh-pages" push origin HEAD:gh-pages', helm_pages) + self.assertIn('grep -q "version: ${VERSION}"', helm_pages) self.assertIn("helm status pulse || true", helm_pages) self.assertIn("kubectl describe pods -A || true", helm_pages) self.assertIn("kubectl get events -A --sort-by=.lastTimestamp || kubectl get events -A || true", helm_pages)