From ccdca942e99e83c4e8f73fdf558b5aa8a7bd3b01 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 10 Nov 2026 10:04:33 +0100 Subject: [PATCH] fix(changelog): make every surface split a release the same way The app, the website and the release scripts each parse CHANGELOG.md with their own code, and only the app skipped fenced code blocks and read CRLF. A `###` or a release heading inside a fenced example in a highlight would have ended the highlights early on the website and in the GitHub release body, or started a phantom release, while the app showed it correctly. The website and script parsers now follow the app's rules, and one case file, scripts/test-support/changelog-structure.json, is run by all three suites so a rule cannot change in one place only. The release-notes script tests were not part of any CI job; they now run with the other script contract tests. --- .github/workflows/ci.yml | 2 +- docs/release.md | 2 +- .../internal/parse-changelog.test.ts | 53 +++++- packages/website/src/changelog.test.ts | 41 +++++ packages/website/src/changelog.ts | 36 +++- scripts/changelog-utils.mjs | 35 +++- scripts/changelog-utils.test.mjs | 41 +++++ scripts/test-support/changelog-structure.json | 167 ++++++++++++++++++ 8 files changed, 361 insertions(+), 16 deletions(-) create mode 100644 scripts/changelog-utils.test.mjs create mode 100644 scripts/test-support/changelog-structure.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 285ff8e072..c14e060e0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: filters: .github/ci-paths.yml - name: Validate CI contracts - run: node --test scripts/ci-workflow.test.mjs scripts/daemon-launch-contract.test.mjs scripts/sync-fdroid-changelogs.test.mjs scripts/upload-release-assets.test.mjs + run: node --test scripts/ci-workflow.test.mjs scripts/daemon-launch-contract.test.mjs scripts/changelog-utils.test.mjs scripts/sync-fdroid-changelogs.test.mjs scripts/sync-release-notes-from-changelog.test.mjs scripts/upload-release-assets.test.mjs quality: name: quality diff --git a/docs/release.md b/docs/release.md index c4bf822f7e..e76d2a833b 100644 --- a/docs/release.md +++ b/docs/release.md @@ -594,7 +594,7 @@ Release notes depend on the changelog heading format. The heading **must** be st No prefix (`v`), no extra text. `Release Notes Sync` matches the `## X.Y.Z` (or `## X.Y.Z-beta.N`) line for the pushed tag to extract the version. A malformed heading breaks the release-notes sync for that tag. -`CHANGELOG.md` on `main` is also what the app's **What's new** sheet fetches and renders, so the file is a shipped product surface, not just a release input. `##` starts a release and `###` starts a section; the app reads section titles from the document, so renaming or adding one needs no app change. Content between the release heading and the first `###` is the release's [highlights](#changelog-highlights). The What's new sheet, the website changelog and the GitHub release body show the highlights and keep the sections collapsed behind one control: Show all changes in the app and on the website, and an All changes `
` block that `Release Notes Sync` writes into the release body, so the file itself never needs HTML. A release with nothing before its first `###` shows its sections. Older entries that open with summary paragraphs are treated as highlights. Everything under a section is rendered as Markdown: prose, lists, links, inline code, fenced code, block quotes, tables, and images. Raw HTML does not render — the shared Markdown parser runs with `html: false`, so a `