From 20d093219f085ec59390d7794ed645f29513b173 Mon Sep 17 00:00:00 2001 From: Ali Turki Date: Sun, 12 Jul 2026 21:37:49 +0800 Subject: [PATCH] fix(ci): create release before matrix to stop parallel jobs racing The three publish-tauri matrix jobs each ran tauri-action, which looks up the release by tag and creates it when absent. With no release present at the start, all three raced to create it: the first won and the others failed with a 422 already_exists, dropping their platform's assets. That is how v0.9.0 published with no macOS DMG and a latest.json missing the darwin targets. Add a create-release job that ensures the release exists before the matrix runs, so every publish-tauri job takes the find-existing-and-upload path instead of racing to create. The job is idempotent, so re-dispatching against an existing tag is a no-op. Immediate incremental publishing and the async-notarization flow are unchanged. --- .github/workflows/release.yml | 44 ++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7477f59..397b018 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,8 +57,50 @@ jobs: echo "tag=$TAG" >> "$GITHUB_OUTPUT" echo "macos_included=$MAC_IN" >> "$GITHUB_OUTPUT" - publish-tauri: + # Create the GitHub release once, up front. The publish-tauri matrix jobs + # run tauri-action in parallel; each looks up the release by tag and, when + # absent, creates it. With no release yet, all three raced to create it - + # the first won and the losers failed with "already_exists", dropping their + # platform's assets (this is how v0.9.0 shipped with no macOS DMG). Ensuring + # the release exists first makes every matrix job take the "found existing, + # upload" path instead. Idempotent, so a re-dispatch against an existing tag + # is a no-op. + create-release: needs: setup + runs-on: ubuntu-latest + permissions: + contents: write + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + TAG: ${{ needs.setup.outputs.tag }} + steps: + - name: Ensure release exists + run: | + set -euo pipefail + if gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; then + echo "Release $TAG already exists; nothing to do." + exit 0 + fi + NOTES=$(printf '%s\n' \ + 'See assets below to download and install.' \ + '' \ + 'Install via Homebrew:' \ + '```' \ + 'brew install --cask anbturki/tap/docsreader' \ + '```' \ + '' \ + 'Install via curl:' \ + '```' \ + 'curl -fsSL https://raw.githubusercontent.com/anbturki/docsreader/main/install.sh | bash' \ + '```') + gh release create "$TAG" \ + --repo "$REPO" \ + --title "DocsReader $TAG" \ + --notes "$NOTES" + + publish-tauri: + needs: [setup, create-release] permissions: contents: write strategy: