chart: publish from the tag only, not from both workflows

Two workflows published the chart and disagreed about its metadata.
release.yml stamps version and appVersion from the git tag;
chart-release.yml, triggered by any charts/** push to main, took
Chart.yaml verbatim, where appVersion is the hardcoded "latest".
Both fired for the same commit, both tried to publish the same chart
version, and skip_existing turned whichever lost into a no-op — so what
a release said about itself came down to which runner was quicker.

Chart 0.9.0 went out that way, reading appVersion "latest". Every
earlier release got the right answer by accident: Chart.yaml's version
lagged the published set, so chart-release.yml always collided with an
existing version and skipped, leaving release.yml to win uncontested.
Bumping Chart.yaml to match the tag before cutting 0.9.0 removed that
accident and the race showed itself.

Making the two agree is not possible. The tag is pushed after the branch,
so a workflow triggered by the main push cannot know the version it is
about to be tagged with — no amount of deriving from git describe fixes
that ordering. The fix is one publisher, triggered by the tag, so
chart-release.yml is deleted.

The chart now only ships with an app release. Nothing is lost: the sed in
release.yml ties the chart version to the app version, so a chart-only
change never had a version of its own to be released under. Chart fixes
ride the next tag.

Chart.yaml's version and appVersion are documented as the placeholders
they now are, so the next person does not helpfully bump them and
reintroduce this. skip_existing stays, for idempotent re-runs of a failed
release rather than for the race, and a non-version tag now fails the job
instead of silently publishing unstamped metadata.
This commit is contained in:
Niklas Ye
2026-08-08 21:41:44 +02:00
parent 14c24f8fda
commit 766f43931c
3 changed files with 32 additions and 42 deletions
-38
View File
@@ -1,38 +0,0 @@
name: Release Helm Chart
on:
push:
branches:
- main
paths:
- charts/**
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pages: write
steps:
- name: Checkout
uses: actions/checkout@v4
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: Install Helm
uses: azure/setup-helm@v4
- name: Run chart-releaser
uses: helm/chart-releaser-action@v1.6.0
with:
# A charts/** push without a Chart.yaml version bump would otherwise
# fail trying to re-release the current version. Tagged releases also
# publish the chart from release.yml, so the two can race.
skip_existing: true
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+27 -4
View File
@@ -112,18 +112,41 @@ jobs:
- name: Install Helm
uses: azure/setup-helm@v4
# This job is the only thing that publishes the chart, which is what keeps
# the published metadata honest. There used to be a second publisher --
# chart-release.yml, on every charts/** push to main -- and the two raced
# for the same chart version with different answers: this one stamps
# version and appVersion from the tag, that one took Chart.yaml verbatim,
# where appVersion is the hardcoded "latest". Whichever landed first won
# and skip_existing turned the loser into a no-op, so the metadata of a
# release depended on which runner was quicker. Chart 0.9.0 went out on
# 2026-08-08 reading appVersion "latest" that way.
#
# It could not be fixed by making both agree: the tag is pushed after the
# branch, so a workflow triggered by the main push cannot know the version
# it is about to be tagged with. One publisher, triggered by the tag.
#
# The cost is that the chart only ships with an app release. That is no
# real loss -- the sed below ties the chart version to the app version, so
# a chart-only change has no version of its own to be released under
# anyway. Chart fixes ride the next tag.
- name: Update chart versions
run: |
VERSION="${{ github.ref_name }}"
if [[ "$VERSION" =~ ^v[0-9] ]]; then
CHART_VERSION="${VERSION#v}"
sed -i "s/^version:.*/version: ${CHART_VERSION}/" charts/terdut-server/Chart.yaml
sed -i "s/^appVersion:.*/appVersion: \"${VERSION}\"/" charts/terdut-server/Chart.yaml
if [[ ! "$VERSION" =~ ^v[0-9] ]]; then
echo "::error::refusing to publish a chart for non-version tag ${VERSION}"
exit 1
fi
CHART_VERSION="${VERSION#v}"
sed -i "s/^version:.*/version: ${CHART_VERSION}/" charts/terdut-server/Chart.yaml
sed -i "s/^appVersion:.*/appVersion: \"${VERSION}\"/" charts/terdut-server/Chart.yaml
- name: Run chart-releaser
uses: helm/chart-releaser-action@v1.6.0
with:
# Keeps a re-run of a failed release idempotent rather than failing on
# the chart that already went out. It is no longer papering over a
# race -- see above.
skip_existing: true
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+5
View File
@@ -2,5 +2,10 @@ apiVersion: v2
name: terdut-server
description: A Helm chart for Terminal Duty — on-call alert management server
type: application
# These two are placeholders for a local `helm install ./charts/terdut-server`,
# not the released values. release.yml rewrites both from the git tag when it
# publishes, so the chart version always equals the app version. Bumping them by
# hand does nothing for a release and is not needed before tagging.
# "latest" is honest here: it matches image.tag in values.yaml.
version: 0.9.0
appVersion: "latest"