From ed59c601b31ca450ab13ea0cdaa13894fd4e6009 Mon Sep 17 00:00:00 2001 From: Ancelin SERRE Date: Fri, 23 Oct 2026 10:15:05 +0200 Subject: [PATCH] fix: join wrapped changelog lines in release notes The release page is not 80 columns wide. check-release --notes now joins a bullet's continuation lines, and points relative links at the tag when GITHUB_REPOSITORY is set, as it is on a runner. Co-Authored-By: Claude Sonnet 5.5 --- .mise/scripts/check-release | 15 ++++++++++++++- tests/unit/test_check_release.py | 26 ++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.mise/scripts/check-release b/.mise/scripts/check-release index 8c6abc1..5b0c525 100644 --- a/.mise/scripts/check-release +++ b/.mise/scripts/check-release @@ -44,5 +44,18 @@ section=$(awk -v h="## [$version]" ' [[ -n "${section//[[:space:]]/}" ]] || fail "CHANGELOG.md has no filled '## [$version]' section" ((failures == 0)) || exit 1 -$notes && printf '%s\n' "$section" + +# The changelog is wrapped for the repository; a release page is not, so a +# bullet's continuation lines are joined onto it. Relative links would lead +# nowhere from the release page, so they point at the tag when the repository +# is known, as it is on a runner. +if $notes; then + base="" + [[ -z "${GITHUB_REPOSITORY:-}" ]] || base="${GITHUB_SERVER_URL:-https://github.com}/$GITHUB_REPOSITORY/blob/$tag/" + printf '%s\n' "$section" | awk ' + /^ / { sub(/^ +/, ""); line = line " " $0; next } + { if (NR > 1) print line; line = $0 } + END { print line } + ' | sed -E "s|\]\(|](${base}|g; s|\]\(${base}(https?://)|](\1|g" +fi exit 0 diff --git a/tests/unit/test_check_release.py b/tests/unit/test_check_release.py index 18dda42..260297f 100644 --- a/tests/unit/test_check_release.py +++ b/tests/unit/test_check_release.py @@ -27,13 +27,13 @@ def make_repo(root: Path, *, skill: str = "0.1.0", pyproject: str = "0.1.0") -> ) -def run(root: Path, *args: str) -> subprocess.CompletedProcess[str]: +def run(root: Path, *args: str, **env: str) -> subprocess.CompletedProcess[str]: return subprocess.run( # noqa: S603 ["bash", str(SCRIPT), *args], # noqa: S607 capture_output=True, text=True, check=False, - env={"CHECK_RELEASE_ROOT": str(root), "PATH": "/usr/bin:/bin"}, + env={"CHECK_RELEASE_ROOT": str(root), "PATH": "/usr/bin:/bin", **env}, ) @@ -60,6 +60,28 @@ def test_notes_are_the_matching_section_only(tmp_path: Path) -> None: assert result.stdout.strip() == "- First release.\n- Second line." +def test_notes_join_wrapped_lines_and_point_links_at_the_tag(tmp_path: Path) -> None: + # Given a changelog whose bullet wraps and links to a file in the repository + make_repo(tmp_path) + (tmp_path / "CHANGELOG.md").write_text( + "# Changelog\n\n## [0.1.0] - 2026-10-02\n\n" + "- First release, wrapped\n onto a second line ([ADR](docs/a.md), [site](https://x.test/y)).\n" + "- Second.\n" + ) + + # When the notes are asked for on a runner, which names its repository + result = run(tmp_path, "v0.1.0", "--notes", GITHUB_REPOSITORY="org/repo") + + # Then each bullet is one line, and only the relative link is rewritten + assert result.stdout.strip().splitlines() == [ + ( + "- First release, wrapped onto a second line " + "([ADR](https://github.com/org/repo/blob/v0.1.0/docs/a.md), [site](https://x.test/y))." + ), + "- Second.", + ] + + @pytest.mark.parametrize("tag", ["0.1.0", "v1", "v0.1", "v0.1.0-rc1", ""]) def test_malformed_tag_is_a_usage_error(tmp_path: Path, tag: str) -> None: # Given a consistent repository