From 1320a4c69ad9ae316b9fa92443850da054080245 Mon Sep 17 00:00:00 2001 From: Sam Donche Date: Mon, 5 Oct 2026 12:57:56 +0200 Subject: [PATCH] feat(release): fold changelog sections in release notes The release page opened as one long list. Each Added / Changed / Fixed section now collapses into a
block titled with its entry count, while the summary above them stays in view, matching the designer dark mode module's release pages. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 +++- ops/changelog-notes.py | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97a39e9..dae98ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,9 @@ are semver. Ignition's module version is numeric only, so releases are plain line alarm pauses the game), a "Built by Mustry Solutions" section, and an independence notice. `ops/make-gif.py` rebuilds the animation from frames the screenshot job captures. -- Release notes carry a short footer about who makes the module. +- Release notes carry a short footer about who makes the module, and fold + each Added / Changed / Fixed section into a collapsible block with its + entry count; the summary above them stays in view. - Dependabot: weekly grouped updates for GitHub Actions, Gradle and the `web/` and `e2e/` npm projects. The Ignition SDK, Jetty and the Ignition image stay manual (they track the tested gateway), as do React 16 and diff --git a/ops/changelog-notes.py b/ops/changelog-notes.py index 5961a22..dd0ad83 100755 --- a/ops/changelog-notes.py +++ b/ops/changelog-notes.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 """Print the CHANGELOG.md section for a given version, for use as GitHub Release notes. Matches the Keep-a-Changelog heading `## []...` and emits every -line up to (but not including) the next `## ` heading. +line up to (but not including) the next `## ` heading, with each `### ` +subsection folded into a
block. Usage: ops/changelog-notes.py 0.2.0 [path/to/CHANGELOG.md] Exit 0 with the section on stdout; exit 0 with a short fallback if not found @@ -27,6 +28,34 @@ def section(changelog: str, version: str) -> str: return "\n".join(out).strip() +def fold(body: str) -> str: + """Keep the summary above the first `### ` heading in view and fold each + `### Added` / `### Changed` / ... subsection into a
block titled + with its entry count, so the release page opens short and the detail is + one click away. GitHub needs a blank line after and before +
to render the Markdown inside.""" + out, title, sub = [], None, [] + + def flush(): + if title is None: + return + text = "\n".join(sub).strip("\n") + n = sum(1 for line in sub if line.startswith("- ")) + count = f" ({n})" if n else "" + out.append(f"
\n{title}{count}\n\n{text}\n\n
\n") + + for line in body.splitlines(): + if line.startswith("### "): + flush() + title, sub = line[4:].strip(), [] + elif title is None: + out.append(line) + else: + sub.append(line) + flush() + return "\n".join(out).strip() + + # Every release page carries the same footer: the README's download link lands # here, so this is where a reader who arrived for the joke learns who made it. FOOTER = """ @@ -45,7 +74,7 @@ def main() -> int: path = sys.argv[2] if len(sys.argv) > 2 else "CHANGELOG.md" with open(path, encoding="utf-8") as f: body = section(f.read(), version) - print((body if body else f"Release {version}. See CHANGELOG.md for details.") + FOOTER) + print((fold(body) if body else f"Release {version}. See CHANGELOG.md for details.") + FOOTER) return 0