-
Notifications
You must be signed in to change notification settings - Fork 35
ci(helm): add chart release workflows #113
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
Open
spencercjh
wants to merge
4
commits into
Project-HAMi:main
Choose a base branch
from
spencercjh:feat/release-chart
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
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,170 @@ | ||
| name: Helm Release | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| push: | ||
| branches: | ||
| - main | ||
| tags: | ||
| - "v*" | ||
| paths: | ||
| - charts/ascend-device-plugin/Chart.yaml | ||
|
|
||
| env: | ||
| HELM_VERSION: "v3.20.0" | ||
| CHART_PATH: charts/ascend-device-plugin | ||
| CHART_NAME: ascend-device-plugin | ||
|
|
||
| concurrency: | ||
| group: helm-release | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| detect-chart-version: | ||
|
spencercjh marked this conversation as resolved.
|
||
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| version_changed: ${{ steps.compare.outputs.version_changed }} | ||
| previous_version: ${{ steps.compare.outputs.previous_version }} | ||
| current_version: ${{ steps.compare.outputs.current_version }} | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Compare chart version | ||
| id: compare | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| before_sha="${{ github.event.before }}" | ||
| if [[ -z "${before_sha}" || "${before_sha}" == "0000000000000000000000000000000000000000" ]]; then | ||
| echo "github.event.before is not available for this push" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| current_version="$(awk '$1 == "version:" { print $2; exit }' "${{ env.CHART_PATH }}/Chart.yaml")" | ||
| if [[ -z "${current_version}" ]]; then | ||
| echo "failed to resolve current chart version from ${{ env.CHART_PATH }}/Chart.yaml" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if git cat-file -e "${before_sha}:${{ env.CHART_PATH }}/Chart.yaml" 2>/dev/null; then | ||
| previous_version="$(git show "${before_sha}:${{ env.CHART_PATH }}/Chart.yaml" | awk '$1 == "version:" { print $2; exit }')" | ||
| else | ||
| previous_version="" | ||
| fi | ||
|
|
||
| if [[ -z "${previous_version}" || "${previous_version}" != "${current_version}" ]]; then | ||
| version_changed=true | ||
| else | ||
| version_changed=false | ||
| fi | ||
|
|
||
| { | ||
| echo "previous_version=${previous_version}" | ||
| echo "current_version=${current_version}" | ||
| echo "version_changed=${version_changed}" | ||
| } >>"$GITHUB_OUTPUT" | ||
|
|
||
| helm-release: | ||
| needs: | ||
| - detect-chart-version | ||
| if: >- | ||
| always() && | ||
| (github.event_name == 'workflow_dispatch' || | ||
| startsWith(github.ref, 'refs/tags/') || | ||
| needs.detect-chart-version.outputs.version_changed == 'true') | ||
| permissions: | ||
| contents: write | ||
| packages: write | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Configure Git | ||
| run: | | ||
| git config user.name "$GITHUB_ACTOR" | ||
| git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | ||
|
|
||
| - name: Ensure gh-pages branch exists | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then | ||
| echo "origin/gh-pages already exists" | ||
| exit 0 | ||
| fi | ||
|
|
||
| workdir="$(mktemp -d)" | ||
| git worktree add --detach "${workdir}" HEAD | ||
|
|
||
| pushd "${workdir}" | ||
| git switch --orphan gh-pages | ||
| git rm -rf . >/dev/null 2>&1 || true | ||
| touch .nojekyll | ||
| git add .nojekyll | ||
| git commit -m "chore: initialize gh-pages branch" | ||
| git push origin gh-pages | ||
| popd | ||
|
|
||
| git worktree remove --force "${workdir}" | ||
| git fetch origin gh-pages | ||
|
|
||
| - name: Set up Helm | ||
| uses: azure/setup-helm@v5.0.0 | ||
| with: | ||
| version: ${{ env.HELM_VERSION }} | ||
|
|
||
| - name: Package Helm chart | ||
| run: | | ||
| mkdir -p .cr-release-packages | ||
| helm package "${{ env.CHART_PATH }}" --destination .cr-release-packages | ||
|
|
||
| - name: Run chart-releaser | ||
| uses: helm/chart-releaser-action@v1.6.0 | ||
| with: | ||
| charts_dir: charts | ||
| skip_existing: true | ||
| skip_packaging: true | ||
| env: | ||
| CR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Publish Helm chart to GHCR | ||
| shell: bash | ||
| env: | ||
| GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| namespace="${GITHUB_REPOSITORY_OWNER,,}" | ||
| chart_version="$(awk '$1 == "version:" { print $2; exit }' "${{ env.CHART_PATH }}/Chart.yaml")" | ||
| package_path=".cr-release-packages/${{ env.CHART_NAME }}-${chart_version}.tgz" | ||
|
|
||
| if [[ -z "${chart_version}" || ! -f "${package_path}" ]]; then | ||
| echo "failed to resolve packaged chart for ${{ env.CHART_NAME }}" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "${GHCR_TOKEN}" | helm registry login ghcr.io --username "${GITHUB_ACTOR}" --password-stdin | ||
| chart_ref="oci://ghcr.io/${namespace}/charts/${{ env.CHART_NAME }}" | ||
| lookup_error="$(mktemp)" | ||
|
|
||
| if helm show chart "${chart_ref}" --version "${chart_version}" >/dev/null 2>"${lookup_error}"; then | ||
| echo "${chart_ref}:${chart_version} already exists; skipping GHCR push" | ||
| exit 0 | ||
| fi | ||
|
|
||
| if ! grep -Eqi 'not found|manifest unknown' "${lookup_error}"; then | ||
| echo "failed to query ${chart_ref}:${chart_version}" >&2 | ||
| cat "${lookup_error}" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| helm push "${package_path}" "oci://ghcr.io/${namespace}/charts" | ||
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,85 @@ | ||
| name: Helm Lint | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - main | ||
|
|
||
| env: | ||
| HELM_VERSION: "v3.20.0" | ||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: read | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| changes: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| helm: ${{ steps.filter.outputs.helm }} | ||
| steps: | ||
| - name: Detect Helm changes | ||
| uses: dorny/paths-filter@v4 | ||
| id: filter | ||
| with: | ||
| filters: | | ||
| helm: | ||
| - 'charts/ascend-device-plugin/**' | ||
| - 'Makefile' | ||
| - '.github/workflows/helm-lint.yaml' | ||
| - '.github/workflows/build-helm-release.yaml' | ||
|
|
||
| lint-test: | ||
| runs-on: ubuntu-latest | ||
| needs: changes | ||
| if: needs.changes.outputs.helm == 'true' | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
|
spencercjh marked this conversation as resolved.
|
||
|
|
||
| - name: Set up Helm | ||
| uses: azure/setup-helm@v5.0.0 | ||
| with: | ||
| version: ${{ env.HELM_VERSION }} | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version-file: go.mod | ||
|
|
||
| - name: Set up helm-docs | ||
| uses: gabe565/setup-helm-docs-action@v1 | ||
| with: | ||
| version: v1.14.2 | ||
|
|
||
| - name: Run Helm chart verification | ||
| run: make verify-helm-chart | ||
|
|
||
| helm-lint-required: | ||
| runs-on: ubuntu-latest | ||
| needs: | ||
| - changes | ||
| - lint-test | ||
| if: always() | ||
| steps: | ||
| - name: Check Helm workflow result | ||
| shell: bash | ||
| run: | | ||
| if [[ "${{ needs.changes.result }}" != "success" ]]; then | ||
| echo "Helm change detection did not complete successfully: ${{ needs.changes.result }}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ "${{ needs.changes.outputs.helm }}" != "true" ]]; then | ||
| echo "No Helm-relevant changes." | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "${{ needs.lint-test.result }}" != "success" ]]; then | ||
| echo "Helm verification did not complete successfully: ${{ needs.lint-test.result }}" | ||
| exit 1 | ||
| fi | ||
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,75 @@ | ||
| ### Linux template | ||
| *~ | ||
|
|
||
| # temporary files which can be created if a process still has a handle open of a deleted file | ||
| .fuse_hidden* | ||
|
|
||
| # KDE directory preferences | ||
| .directory | ||
|
|
||
| # Linux trash folder which might appear on any partition or disk | ||
| .Trash-* | ||
|
|
||
| # .nfs files are created when an open file is removed but is still being accessed | ||
| .nfs* | ||
|
|
||
| ### Go template | ||
| # If you prefer the allow list template instead of the deny list, see community template: | ||
| # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore | ||
| # | ||
| # Binaries for programs and plugins | ||
| *.exe | ||
| *.exe~ | ||
| *.dll | ||
| *.so | ||
| *.dylib | ||
|
|
||
| # Test binary, built with `go test -c` | ||
| *.test | ||
|
|
||
| # Output of the go coverage tool, specifically when used with LiteIDE | ||
| *.out | ||
|
|
||
| # Dependency directories (remove the comment below to include it) | ||
| # vendor/ | ||
|
|
||
| # Go workspace file | ||
| go.work | ||
| go.work.sum | ||
|
|
||
| # env file | ||
| .env | ||
|
|
||
| ### macOS template | ||
| # General | ||
| .DS_Store | ||
| .AppleDouble | ||
| .LSOverride | ||
|
|
||
| # Icon must end with two \r | ||
| Icon | ||
|
|
||
| # Thumbnails | ||
| ._* | ||
|
|
||
| # Files that might appear in the root of a volume | ||
| .DocumentRevisions-V100 | ||
| .fseventsd | ||
| .Spotlight-V100 | ||
| .TemporaryItems | ||
| .Trashes | ||
| .VolumeIcon.icns | ||
| .com.apple.timemachine.donotpresent | ||
|
|
||
| # Directories potentially created on remote AFP share | ||
| .AppleDB | ||
| .AppleDesktop | ||
| Network Trash Folder | ||
| Temporary Items | ||
| .apdisk | ||
|
|
||
|
|
||
| ### Custom | ||
| .idea/ | ||
| .vscode/ | ||
| .worktree/ |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
release the chart if a new tag created
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented
v*tag-triggered releases inaa8cc74.One warning is that repository tags and
Chart.yaml.versionare independent, so a new repository tag may point to a chart version already published by an earliermainbranch version bump. The workflow therefore treats chart artifacts as immutable: chart-releaser usesskip_existing, and GHCR checks the exact OCI chart version before pushing. Existing versions are skipped instead of overwritten; publishing new chart content still requires updatingChart.yaml.version.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we modify this version via parameters during helm packaging?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theoretically, of course, it’s possible, but I think that when someone modifies the contents of a chart and wants to publish it for others to use, they should explicitly update the version in
Chart.yaml. When templates change frequently, it’s perfectly normal for the patch version in the chart version to be very high. Of course, the maintainer can require restrictions on version increments and decide for themselves what the chart version should be.I think implementing version updates by passing the version number into a GitHub workflow would make the whole process quite complicated. We’d have to modify the file first, commit and push it, and then perform the Helm packaging and release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean that the chart version should be independent from the entire project?
Getting the tag version in the workflow isn't complicated. Also, creating a new tag already means releasing a new version. If we require the release owner to update the version manually, it's easy to forget and end up with inconsistent version information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the chart version can be independent from the application or repository version. However, I am not insisting that this project must use independent versioning. If the maintainers prefer to keep the repository tag,
appVersion, and chartversionaligned, that is a valid project policy.I also agree that relying entirely on the release owner to remember updating
Chart.yamlis error-prone. My concern is only that silently overriding the chart version during packaging may create a difference between the checked-inChart.yamland the published artifact.I think CI validation would solve the problem more clearly.
For example, on a
v1.3.1tag, the workflow could verify that:If they do not match, the release should fail with a clear error asking the release owner to update
Chart.yaml.This gives us both properties:
In other words, automation should prevent an inconsistent release, rather than silently changing the version of the packaged artifact.
If the project later needs to publish a chart-only fix without releasing a new application version, we can reconsider independent chart versioning at that point. But that is a separate versioning-policy decision.
The issue regarding chart versions has actually already come to light in HAMi. HAMi’s charts are already quite complex, and when we discover bugs in chart templates or default values, there’s currently no way to release a quick fix because it must be tied to the entire HAMi release. This causes users to miss out on many minor chart fixes, forcing them to fork the source code and release their own charts.
In the real world, there are numerous well-known open-source projects that use independent chart versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The chart version is part of the source and release metadata. Choosing and updating it correctly is one of the responsibilities of maintaining and releasing the chart, just like updating release notes or documenting compatibility changes. The maintainer should still decide whether a chart change requires a patch, minor, or major version bump.
Automation can help us enforce that responsibility. For example, CI can fail when a release tag is created but the expected fields in Chart.yaml were not updated. However, that validation should be a guardrail, not a replacement for maintaining the version correctly.
Automatically injecting the Git tag during packaging may prevent one kind of mistake, but it also hides the fact that the version recorded in the repository is stale. It makes the published artifact differ from the checked-in source and treats the symptom rather than fixing the release process.
So I would separate these two questions:
Should this project keep the chart version aligned with the application version?
That is a valid project policy.
How should we prevent maintainers from forgetting to update the version?
CI should detect the inconsistency and fail the release.
Regardless of whether the two versions are aligned or independent, correctly maintaining the chart version is something we should do properly, rather than something we should avoid through packaging-time overrides.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll open an issue on HAMi in a few days to elaborate on the above points again.