From c3b93f0127eddfe849255098bfca8fa2fb4a5d00 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Sun, 26 Jul 2026 13:35:04 +0100 Subject: [PATCH 1/2] fix(ci): trigger the plugin release on workflow_run, link bundles in the notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.3.0 published with no plugin bundles attached. The workflow triggered on `release: published`, but GitHub refuses to start workflows from events created with the default GITHUB_TOKEN — and dist's `host` job creates the release with exactly that token, so the event never fired. The bundles had to be dispatched by hand. Tag push is not the alternative: it races dist and 404s on every upload for the ~8 minutes dist spends building. workflow_run fires on the Release workflow completing, by which point the release object exists, and `head_branch` carries the tag name. Guarded on a successful run from a tag push, since Release also runs on pull_request. Also appends a plugin download table to the release notes. dist writes the body and only knows what it built, so its table lists the standalone alone and the plugin zips sit in Assets with nothing pointing at them. Keyed on an HTML marker so re-dispatching does not stack up tables. --- .github/workflows/plugin-release.yml | 73 ++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/.github/workflows/plugin-release.yml b/.github/workflows/plugin-release.yml index c0de420..3d867f4 100644 --- a/.github/workflows/plugin-release.yml +++ b/.github/workflows/plugin-release.yml @@ -1,19 +1,28 @@ # Builds the CLAP + VST3 plugin bundles and attaches them to an existing GitHub # release. # -# NOTE: this deliberately triggers on `release: published`, NOT on tag push. -# cargo-dist's own `release.yml` is what calls `gh release create`; a workflow -# triggered by the same tag push would race it and fail every upload with a 404 -# because the release does not exist yet. Waiting for `published` guarantees the -# release object is there before we upload to it. +# TRIGGER: this waits for cargo-dist's `Release` workflow to finish, because the +# release object must exist before anything can be uploaded to it. +# +# It does NOT trigger on `release: published`, even though that reads like the +# obvious choice. GitHub refuses to start workflows from events created with the +# default GITHUB_TOKEN (a deliberate guard against recursive runs), and dist's +# `host` job creates the release with exactly that token — so a `release: +# published` trigger never fires at all. v0.3.0 shipped with no plugin bundles +# because of this and had to be dispatched by hand. +# +# Triggering on tag push instead would race dist and 404 on every upload, since +# the release does not exist for the ~8 minutes dist spends building. workflow_run +# avoids both problems: it fires on completion, and `head_branch` carries the tag. # # Do not fold this into `.github/workflows/release.yml` — that file is generated # by `dist init` and hand edits are destroyed on regeneration. name: Plugin Release on: - release: - types: [published] + workflow_run: + workflows: ["Release"] + types: [completed] workflow_dispatch: inputs: tag: @@ -25,12 +34,20 @@ permissions: contents: write env: - # `github.event.release.tag_name` is unset for workflow_dispatch runs. - RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }} + # For workflow_run, `head_branch` is the ref that started the upstream run — + # the tag name for a tag push. Unset for workflow_dispatch, which passes `tag`. + RELEASE_TAG: ${{ github.event.workflow_run.head_branch || inputs.tag }} jobs: bundle: name: Bundle plugin (${{ matrix.label }}) + # `Release` also runs on pull_request, and those completions raise + # workflow_run too. Only act on a successful run that came from a tag push. + if: >- + github.event_name == 'workflow_dispatch' || + (github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && + startsWith(github.event.workflow_run.head_branch, 'v')) runs-on: ${{ matrix.runner }} strategy: fail-fast: false @@ -126,3 +143,41 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh release upload "$RELEASE_TAG" "${{ matrix.asset }}" --clobber + + # dist writes the release body and only knows about what it built, so its + # download table lists the standalone alone. Without this the plugin zips are + # present in Assets but nothing in the notes points at them, which reads as + # "this release is standalone-only". + notes: + name: Add the plugin downloads to the release notes + needs: bundle + runs-on: ubuntu-latest + steps: + - name: Append plugin download table + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + body="$(gh release view "$RELEASE_TAG" --json body --jq '.body')" + + # Idempotent: re-dispatching this workflow must not stack up tables. + if printf '%s' "$body" | grep -qF ''; then + echo "Plugin download table already present; leaving the notes alone." + exit 0 + fi + + base="https://github.com/$GITHUB_REPOSITORY/releases/download/$RELEASE_TAG" + { + printf '%s\n\n' "$body" + printf '\n' + printf '## Download the VST3/CLAP plugin %s\n\n' "${RELEASE_TAG#v}" + printf '| File | Platform | Status |\n' + printf '|--------|----------|--------|\n' + printf '| [Rustortion-linux-x86_64.zip](%s/Rustortion-linux-x86_64.zip) | x64 Linux | Tested in a DAW |\n' "$base" + printf '| [Rustortion-linux-aarch64.zip](%s/Rustortion-linux-aarch64.zip) | ARM64 Linux | Built in CI, not hand-tested |\n' "$base" + printf '| [Rustortion-windows-x86_64.zip](%s/Rustortion-windows-x86_64.zip) | x64 Windows | Built in CI, not hand-tested |\n' "$base" + printf '\nEach archive contains both `Rustortion.clap` and `Rustortion.vst3`. ' + printf 'See the [README](https://github.com/%s#vst3clap-plugin) for install paths.\n' "$GITHUB_REPOSITORY" + } > release-notes.md + + gh release edit "$RELEASE_TAG" --notes-file release-notes.md From baff594b5a56fc8bf7a0fa2b9eba5e5432aca221 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Sun, 26 Jul 2026 13:42:13 +0100 Subject: [PATCH 2/2] fix(ci): set shell: bash on the Windows upload step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Windows bundle built and packaged fine but failed to upload with "release not found". The step had no explicit shell, so it ran under pwsh, where $RELEASE_TAG is not an env var reference — it expanded to an empty string and gh was asked to upload to a release named "". Introduced when the matrix gained Windows: shell: bash was added to the clean, verify and package steps but missed here. Every run step that reads a shell variable now names its shell explicitly. --- .github/workflows/plugin-release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/plugin-release.yml b/.github/workflows/plugin-release.yml index 3d867f4..8c4e91c 100644 --- a/.github/workflows/plugin-release.yml +++ b/.github/workflows/plugin-release.yml @@ -139,7 +139,11 @@ jobs: Compress-Archive -Path Rustortion.clap, Rustortion.vst3 ` -DestinationPath "$env:GITHUB_WORKSPACE\${{ matrix.asset }}" working-directory: target/bundled + # shell: bash is load-bearing on Windows. The default shell there is pwsh, + # which does not expand `$RELEASE_TAG` — it silently becomes an empty + # string and `gh release upload ""` fails with "release not found". - name: Upload to release + shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh release upload "$RELEASE_TAG" "${{ matrix.asset }}" --clobber