ZapretKVN-android/scripts/check-release-changes.py
loop-uh 9a15f0c611
All checks were successful
Android CI / build (push) Successful in 5m0s
release: проверять список изменений по правилам Telegram до публикации
В v0.5.0 три пункта содержали «;» внутри фразы. Бот делит changes по ;
| • и переводам строк, получил 9 пунктов вместо 6 и ответил 400 уже после
публикации на Forgejo; клиент не показал причину, и выпуск выглядел
зависшим.

scripts/check-release-changes.py повторяет правила бота (1–6 пунктов,
≤180 символов, ≤700 всего, без ; | • и прямых кавычек внутри пункта) и
запускается в publish-local-stable.sh до сборки и в verify-project.sh.
В release-changes.txt «;» внутри пунктов заменены запятыми — тот же
текст ушёл в Telegram для v0.5.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:49:44 +03:00

66 lines
2.7 KiB
Python
Executable file

#!/usr/bin/env python3
"""Validate scripts/release-changes.txt against the Telegram bot's changelog rules.
The same items feed the Forgejo release notes and the Telegram announcement.
The bot (zapretgpt release_changelog.normalize_changes) receives them joined
by "; " inside one shell-quoted command and splits them again on ; | • and
newlines. An item that itself contains one of those separators turns into
several items on the bot side — v0.5.0 had 6 items that became 9 and the
announcement was rejected with HTTP 400 after the Forgejo release was already
public. Fail before publication instead.
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
MAX_ITEMS = 6
MAX_ITEM_CHARS = 180
MAX_TOTAL_CHARS = 700
SEPARATORS = re.compile(r"[;|•]")
def load_items(path: Path) -> list[str]:
items = []
for line in path.read_text(encoding="utf-8").splitlines():
if not line.strip() or line.startswith("#"):
continue
items.append(" ".join(line.split()).strip(" -•\t"))
return items
def problems(items: list[str]) -> list[str]:
found = []
if not 1 <= len(items) <= MAX_ITEMS:
found.append(f"нужно от 1 до {MAX_ITEMS} пунктов, сейчас {len(items)}")
for number, item in enumerate(items, start=1):
if len(item) > MAX_ITEM_CHARS:
found.append(f"пункт {number}: {len(item)} символов, максимум {MAX_ITEM_CHARS}")
if SEPARATORS.search(item):
found.append(f"пункт {number}: символы ; | • делят пункт в Telegram — замените запятой")
if "'" in item or '"' in item:
found.append(f"пункт {number}: прямые кавычки ломают команду бота — используйте «ёлочки»")
if len("; ".join(items)) > MAX_TOTAL_CHARS:
found.append(f"всего {len('; '.join(items))} символов, максимум {MAX_TOTAL_CHARS}")
bot_view = "\n".join(f"• {item}" for item in items)
if len(bot_view) > MAX_TOTAL_CHARS:
found.append(f"в Telegram выйдет {len(bot_view)} символов, максимум {MAX_TOTAL_CHARS}")
return found
def main() -> int:
path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).with_name("release-changes.txt")
found = problems(load_items(path))
if found:
print(f"{path}: changelog не пройдёт в Telegram:", file=sys.stderr)
for problem in found:
print(f" - {problem}", file=sys.stderr)
return 1
print("Release changelog fits the Forgejo notes and the Telegram announcement.")
return 0
if __name__ == "__main__":
raise SystemExit(main())