Announce #7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Announce: posts an already-published release to the Discord #releases channel. Manually | |
| # dispatched, never automatic — the dispatch IS the maintainer's approval, given only after | |
| # they have personally verified the published release (the workflow succeeded, repo.json | |
| # serves the new version, the asset URL answers, the in-game update works). Running this is | |
| # the release process's very last step, so a broken or half-published release can never | |
| # announce itself. | |
| # | |
| # Deliberately a separate workflow rather than an approval-gated job inside release.yml: a | |
| # waiting job sits on the release run inviting an approve-to-clear-the-queue click, while a | |
| # dispatch requires the maintainer to come back and actively say "announce it". | |
| # | |
| # Re-running posts a SECOND Discord message (webhooks are not idempotent) — re-run only when | |
| # the previous run failed without posting anything. | |
| name: Announce | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Published release tag to announce (vX.Y.Z)" | |
| required: true | |
| type: string | |
| jobs: | |
| announce: | |
| runs-on: ubuntu-latest | |
| # Reading the release needs only the default read scope; this workflow never writes to | |
| # the repository. | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| shell: pwsh | |
| steps: | |
| # Checked out at the dispatched ref (main, normally), NOT the release's tag: release | |
| # tags are immutable, so a tag checkout would forever run whatever announcement script | |
| # existed at release time — a script fix landed on main could never reach it. The | |
| # screenshots still match the release, because per-release folders | |
| # (images/releases/<tag>/) are committed on main and stay there. | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| # The interlock this workflow exists for: only a genuinely published release can be | |
| # announced. A missing or draft release fails here, loudly, and nothing reaches | |
| # Discord. | |
| - name: Verify the release is published | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ inputs.tag }} | |
| run: | | |
| if ($env:TAG -notmatch '^v\d+\.\d+\.\d+$') { | |
| throw "Input '$($env:TAG)' is not a release tag (expected vMAJOR.MINOR.PATCH)." | |
| } | |
| # Captured before parsing so a missing release reports itself rather than | |
| # surfacing as a JSON parse error on empty output. | |
| $json = gh release view $env:TAG --json isDraft 2>$null | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "No GitHub Release exists for $($env:TAG); publish it (push the tag) first." | |
| } | |
| $release = $json | ConvertFrom-Json | |
| if ($release.isDraft) { | |
| throw "The $($env:TAG) release is still a draft; publish it before announcing." | |
| } | |
| # The release's fields are read back from the GitHub API and cross into the Node | |
| # script as environment variables — the body is arbitrary changelog markdown and must | |
| # never be interpolated into script text. No continue-on-error: this run's only job | |
| # is the announcement, so a Discord failure should fail the run visibly. | |
| - name: Announce the release on Discord | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| DISCORD_RELEASES_WEBHOOK_URL: ${{ secrets.DISCORD_RELEASES_WEBHOOK_URL }} | |
| TAG: ${{ inputs.tag }} | |
| run: | | |
| $release = gh release view $env:TAG --json name,body,url | ConvertFrom-Json | |
| $env:RELEASE_NAME = $release.name | |
| $env:RELEASE_BODY = $release.body | |
| $env:RELEASE_URL = $release.url | |
| $env:RELEASE_TAG = $env:TAG | |
| node .github/scripts/post-discord-release.mjs |