From 5c258f46870e15aba8a650ffeeef138206f4d1d4 Mon Sep 17 00:00:00 2001 From: Yuriy Kirillov Date: Sat, 29 Aug 2026 14:49:27 +0200 Subject: [PATCH] fix: compact Telegram release descriptions --- .../prepare.py | 33 ++++++++++++++----- test/test_telegram_notifications.py | 12 ++++--- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/.github/actions/prepare-telegram-release-message/prepare.py b/.github/actions/prepare-telegram-release-message/prepare.py index 8f8be65..36352b1 100644 --- a/.github/actions/prepare-telegram-release-message/prepare.py +++ b/.github/actions/prepare-telegram-release-message/prepare.py @@ -6,6 +6,8 @@ RELEASE_DESCRIPTION_LIMIT = 3500 MARKDOWN_V2_SPECIAL_CHARACTERS = frozenset("_*[]()~`>#+-=|{}.!\\") MARKDOWN_LINK = re.compile(r"\[([^]]+)]\([^)]*\)") +MARKDOWN_HEADING = re.compile(r"^(#{1,6})\s+") +MARKDOWN_LIST_ITEM = re.compile(r"^(?:[-+*]|\d+\.)\s+") def escape_markdown(value): @@ -22,16 +24,31 @@ def truncate(value, limit): return value[: limit - 3].rstrip() + "..." -def release_description(value, limit=RELEASE_DESCRIPTION_LIMIT): +def is_release_heading(value, tag): + version = re.escape(tag.removeprefix("v")) + return bool(re.fullmatch(rf"v?{version}(?:\s+\(\d{{4}}-\d{{2}}-\d{{2}}\))?", value)) + + +def release_description(value, tag="", limit=RELEASE_DESCRIPTION_LIMIT): lines = [] for source_line in value.strip().splitlines(): - line = re.sub(r"^#{1,6}\s+", "", source_line.strip()) - line = re.sub(r"^(?:[-+*]|\d+\.)\s+", "", line) + source_line = source_line.strip() + if not source_line: + continue + + heading = bool(MARKDOWN_HEADING.match(source_line)) + line = MARKDOWN_HEADING.sub("", source_line) + line = MARKDOWN_LIST_ITEM.sub("", line) line = MARKDOWN_LINK.sub(r"\1", line) - if line or (lines and lines[-1]): - lines.append(line) + if not line or line in ("---", "***"): + continue + if heading and not lines and tag and is_release_heading(line, tag): + continue + + escaped = escape_markdown(line) + lines.append(f"*{escaped}*" if heading else f"• {escaped}") - return truncate("\n".join(lines).strip(), limit) + return truncate("\n".join(lines), limit) def format_published(repository, release): @@ -46,8 +63,8 @@ def format_published(repository, release): parts.append(escape_markdown(release.get("actor") or "ghost")) message = " · ".join(parts) - if description := release_description(release.get("body") or ""): - message += f"\n{escape_markdown(description)}" + if description := release_description(release.get("body") or "", tag=tag): + message += f"\n{description}" return message diff --git a/test/test_telegram_notifications.py b/test/test_telegram_notifications.py index 4a2dde7..339a0ec 100644 --- a/test/test_telegram_notifications.py +++ b/test/test_telegram_notifications.py @@ -220,7 +220,7 @@ def test_formats_distinct_release_name_and_escapes_markdown(self): self.assertIn(r"*Summer \[release\]*", message) self.assertTrue(message.endswith(r"dependabot\[bot\]")) - def test_includes_release_please_description_as_plain_text(self): + def test_formats_release_please_description_as_compact_list(self): release = { "tag": "v0.16.0", "name": "v0.16.0", @@ -230,7 +230,8 @@ def test_includes_release_please_description_as_plain_text(self): "### Features\n\n" "* add Telegram release notifications " "([#171](https://github.com/owner/repo/issues/171)) " - "([8d9e8c0](https://github.com/owner/repo/commit/8d9e8c0))" + "([8d9e8c0](https://github.com/owner/repo/commit/8d9e8c0))\n\n" + "Deploy: mainframe updated" ), "actor": "octocat", } @@ -239,10 +240,13 @@ def test_includes_release_please_description_as_plain_text(self): self.assertTrue( message.endswith( - "octocat\n0\\.16\\.0 \\(2026\\-08\\-24\\)\n\n" - "Features\n\nadd Telegram release notifications \\(\\#171\\) \\(8d9e8c0\\)" + "octocat\n*Features*\n" + "• add Telegram release notifications \\(\\#171\\) \\(8d9e8c0\\)\n" + "• Deploy: mainframe updated" ) ) + self.assertNotIn("0\\.16\\.0 \\(2026\\-08\\-24\\)", message) + self.assertNotIn("\n\n", message) def test_truncates_long_release_description(self): description = RELEASE_TELEGRAM.release_description(