ci(release): make the Discord announcement dispatchable on its own - #289
Conversation
📝 WalkthroughWalkthroughThe pull request adds a manually dispatched GitHub Actions workflow for Discord release announcements. The announcement script now supports strict failure reporting, with tests covering strict and non-strict execution. ChangesRelease announcement workflow
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
actor ReleaseOperator
participant GitHubActions
participant DiscordReleaseAnnounce
participant Discord
ReleaseOperator->>GitHubActions: Dispatch workflow with tag, kind, and extra text
GitHubActions->>DiscordReleaseAnnounce: Run with channel, tokens, release metadata, and STRICT=1
DiscordReleaseAnnounce->>Discord: Look up channel and post announcement
Discord-->>DiscordReleaseAnnounce: Return lookup or posting result
DiscordReleaseAnnounce-->>GitHubActions: Report success or workflow failure
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/announce-release.yml:
- Line 60: Update the announcement script invocation in the workflow and the
corresponding logic in discord-release-announce.mjs to support strict mode for
manual announcements. Enable strict mode from announce-release.yml, and ensure
missing Discord configuration, channel lookup failures, and post failures exit
with a non-zero status while preserving current behavior when strict mode is not
enabled.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2b72a33b-5ca6-48d5-bf53-2bc95d26de24
📒 Files selected for processing (1)
.github/workflows/announce-release.yml
Announcing a release only ever existed as the final step of prerelease.yml and promote.yml. Both promotions so far failed before reaching it — v1.8.0 on a merge conflict, v1.9.0 on a non-rebasable sync branch — and each time the announcement was skipped along with everything downstream of the failure. Recovering it meant re-running a promotion over an already-tagged release, which re-attempts tagging and the main merge; nobody was going to do that for a Discord post, so v1.9.0 simply shipped unannounced. This wraps the existing discord-release-announce.mjs in a workflow_dispatch and changes nothing else. The message is derived entirely from the tag and the matching milestone, so a late announcement is identical to the one that would have gone out on time. The destination is selected by blanking one of the two channel variables rather than by KIND, because that is what the script actually branches on: it prefers DISCORD_RC_TESTING_CHANNEL_ID whenever it is non-empty.
discord-release-announce.mjs exits 0 on four paths that never announce: no STABLE_TAG, missing bot token or channel id, a failed channel lookup, and a failed post. That is correct for prerelease.yml and promote.yml — the release is already published there, the announcement is bookkeeping, and failing the job would misreport a successful release. A manual dispatch has the opposite contract. This workflow exists *because* an announcement was missed, so a green run that posted nothing recreates the exact failure it was invoked to repair — which is how v1.9.0 shipped unannounced. STRICT, set only by announce-release.yml, makes those four paths exit non-zero via setFailed. Default behaviour is unchanged, and the existing suite still passes untouched. The catch deliberately does not route through bail(): it is the last statement, and 'handles 4xx gracefully without throwing' pins that the module finishes on its own rather than calling process.exit. Five tests added, covering each strict path, the nominal announcement, and the non-strict case staying non-fatal.
d206fa2 to
a65d1e4
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/scripts/discord-release-announce.test.mjs (1)
202-205: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd strict-mode coverage for a missing
STABLE_TAG.The strict test set does not exercise the
bail("STABLE_TAG missing; skipping.")branch. Add a test that setsSTRICT: "1"and an emptySTABLE_TAG. AssertsetFailedreceives the missing-tag message.Proposed test
+ it("fails when the release tag is missing", async () => { + await expect( + loadScript({ ...BASE_ENV, STABLE_TAG: "", STRICT: "1", DISCORD_RELEASE_CHANNEL_ID: "123" }), + ).rejects.toThrow(exits1); + expect(vi.mocked(setFailed)).toHaveBeenCalledWith(expect.stringContaining("STABLE_TAG missing")); + }); + it("fails when the Discord configuration is missing", async () => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/scripts/discord-release-announce.test.mjs around lines 202 - 205, Add a strict-mode test alongside the existing missing Discord configuration test that invokes loadScript with STRICT set to "1" and an empty STABLE_TAG, then assert setFailed is called with the exact missing-tag message "STABLE_TAG missing; skipping.".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/scripts/discord-release-announce.test.mjs:
- Around line 202-205: Add a strict-mode test alongside the existing missing
Discord configuration test that invokes loadScript with STRICT set to "1" and an
empty STABLE_TAG, then assert setFailed is called with the exact missing-tag
message "STABLE_TAG missing; skipping.".
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2ac5edba-23e4-4eb6-951f-4a53226bb3ef
📒 Files selected for processing (3)
.github/scripts/discord-release-announce.mjs.github/scripts/discord-release-announce.test.mjs.github/workflows/announce-release.yml
|
Nitpick applied — the strict set covered three of the four |
|
Correction to my previous comment: this PR merged before that test landed, so the nitpick fix is not in |
Why
Announcing a release only ever existed as the last step of
prerelease.ymlandpromote.yml. Both promotions so far failed before reaching it:Merge release branch into mainfailed on merge conflictsThis branch can't be rebasedEach time the announcement was skipped along with everything downstream of the failure. Recovering it meant re-running a whole promotion over an already-tagged release — which re-attempts tagging and the main merge — so nobody was going to do that for a Discord post. v1.9.0 shipped unannounced.
What this does
Wraps the existing
.github/scripts/discord-release-announce.mjsin aworkflow_dispatch. No change to the script, and no change to either release workflow.The message is derived entirely from the tag and the matching milestone, so a late announcement is byte-identical to the one that would have gone out on time. That is what makes this safe to run after the fact rather than a reconstruction.
One non-obvious detail
The destination is chosen by blanking one of the two channel variables, not by the
KINDinput:because that is what the script actually branches on — it prefers
DISCORD_RC_TESTING_CHANNEL_IDwhenever it is non-empty, andKINDonly selects the embed's wording and colour. Setting both would post a "released" embed into the RC testing channel.After merging
That sends the announcement v1.9.0 never got. It is safe to re-run — the only consequence of a double dispatch is a duplicate post, and
allowed_mentionsis empty so nothing is pinged either way.Not addressed here
The reason promotions keep failing at the main-sync step is separate and still open:
mainand the release branch accumulate the same fixes under different SHAs, so GitHub's rebase-merge replays commits already present. Worth its own change — this PR only stops one recurring casualty of it.Summary by CodeRabbit
New Features
Bug Fixes
Tests