From c2f9ff6efb84bcf6957fed03027200ed3814f6f2 Mon Sep 17 00:00:00 2001 From: Eric Rasputin Date: Mon, 14 Sep 2026 21:23:34 +0530 Subject: [PATCH 1/2] Bundle changelog entries for automatic fork versions --- .github/workflows/fork-release.yml | 4 ++ docs/fork-updates.md | 3 ++ scripts/fork-release.mjs | 63 +++++++++++++++++++++++++++++- scripts/fork-release.test.mjs | 23 ++++++++++- 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml index df4e2ca4..2349593e 100644 --- a/.github/workflows/fork-release.yml +++ b/.github/workflows/fork-release.yml @@ -26,6 +26,8 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: 20 @@ -37,6 +39,8 @@ jobs: with: key: fork-${{ matrix.target }} - run: npm ci + - name: Bundle fork release notes + run: node scripts/fork-release.mjs prepare "$FORK_VERSION" - name: Build and sign fork update env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.updater-private-key }} diff --git a/docs/fork-updates.md b/docs/fork-updates.md index 63368397..79fbbe1a 100644 --- a/docs/fork-updates.md +++ b/docs/fork-updates.md @@ -28,6 +28,9 @@ or agent request is needed after merging a change. `package.json`, Cargo, and the base Tauri config; the fork config overrides it. - Release tags use `fork-v0.2.`, so upstream `v*` tags stay separate. - Both `darwin-aarch64` and `darwin-x86_64` packages must finish successfully. +- Packaging adds a changelog section for the fork version from changes on main + since the previous fork release, so the post-update **What's new** view works. + This generated section is bundled in the app without committing version bumps. - The workflow checks bundle identity, version, architecture, and code signature. It stages a DMG, signed `.app.tar.gz`, and signature for each architecture. - A single publisher validates artifact hashes and commit/version consistency, diff --git a/scripts/fork-release.mjs b/scripts/fork-release.mjs index a5c769fa..1a47ba2f 100644 --- a/scripts/fork-release.mjs +++ b/scripts/fork-release.mjs @@ -42,6 +42,64 @@ function gitSha() { }).trim(); } +export function forkChangelogSection(version, messages, upstreamVersion, date) { + releaseTag(version); + const entries = messages.map((message) => { + const paragraphs = message.trim().split(/\n\s*\n/); + const title = + /^Merge /.test(paragraphs[0]) && paragraphs[1] + ? paragraphs[1].split("\n")[0] + : paragraphs[0].split("\n")[0]; + return `- ${title}`; + }); + return `## [${version}] - ${date}\n\nBased on upstream MonoCode ${upstreamVersion}.\n\n${entries.join("\n")}\n\n[Full release notes](https://github.com/${repository}/releases/tag/${releaseTag(version)})\n`; +} + +function prepare(version) { + releaseTag(version); + let previous; + try { + previous = execFileSync( + "git", + [ + "describe", + "--tags", + "--first-parent", + "--match", + "fork-v0.2.*", + "--abbrev=0", + "HEAD^", + ], + { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }, + ).trim(); + } catch { + // The first release has no preceding fork tag; show recent main changes. + } + const args = ["log", "--first-parent", "--format=%B%x00"]; + if (previous) args.push(`${previous}..HEAD`); + else args.push("-10"); + const messages = execFileSync("git", args, { encoding: "utf8" }) + .split("\0") + .map((message) => message.trim()) + .filter(Boolean); + const section = forkChangelogSection( + version, + messages, + json("package.json").version, + new Date().toISOString().slice(0, 10), + ); + const changelog = readFileSync("CHANGELOG.md", "utf8"); + writeFileSync( + "CHANGELOG.md", + changelog.replace(/^(# [^\n]+\n)/, `$1\n${section}\n`), + ); + if (!readFileSync("CHANGELOG.md", "utf8").includes(`## [${version}]`)) { + throw new Error( + "Could not add fork release notes to the bundled changelog", + ); + } +} + export function stage(version, target, root = process.cwd()) { releaseTag(version); const platform = platforms[target]; @@ -243,10 +301,11 @@ if ( resolve(process.argv[1]) === fileURLToPath(import.meta.url) ) { const [command, version, target] = process.argv.slice(2); - if (command === "stage") stage(version, target); + if (command === "prepare") prepare(version); + else if (command === "stage") stage(version, target); else if (command === "publish") publish(version); else throw new Error( - "Usage: node scripts/fork-release.mjs [target]", + "Usage: node scripts/fork-release.mjs [target]", ); } diff --git a/scripts/fork-release.test.mjs b/scripts/fork-release.test.mjs index e9a5e4bc..a2e312c4 100644 --- a/scripts/fork-release.test.mjs +++ b/scripts/fork-release.test.mjs @@ -4,7 +4,28 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { test } from "node:test"; import assert from "node:assert/strict"; -import { manifest, shouldPublish } from "./fork-release.mjs"; +import { + forkChangelogSection, + manifest, + shouldPublish, +} from "./fork-release.mjs"; + +test("bundled notes use the fork version and human-readable merge titles", () => { + const section = forkChangelogSection( + "0.2.7", + [ + "Merge pull request #8 from owner/updates\n\nEnable in-app updates", + "Fix session recovery\n\nPreserve archived conversations.", + ], + "0.1.46", + "2026-09-14", + ); + assert.match(section, /^## \[0\.2\.7\] - 2026-09-14\n/m); + assert.match(section, /- Enable in-app updates\n- Fix session recovery/); + assert.match(section, /upstream MonoCode 0\.1\.46/); + assert.ok(!section.includes("Merge pull request")); + assert.match(section, /releases\/tag\/fork-v0\.2\.7/); +}); function fixture(t) { const dir = mkdtempSync(join(tmpdir(), "fork-release-test-")); From 69fbf133c7891fbf722136aa00ba92f5dce86bfc Mon Sep 17 00:00:00 2001 From: Eric Rasputin Date: Mon, 14 Sep 2026 21:24:11 +0530 Subject: [PATCH 2/2] Preserve literal commit text when inserting release notes --- scripts/fork-release.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fork-release.mjs b/scripts/fork-release.mjs index 1a47ba2f..9c35e44f 100644 --- a/scripts/fork-release.mjs +++ b/scripts/fork-release.mjs @@ -91,7 +91,7 @@ function prepare(version) { const changelog = readFileSync("CHANGELOG.md", "utf8"); writeFileSync( "CHANGELOG.md", - changelog.replace(/^(# [^\n]+\n)/, `$1\n${section}\n`), + changelog.replace(/^(# [^\n]+\n)/, (heading) => `${heading}\n${section}\n`), ); if (!readFileSync("CHANGELOG.md", "utf8").includes(`## [${version}]`)) { throw new Error(