From df46c9e06142a61cd2942f66ab039e1b0fe45915 Mon Sep 17 00:00:00 2001 From: Chris Fordham Date: Tue, 25 Aug 2026 12:24:10 +1000 Subject: [PATCH 1/3] fix(ci): pass release notes by file, not shell interpolation [main] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first real release published notes with every `code span` and the fenced code block silently removed: `${{ steps.notes.outputs.body }}` interpolates the text into the shell script, so bash treats the backticks as command substitution and executes them. The preamble is already on disk, so use --notes-file and drop the GITHUB_OUTPUT round-trip. The generator itself was correct — the dry-run summaries rendered properly, which isolated the fault to the publishing step. Same fix applied across all five repositories. --- .github/workflows/release.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ec451f0..d99d32d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -66,11 +66,6 @@ jobs: --from "$(git describe --tags --abbrev=0)" \ --to HEAD > /tmp/preamble.md cat /tmp/preamble.md - { - echo 'body<> "$GITHUB_OUTPUT" - name: Summary run: | @@ -94,9 +89,13 @@ jobs: # --generate-notes appends the categorised commit list, grouped per # .github/release.yml, beneath our preamble. + # + # --notes-file, not --notes "${{ ... }}": interpolating the body into the + # shell makes bash treat its backticks as command substitution, which + # silently ate every `code span` and the fenced block. gh release create "$VERSION" \ --title "$VERSION" \ - --notes "${{ steps.notes.outputs.body }}" \ + --notes-file /tmp/preamble.md \ --generate-notes \ --verify-tag From bc77a9b80587f3ea8bcb004b8184cbda2439bee0 Mon Sep 17 00:00:00 2001 From: Chris Fordham Date: Tue, 25 Aug 2026 12:38:17 +1000 Subject: [PATCH 2/3] fix(ci): dispatch the image build after tagging [main] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first real release tagged v0.2.1 but published no versioned image. A tag pushed with GITHUB_TOKEN does not trigger other workflows — GitHub suppresses that to prevent recursion — so docker.yml never fired despite its `tags: ["v*"]` trigger. That matters beyond the missing tag: kube-workspaces/deploy's release workflow refuses to release unless a matching image exists for all four components, so the whole chain would stall. Dispatch the build explicitly once the release is created. The v0.2.1 images were built by hand; from v0.2.2 onward this is unattended. --- .github/workflows/release.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d99d32d..3e792bc 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -99,6 +99,20 @@ jobs: --generate-notes \ --verify-tag + # A tag pushed with GITHUB_TOKEN does not trigger other workflows — + # GitHub suppresses that to prevent recursion. So the image build has to be + # dispatched explicitly, or the release would have no versioned image and + # kube-workspaces/deploy would refuse to release against it. + - name: Build the release image + if: ${{ !inputs.dry_run }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + run: | + set -euo pipefail + gh workflow run docker.yml --ref "$VERSION" + echo "::notice::dispatched the image build for $VERSION" + - name: Dry run notice if: ${{ inputs.dry_run }} run: | From fe39ebf7e50f8fc306bb548e4ee8342134eb0c1b Mon Sep 17 00:00:00 2001 From: Chris Fordham Date: Tue, 25 Aug 2026 12:53:13 +1000 Subject: [PATCH 3/3] fix(ci): remove a literal expression from a comment [main] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Actions evaluates expressions everywhere in a workflow file, including inside comments. The placeholder in the previous commit's explanatory comment was not valid expression syntax, so the file failed to parse and the workflow became undispatchable — it registered by filename rather than by name. Caught in kube-workspaces/deploy before this branch merged. --- .github/workflows/release.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3e792bc..9402540 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -90,9 +90,11 @@ jobs: # --generate-notes appends the categorised commit list, grouped per # .github/release.yml, beneath our preamble. # - # --notes-file, not --notes "${{ ... }}": interpolating the body into the - # shell makes bash treat its backticks as command substitution, which - # silently ate every `code span` and the fenced block. + # Use --notes-file rather than passing the body through a GitHub + # expression: interpolating it into the shell makes bash treat its + # backticks as command substitution, which silently ate every code span + # and the fenced block. (A literal expression cannot appear even in a + # comment here — Actions evaluates it and fails to parse the file.) gh release create "$VERSION" \ --title "$VERSION" \ --notes-file /tmp/preamble.md \