Skip to content

Commit acba7aa

Browse files
waleedlatif1claude
andcommitted
improvement(helm): gate chart appVersion on the release PR, before the merge
The appVersion check only runs in the publish job on a push to main, so a release that forgets to bump it fails after the merge — and the chart for that release goes unpublished until someone bumps by hand. A release PR already knows the version it cuts: `vX.Y.Z:` in the title is exactly what detect-version turns into the tag, so the target is knowable up front and the assertion can be an equality rather than the lags-behind comparison the publish job is stuck with. Its own workflow, not a job in helm.yml, because paths filters apply per workflow and helm.yml only runs when chart files change — a release PR that forgets appVersion is very often one that touches no chart file at all. Also bumps appVersion to the current release and regenerates the image inventory, which embeds it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TknQyteeUDn6xi94sH71Y
1 parent 7aee676 commit acba7aa

4 files changed

Lines changed: 109 additions & 13 deletions

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Helm appVersion
2+
3+
# Pre-merge half of the appVersion gate. The post-merge half lives in the
4+
# publish job of helm.yml, which refuses to publish a chart whose appVersion
5+
# lags the latest release -- but it runs only on a push to main, so it can only
6+
# ever report the mistake after the release is already merged, with the chart
7+
# for that release left unpublished until someone bumps by hand.
8+
#
9+
# A release PR knows the version it is cutting before the merge: the main-branch
10+
# merge commit message is the PR title, and `vX.Y.Z:` in that message is exactly
11+
# what detect-version in ci.yml turns into the release tag. So on a release PR
12+
# the target is knowable up front and the check is an equality, not the
13+
# lags-behind comparison the publish job is stuck with.
14+
#
15+
# Deliberately its own workflow rather than a job in helm.yml: paths filters
16+
# apply per workflow, and helm.yml only runs when chart files change. A release
17+
# PR that forgets appVersion is very often a release PR that touches no chart
18+
# file at all, which is precisely the case that must not slip through.
19+
20+
on:
21+
pull_request:
22+
# `edited` matters as much as `synchronize`: the version being cut lives in
23+
# the PR title, so retitling a PR changes what this check asserts.
24+
types: [opened, edited, reopened, synchronize]
25+
branches: [main]
26+
27+
concurrency:
28+
group: helm-release-appversion-${{ github.event.pull_request.number }}
29+
cancel-in-progress: true
30+
31+
permissions:
32+
contents: read
33+
34+
jobs:
35+
appversion:
36+
name: Chart appVersion matches the release
37+
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }}
38+
timeout-minutes: 5
39+
steps:
40+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
41+
with:
42+
# Reads two files out of the merge commit; no history, no pushes.
43+
persist-credentials: false
44+
45+
- name: appVersion names the release this PR cuts
46+
env:
47+
# Never interpolated into the script body: a PR title is attacker-controlled text.
48+
PR_TITLE: ${{ github.event.pull_request.title }}
49+
run: |
50+
set -euo pipefail
51+
52+
# Same shape detect-version (ci.yml) matches on the merge commit. A PR
53+
# to main that is not a release -- a hotfix, a revert, a docs fix --
54+
# cuts no tag, so there is nothing for appVersion to name.
55+
if ! [[ "$PR_TITLE" =~ ^(v[0-9]+\.[0-9]+\.[0-9]+): ]]; then
56+
echo "::notice::\"${PR_TITLE}\" is not a release title (vX.Y.Z: ...); nothing to check."
57+
exit 0
58+
fi
59+
release="${BASH_REMATCH[1]}"
60+
61+
app_version=$(awk '/^appVersion:/ {print $2}' helm/sim/Chart.yaml | tr -d '"')
62+
chart_version=$(awk '/^version:/ {print $2}' helm/sim/Chart.yaml)
63+
64+
if [ "$app_version" = "$release" ]; then
65+
echo "::notice::Chart ${chart_version} ships appVersion ${app_version}, matching release ${release}."
66+
exit 0
67+
fi
68+
69+
# Equality, not "not behind". An appVersion ahead of the release being
70+
# cut names an image tag that this merge will not create either, so
71+
# the chart would install into ImagePullBackOff.
72+
echo "::error::helm/sim/Chart.yaml appVersion is ${app_version}, but this PR cuts ${release}. The chart defaults its image tags to appVersion, and published chart versions are immutable, so a stale value freezes an old Sim into the chart for ${release} forever."
73+
{
74+
echo "### Chart appVersion does not match this release"
75+
echo
76+
echo "| | |"
77+
echo "| --- | --- |"
78+
echo "| Release being cut | \`${release}\` |"
79+
echo "| \`Chart.yaml\` appVersion | \`${app_version}\` |"
80+
echo "| \`Chart.yaml\` version | \`${chart_version}\` |"
81+
echo
82+
echo "Fix it on this PR's head branch:"
83+
echo
84+
echo '```bash'
85+
echo "# 1. appVersion: \"${release}\" and a SemVer bump to version: in helm/sim/Chart.yaml"
86+
echo "# 2. the image inventory embeds appVersion, so regenerate it"
87+
echo "bun run images:generate"
88+
echo '```'
89+
} >> "$GITHUB_STEP_SUMMARY"
90+
exit 1

.github/workflows/helm.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,12 @@ jobs:
265265
# Compares against the latest GitHub release rather than a hardcoded value
266266
# so the check cannot go stale itself. Prereleases and drafts are excluded:
267267
# the `/releases/latest` endpoint already returns neither.
268+
#
269+
# This is the last line before an immutable push, not the first: it can
270+
# only run once the release exists, so it reports a stale appVersion after
271+
# the merge. `helm-release-appversion.yml` is the pre-merge half -- on a
272+
# release PR the version being cut is in the title, so it can assert
273+
# equality before anything is published.
268274
- name: appVersion does not lag the app release
269275
env:
270276
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

helm/sim/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ apiVersion: v2
22
name: sim
33
description: A Helm chart for Sim - the open-source AI workspace where teams build, deploy, and manage AI agents
44
type: application
5-
version: 1.11.1
6-
appVersion: "v0.8.24"
5+
version: 1.11.2
6+
appVersion: "v0.8.25"
77
kubeVersion: ">=1.25.0-0"
88
home: https://sim.ai
99
icon: https://raw.githubusercontent.com/simstudioai/sim/main/apps/sim/public/logo/primary/primary.svg

helm/sim/images.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,22 @@
2222
# render it twice. That override also CHANGES where the chart pulls from, to
2323
# `<your-registry>/nvidia/k8s-device-plugin` — mirror the device plugin there
2424
# instead of to the `mirror` path listed below, or the pull fails.
25-
appVersion: v0.8.24
25+
appVersion: v0.8.25
2626
images:
2727
- source: busybox:1.36
2828
mirror: busybox:1.36
2929
- source: curlimages/curl:8.5.0
3030
mirror: curlimages/curl:8.5.0
31-
- source: ghcr.io/simstudioai/copilot:v0.8.24
32-
mirror: simstudioai/copilot:v0.8.24
33-
- source: ghcr.io/simstudioai/migrations:v0.8.24
34-
mirror: simstudioai/migrations:v0.8.24
35-
- source: ghcr.io/simstudioai/pii:v0.8.24
36-
mirror: simstudioai/pii:v0.8.24
37-
- source: ghcr.io/simstudioai/realtime:v0.8.24
38-
mirror: simstudioai/realtime:v0.8.24
39-
- source: ghcr.io/simstudioai/simstudio:v0.8.24
40-
mirror: simstudioai/simstudio:v0.8.24
31+
- source: ghcr.io/simstudioai/copilot:v0.8.25
32+
mirror: simstudioai/copilot:v0.8.25
33+
- source: ghcr.io/simstudioai/migrations:v0.8.25
34+
mirror: simstudioai/migrations:v0.8.25
35+
- source: ghcr.io/simstudioai/pii:v0.8.25
36+
mirror: simstudioai/pii:v0.8.25
37+
- source: ghcr.io/simstudioai/realtime:v0.8.25
38+
mirror: simstudioai/realtime:v0.8.25
39+
- source: ghcr.io/simstudioai/simstudio:v0.8.25
40+
mirror: simstudioai/simstudio:v0.8.25
4141
- source: nvcr.io/nvidia/k8s-device-plugin:v0.18.2
4242
mirror: nvcr.io/nvidia/k8s-device-plugin:v0.18.2
4343
- source: ollama/ollama:0.23.2

0 commit comments

Comments
 (0)