From b8cf40ff5ac6d201d6629157a87f89110119c553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl?= Date: Fri, 26 Jun 2026 16:41:28 +0200 Subject: [PATCH] ci(desktop): enforce app version matches release tag --- .claude/skills/releasing-healthchat/SKILL.md | 48 ++++++++++++++++--- .../workflows/build-healthchat-desktop.yaml | 30 ++++++++++-- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/.claude/skills/releasing-healthchat/SKILL.md b/.claude/skills/releasing-healthchat/SKILL.md index 18331deed3..40177449c1 100644 --- a/.claude/skills/releasing-healthchat/SKILL.md +++ b/.claude/skills/releasing-healthchat/SKILL.md @@ -21,9 +21,15 @@ Releases are driven by git tags of the form `healthchat-v` pushed to Publish target: **ghcr.io Docker image + GitHub Release (web bundle + desktop installers).** No npm, no mobile fan-out. -The desktop app version is taken from `apps/desktop/package.json`, not the tag -(Windows squirrel rewrites any `version` override into a nightly string). Bump it -in the release commit if you want the About dialog / installer filenames to match. +The desktop app version is taken from `apps/desktop/package.json` (the per-job +`version` input cannot set it — Windows squirrel mangles it into a nightly string, +and on macOS/Linux it only feeds the update manifest). So `apps/desktop/package.json` +**must be bumped to the release version in the release commit** to keep the About +dialog and installer filenames matching the tag. This is no longer optional: the +desktop workflow's "Assert desktop app version matches release" step fails the build +if `apps/desktop/package.json` drifts from the tag's `MAJOR.MINOR.PATCH` (any +`-rc1`/`-hotfix1` suffix on the tag is ignored — squirrel needs a clean numeric +version, so set `1.4.0` even when tagging `healthchat-v1.4.0-rc1`). ## Preflight checklist @@ -33,14 +39,42 @@ Verify each item before tagging. If any fail, fix and commit first. - [ ] `HEALTHCHAT_CHANGES.md` has a section `## Changes in ()` at the top of the file. The pipeline's awk extractor matches this exact heading format. +- [ ] `apps/desktop/package.json` `version` is set to the release's + `MAJOR.MINOR.PATCH` (no suffix). **Required** — the desktop build asserts + this and fails otherwise. This is what the desktop apps report as their + version. - [ ] `.healthchat-workspace-version` points at the healthchat-workspace tag - or ref that should ship with this release. Bump it in the same commit - as the changelog entry if needed. -- [ ] `package.json` version can optionally be bumped to match (cosmetic — - the git tag is the source of truth for the build). + or ref that should ship with this release. **Ask the user** whether to bump + it to the latest plugin release or keep the currently pinned ref (see + "Choosing the plugin version" below). Commit any bump in the same commit as + the changelog entry. +- [ ] Root `package.json` version can optionally be bumped to match (cosmetic — + the web bundle version is injected from the tag at build time, and the git + tag is the source of truth for the build). - [ ] No uncommitted changes to `.github/workflows/build-healthchat.yaml`, `Dockerfile`, or `docker/` that haven't been manually sanity-checked. +## Choosing the plugin version + +The HealthChat plugin (healthchat-workspace) ref that ships with the release is +pinned in `.healthchat-workspace-version` (a single line, e.g. `v0.5.0-rc.4`). +Before tagging, **always ask the user** which they want: + +1. **Update to the latest plugin release** — check the available releases: + + ```bash + gh release list --repo Novaloop-AG/healthchat-workspace --limit 10 + ``` + + If they choose a newer ref, write it to `.healthchat-workspace-version` and + commit it alongside the changelog entry. +2. **Keep the currently pinned ref** — leave `.healthchat-workspace-version` + untouched (show them the current value so the choice is informed). + +Do not silently change the plugin ref; the user decides per release. The +`workspace_ref` workflow_dispatch input can override it for a one-off build +without committing, but the committed file is the source of truth for tag builds. + ## Cutting the release (normal path) ```bash diff --git a/.github/workflows/build-healthchat-desktop.yaml b/.github/workflows/build-healthchat-desktop.yaml index e162e2da0a..5c31047ca9 100644 --- a/.github/workflows/build-healthchat-desktop.yaml +++ b/.github/workflows/build-healthchat-desktop.yaml @@ -17,9 +17,13 @@ name: Build HealthChat Desktop # - macOS notarisation and Windows code-signing require the `Desktop Apple` / `Desktop eSigner` # GitHub environments (secrets/vars) to be configured. Without them the builds still run but # produce unsigned/untrusted output. See apps/desktop/element.io/healthchat/README. -# - The desktop app version comes from apps/desktop/package.json (electron-builder), NOT the tag -# (Windows squirrel rewrites any `version` override into a nightly string). Bump -# apps/desktop/package.json in the release commit if you want it to match the tag. +# - The desktop app version comes from apps/desktop/package.json (electron-builder); the per-job +# `version` input only feeds the macOS/Linux update manifest and is mangled into a nightly +# string by Windows squirrel, so it cannot set the app version. To keep the installers / About +# dialog in sync with the tag, apps/desktop/package.json must be bumped to the release version +# in the release commit. The "Assert desktop app version matches release" step below enforces +# this: the build fails fast if package.json drifts from the tag's MAJOR.MINOR.PATCH (any +# -rc1/-hotfix1 suffix is ignored, since squirrel requires a clean numeric version). on: push: @@ -28,7 +32,7 @@ on: workflow_dispatch: inputs: version: - description: "Version (e.g. 1.4.0). Used for the web bundle version; the desktop app version comes from apps/desktop/package.json." + description: "Version (e.g. 1.4.0). Drives the web bundle version and must match apps/desktop/package.json (MAJOR.MINOR.PATCH), which sets the desktop app version." required: true type: string workspace_ref: @@ -73,6 +77,24 @@ jobs: fi echo "version=$VERSION" >> "$GITHUB_OUTPUT" + # electron-builder bakes apps/desktop/package.json's version into the installers and the + # About dialog (the per-platform `version` input cannot override it). Fail fast if that + # file wasn't bumped to this release, so the desktop apps always match the tag. The + # comparison is on MAJOR.MINOR.PATCH only: tags may carry -rc1/-hotfix1 suffixes, but + # Windows squirrel needs package.json to stay a clean numeric version. + - name: Assert desktop app version matches release + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + set -euo pipefail + BASE=$(printf '%s' "$VERSION" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+') + PKG=$(jq -r .version apps/desktop/package.json) + if [[ "$PKG" != "$BASE" ]]; then + echo "::error::apps/desktop/package.json version ($PKG) does not match release $BASE (tag: $VERSION). Bump apps/desktop/package.json to $BASE in the release commit so the desktop installers and About dialog match the tag." + exit 1 + fi + echo "Desktop app version $PKG matches release $BASE" + - name: Resolve workspace ref id: workspace env: