Repository navigation
feat(helm): publish versioned Helm charts to GHCR #483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
e4439a6
feat(helm): rename chart and default Kubernetes resources
vermorag cb43d79
ci(helm): validate, smoke-test and publish OCI chart by release tag
vermorag ca2e607
fix(helm): correct chart archive validation assertion
vermorag 0a03fb2
feat(helm): map external module activation and literal environment va…
vermorag fa29b46
test(helm): cover module flags, environment sources, and collision ha…
vermorag 580db98
test(helm): fix multi-document yq assertions, string env collision ca…
vermorag a1ace5a
feat(helm): add Artifact Hub metadata and chart maintainers
vermorag b3d3abe
fix(helm): probe the built-in MySQL over TCP instead of the socket
vermorag 6bc98f7
fix(helm): keep clearing the legacy rollingUpdate strategy on upgrade
vermorag 889d0f5
fix(helm): address review feedback on release workflow, check script …
vermorag 63e9540
ci(helm): let a re-run verify a chart that an earlier attempt already…
vermorag 434c668
fix(helm): check only known env recipients and keep custom names in t…
vermorag 4181c1e
docs(helm): explain which naming overrides to keep when upgrading fro…
vermorag 2510efd
fix(helm): match only explicit not-found responses and clarify naming…
vermorag b3ccb2a
docs(helm): keep a custom nameOverride when upgrading from 0.1.x
vermorag File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| name: Helm OCI release | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - 'helm/v*' | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: helm-release-${{ github.ref }} | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| publish: | ||
| name: Validate and publish Helm chart | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 20 | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| env: | ||
| OCI_REPOSITORY: ghcr.io/cattr-app/helm/server | ||
| OCI_NAMESPACE: oci://ghcr.io/cattr-app/helm | ||
| steps: | ||
| - uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
| fetch-depth: 0 | ||
|
|
||
| - uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | ||
| with: | ||
| version: v3.19.0 | ||
|
|
||
| - uses: imjasonh/setup-crane@feee3b6bb0d4c68370f256a4502498c9227e5c6b # v0.7 | ||
| with: | ||
| version: v0.22.1 | ||
|
|
||
| - name: Validate tag, chart, image and branch | ||
| env: | ||
| RELEASE_TAG: ${{ github.ref_name }} | ||
| run: | | ||
| set -euo pipefail | ||
| bash .helm/ci/release-metadata.sh "$RELEASE_TAG" | ||
| git fetch --no-tags origin main | ||
| git merge-base --is-ancestor "$GITHUB_SHA" origin/main || { | ||
| echo "::error::Helm releases must point to commits reachable from main" | ||
| exit 1 | ||
| } | ||
| image_tag="$(helm show chart .helm | awk '/^appVersion:/ {gsub(/"/, "", $2); print $2}')" | ||
| crane manifest "ghcr.io/cattr-app/server:$image_tag" >/dev/null || { | ||
| echo "::error::Referenced application image is not available: $image_tag" | ||
| exit 1 | ||
| } | ||
|
|
||
| - name: Lint and validate chart | ||
| uses: docker://alpine/k8s@sha256:d50424976a0a888d2531f13035dce45c004ec2b6f877f233005ba35c0d61be5d # 1.34.12 | ||
| with: | ||
| entrypoint: sh | ||
| args: .helm/ci/check.sh | ||
|
|
||
| # A re-run of a failed release reuses the archive packaged by the first attempt: | ||
| # a fresh `helm package` is not byte-identical (it records timestamps), so it could | ||
| # not be compared with what was already pushed. | ||
| - name: Restore archive from an earlier attempt | ||
| id: restore | ||
| if: github.run_attempt > 1 | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 | ||
| with: | ||
| name: helm-chart-archive | ||
| path: dist | ||
|
|
||
| - name: Package chart | ||
| id: package | ||
| if: steps.restore.outcome != 'success' | ||
| env: | ||
| RELEASE_TAG: ${{ github.ref_name }} | ||
| run: | | ||
| set -euo pipefail | ||
| version="${RELEASE_TAG#helm/v}" | ||
| mkdir -p dist | ||
| helm package .helm --destination dist | ||
| test -f "dist/server-$version.tgz" | ||
| sha256sum "dist/server-$version.tgz" | tee dist/SHA256SUMS | ||
|
|
||
| - name: Preserve packaged archive | ||
| if: steps.package.outcome == 'success' | ||
| uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 | ||
| with: | ||
| name: helm-chart-archive | ||
| path: dist/ | ||
| if-no-files-found: error | ||
| retention-days: 14 | ||
|
|
||
| - name: Authenticate to GHCR | ||
| env: | ||
| GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| set -euo pipefail | ||
| printf '%s' "$GHCR_TOKEN" | helm registry login ghcr.io -u "$GITHUB_ACTOR" --password-stdin | ||
| printf '%s' "$GHCR_TOKEN" | crane auth login ghcr.io -u "$GITHUB_ACTOR" --password-stdin | ||
|
|
||
| - name: Publish immutable OCI chart and verify pull | ||
| env: | ||
| RELEASE_TAG: ${{ github.ref_name }} | ||
| ARCHIVE_RESTORED: ${{ steps.restore.outcome == 'success' }} | ||
| run: | | ||
| set -euo pipefail | ||
| version="${RELEASE_TAG#helm/v}" | ||
| sha256sum -c dist/SHA256SUMS | ||
| # No overwrite: previously published artifacts must remain immutable. | ||
| # Fail closed: only an explicit "not found" from the registry allows the push; | ||
| # any other lookup failure (timeout, authorization) aborts the release. | ||
| # The one exception is a re-run that restored the archive pushed by an earlier | ||
| # attempt of this run: then nothing is pushed and the published chart is only | ||
| # verified against that archive. | ||
| if lookup="$(crane manifest "$OCI_REPOSITORY:$version" 2>&1)"; then | ||
| if [ "$ARCHIVE_RESTORED" != "true" ]; then | ||
| echo "::error::Helm chart $version is already published; refusing overwrite" | ||
| exit 1 | ||
| fi | ||
| echo "Helm chart $version was pushed by an earlier attempt; verifying without pushing" | ||
| elif ! printf '%s' "$lookup" | grep -qE ': (GET|HEAD) [^ ]+: (MANIFEST_UNKNOWN|NAME_UNKNOWN): |: (GET|HEAD) [^ ]+: unexpected status code 404 Not Found'; then | ||
| echo "::error::Cannot determine whether Helm chart $version exists: $lookup" | ||
| exit 1 | ||
| else | ||
| helm push "dist/server-$version.tgz" "$OCI_NAMESPACE" | ||
| fi | ||
| mkdir -p pulled | ||
| helm pull "oci://$OCI_REPOSITORY" --version "$version" --destination pulled | ||
| cmp "dist/server-$version.tgz" "pulled/server-$version.tgz" | ||
| helm show chart "oci://$OCI_REPOSITORY" --version "$version" | ||
| crane digest "$OCI_REPOSITORY:$version" | tee dist/OCI-DIGEST |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| name: Helm Kind smoke test | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: [main] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| install: | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 25 | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | ||
| with: | ||
| version: v3.19.0 | ||
|
|
||
| - uses: helm/kind-action@1544676c07bb3570fcb70166beaa07c4528fd4aa # v1.15.1 | ||
|
|
||
| - name: Install demo chart without --wait (setup runs post-install) | ||
| run: | | ||
| set -euo pipefail | ||
| helm install cattr ./.helm --namespace cattr --create-namespace \ | ||
| -f .helm/ci/demo-mysql-values.yaml --timeout 15m | ||
| kubectl -n cattr rollout status deployment/cattr-mysql --timeout=10m | ||
| kubectl -n cattr wait --for=condition=complete job/cattr-setup --timeout=10m | ||
| kubectl -n cattr rollout status deployment/cattr --timeout=10m | ||
| kubectl -n cattr get deployments,pods,jobs,services | ||
|
|
||
| - name: Inspect failure | ||
| if: failure() | ||
| run: | | ||
| kubectl -n cattr get pods,jobs,deployments -o wide || true | ||
| kubectl -n cattr describe pods || true | ||
| kubectl -n cattr logs job/cattr-setup --all-containers --tail=100 || true | ||
| kubectl -n cattr logs deployment/cattr-mysql --all-containers --tail=100 || true | ||
| kubectl -n cattr logs deployment/cattr-mysql --previous --tail=100 || true | ||
| kubectl -n cattr get events --sort-by=.lastTimestamp || true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.