From 6da9071b8d887330a002f77d7a0fae4562fd6b18 Mon Sep 17 00:00:00 2001 From: Mathew Goldsborough <1759329+mgoldsborough@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:47:17 -1000 Subject: [PATCH 1/2] Tune Discord announce for synapse (drop reusable framing; add compare + footer) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per-product is the right call — a shared/reusable action across synapse/nimblebrain/mpak was premature abstraction. Make this synapse's own announce, optimized for a code-dense dev-SDK changelog. - Drop the "transport-agnostic / will move to a shared action" framing from the script; it's synapse-specific by design now. - Add a compare-diff link (Changelog vPrev…vCur) next to the release-notes link — computed from the previous published tag (omitted on first release). Devs want the diff. - Add an embed footer (`@nimblebrain/synapse`, the npm package) + the release timestamp, mirroring how a good release post anchors itself. - Keep the first-sentence teaser (right for synapse's pill-heavy notes) and the NimbleBrain Releases identity. --- .github/scripts/announce-discord.mjs | 55 +++++++++++++++++----------- .github/workflows/announce.yml | 8 +++- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/.github/scripts/announce-discord.mjs b/.github/scripts/announce-discord.mjs index 06d933c..77b150d 100644 --- a/.github/scripts/announce-discord.mjs +++ b/.github/scripts/announce-discord.mjs @@ -1,20 +1,25 @@ #!/usr/bin/env node -// Post a release announcement to a Discord webhook. Formats mechanically from -// the GitHub Release: title + the opening sentence(s) of the lead paragraph -// (the code-dense detail comes later, so the opener reads cleanly) + link. -// Transport-agnostic formatting lives here so it can move into a shared action -// verbatim when we extend to nimblebrain / mpak. +// Post a synapse release announcement to the NimbleBrain #announcements Discord +// webhook. Formats from the GitHub Release: a one-sentence teaser (synapse's +// CHANGELOG leads are code-dense, so the opening sentence reads far cleaner in +// Discord than the full body) plus links to the full notes and the compare diff. +// +// Synapse-specific by design — NOT a shared/reusable action. Other products get +// their own announce, tuned to their own changelog style. // // Env: -// WEBHOOK_URL Discord webhook. Empty/unset -> print payload + skip (never -// fails a release, so merging before the secret exists is safe). +// WEBHOOK_URL Discord webhook. Empty/unset -> print payload + skip (a release +// never fails on a missing secret). // REPO owner/name (GITHUB_REPOSITORY). -// RELEASE_JSON path to `gh release view ... --json tagName,name,body,url`. +// RELEASE_JSON path to `gh release view ... --json tagName,name,body,url,publishedAt`. +// PREV_TAG previous release tag, for the compare link (optional). // DRY_RUN "true" -> print payload, don't POST. import { readFileSync } from "node:fs"; const webhook = (process.env.WEBHOOK_URL || "").trim(); -const repoName = (process.env.REPO || "").split("/").pop() || "release"; +const repo = process.env.REPO || "NimbleBrainInc/synapse"; +const repoName = repo.split("/").pop() || "synapse"; +const prevTag = (process.env.PREV_TAG || "").trim(); const dryRun = process.env.DRY_RUN === "true"; const rel = JSON.parse(readFileSync(process.env.RELEASE_JSON || "release.json", "utf8")); @@ -34,11 +39,9 @@ for (; i < lines.length; i++) { } const para = lead.join(" ").trim(); -// Teaser = the first sentence (plus the second only if the first is terse and -// they still fit). CHANGELOG leads open with prose; the inline-code-heavy detail -// comes later, so an opening sentence renders cleanly in Discord instead of a -// wall of code pills. Sentence boundaries are detected backtick-aware, so a `.` -// inside an identifier like `tokens.bgSubtle` is never a false split. +// Teaser = the first sentence (+ the second only if the first is terse and they +// still fit). Sentence boundaries are detected backtick-aware, so a `.` inside an +// identifier like `tokens.bgSubtle` is never a false split. function splitSentences(text) { let inCode = false; let start = 0; @@ -72,17 +75,27 @@ if (desc.length > CAP) { desc = `${desc.slice(0, cut > 0 ? cut : CAP).trimEnd()}…`; } if (!desc) { - // The parser found no prose lead under the version heading (e.g. a CHANGELOG - // that leads with `### Fixed`, or a manually-cut release using GitHub's - // auto-generated notes). Post a generic line but make the gap visible in the - // run log rather than silently shipping content-free copy. - console.log("::warning::No lead paragraph found in the release body — posting generic copy. Check the CHANGELOG format."); + console.log("::warning::No lead paragraph found in the release body — posting generic copy. Check CHANGELOG.md."); +} + +const links = [`[Full release notes →](${url})`]; +if (prevTag && tag) { + links.push(`[Changelog ${prevTag}…${tag} →](https://github.com/${repo}/compare/${prevTag}...${tag})`); } -const description = `${desc || "New release."}\n\n[Full release notes →](${url})`; +const description = `${desc || "New release."}\n\n${links.join("\n")}`; const payload = { username: "NimbleBrain Releases", - embeds: [{ title: `🚀 ${repoName} ${tag}`, url, description, color: 0x0055ff }], + embeds: [ + { + title: `🚀 ${repoName} ${tag}`, + url, + description, + color: 0x0055ff, // NimbleBrain brand blue + footer: { text: "@nimblebrain/synapse" }, + ...(rel.publishedAt ? { timestamp: rel.publishedAt } : {}), + }, + ], }; if (!webhook || dryRun) { diff --git a/.github/workflows/announce.yml b/.github/workflows/announce.yml index f7218bb..60cd5bd 100644 --- a/.github/workflows/announce.yml +++ b/.github/workflows/announce.yml @@ -41,12 +41,18 @@ jobs: TAG: ${{ github.event.release.tag_name || github.event.inputs.tag }} run: | gh release view "$TAG" --repo "$GITHUB_REPOSITORY" \ - --json tagName,name,body,url > release.json + --json tagName,name,body,url,publishedAt > release.json + # Previous release tag (newest non-current) for the compare link. + # Empty for the first release -> the script omits the compare link. + PREV=$(gh release list --repo "$GITHUB_REPOSITORY" --exclude-drafts \ + --json tagName --jq '.[].tagName' | grep -vxF "$TAG" | head -n1 || true) + echo "PREV_TAG=$PREV" >> "$GITHUB_ENV" - name: Announce to Discord env: WEBHOOK_URL: ${{ secrets.DISCORD_ANNOUNCE_WEBHOOK }} REPO: ${{ github.repository }} RELEASE_JSON: release.json + PREV_TAG: ${{ env.PREV_TAG }} DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} run: node .github/scripts/announce-discord.mjs From b2ac67eb600891b5777932bbd59c6cf0c697374b Mon Sep 17 00:00:00 2001 From: Mathew Goldsborough <1759329+mgoldsborough@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:00:54 -1000 Subject: [PATCH 2/2] Document single-track assumption in compare-link prev-tag logic QA flagged that the previous-tag selection (newest non-current published release) would produce a backwards compare link for an out-of-order backport. That can't happen on single-track synapse and fails only cosmetically, so this documents the assumption (and the sort -V escape hatch) rather than adding speculative robustness for a case that won't occur. --- .github/workflows/announce.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/announce.yml b/.github/workflows/announce.yml index 60cd5bd..8098b30 100644 --- a/.github/workflows/announce.yml +++ b/.github/workflows/announce.yml @@ -42,8 +42,12 @@ jobs: run: | gh release view "$TAG" --repo "$GITHUB_REPOSITORY" \ --json tagName,name,body,url,publishedAt > release.json - # Previous release tag (newest non-current) for the compare link. - # Empty for the first release -> the script omits the compare link. + # Previous release tag for the compare link: the newest non-current + # published release. Assumes single-track sequential releases (true for + # synapse — semver order matches publish order). A backport published + # after a higher version would yield a cosmetically backwards compare + # link; switch the pipe to `sort -V` if synapse ever ships out of order. + # Empty on the first release -> the script omits the compare link. PREV=$(gh release list --repo "$GITHUB_REPOSITORY" --exclude-drafts \ --json tagName --jq '.[].tagName' | grep -vxF "$TAG" | head -n1 || true) echo "PREV_TAG=$PREV" >> "$GITHUB_ENV"