feat(release): create-changelog tool with Russian validation #59
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Контекст
Текущий процесс релизов создаёт мусорные release notes: скрипт
create_release.pyпихает весь CHANGELOG.md (267 строк, 29 КБ) в body релиза на Forgejo. Причины: (1) нет детерминированного инструмента генерации CHANGELOG, (2) скиллreleaseпишет записи вручную через bash без валидации, (3) записи в CHANGELOG — смесь английского и русского, абзацы вместо однострочников, мусор вроде(PR#N),**Category**:.Шаг 3.5 (бамп pyproject.toml +
__init__.__version__) был потерян — правили в~/.config/opencode/(bind-mount), а не в workspace-клоне (ADR-138 описывает фикс как сделанный, но в каноническом скилле его нет).Инфраструктура tools уже существует:
.opencode/tools/*.tsавто-обнаруживаются,create-pr.tsиcreate-issue.ts— готовые шаблоны с валидацией (regex + Cyrillic check + heading checks). Паттерн: агент вызывает тулзу → тулза валидирует → не прошло → возврат с ошибками → агент исправляет → повтор.Задача
.opencode/tools/create-changelog.ts— детерминированный инструмент валидации и записи CHANGELOG..opencode/skills/release/SKILL.md— использоватьcreate-changelogтулзу вместо ручного bash, вернуть потерянный Шаг 3.5 (бамп pyproject +__init__), убрать правило "НЕ обновляй pyproject.toml version".tests/test_create_changelog_tool.pyпо образцуtests/test_create_pr_tool.py.Контракты
create-changelog.ts
Args:
version: string— версия релиза, формат/^v\d+\.\d+\.\d+$/(с префиксомv)sections: object— объект с секциями. Ключи:added,changed,fixed,removed(необязательные, минимум один). Значения: массив строк (записей).Валидация (fail-fast, возврат
❌ ...+ RULES):version— regex/^v\d+\.\d+\.\d+$//[\u0400-\u04FF]/.test(entry)→ true (русский)\n)/\(PR#\d+\)/,/Closes #\d+/,/^\*\*[^*]+\*\*:/(префикс**Category**:)Действие после валидации:
CHANGELOG.md(если нет — создать с нуля)## [Unreleased]→## [X.Y.Z] - YYYY-MM-DD(дата = сегодня)## [Unreleased]сверху (после шапки)### Добавлено/### Изменено/### Исправлено/### Удаленос bullet-pointspyproject.toml: regex/^version = ".*"$/m→version = "X.Y.Z"(без префикса v)__init__.__version__: regex/__version__\s*=\s*["'].*["']/→__version__ = "X.Y.Z"(если файл существует)✅ CHANGELOG обновлён: vX.Y.Z, N записей. CHANGELOG.md + pyproject.toml + __init__.py обновлены.RULES (возвращаются при ошибке):
release/SKILL.md
create-changelogтулзу вместо ручного bash__init__.__version__(теперь делает тулза)Инварианты
## [X.Y.Z] - YYYY-MM-DD(с дефисом, не тире)CHANGELOG.mdне существует — создаётся с нуля (шапка + Unreleased + версия)toolfrom@opencode-ai/plugin, хелперы из./_sharedпри необходимостиГраничные случаи
CHANGELOG.mdне существует → создать с нуля (шапка +## [Unreleased]+## [X.Y.Z] - дата)## [Unreleased]отсутствует → создать сверхуpyproject.tomlне существует → пропустить бамп (не все репо — Python)__init__.py/__init__.__version__не существует → пропуститьadded: []) → секция не вставляетсяffmpeg,PyInstaller) → допустимо (латиница < 30%)v(0.2.0вместоv0.2.0) → ошибка валидацииВлияние на связанные компоненты
.opencode/skills/release/SKILL.md— обновляется (использует тулзу)tests/test_create_changelog_tool.py— новый файл (по образцуtest_create_pr_tool.py)opencode.json— без изменений (тулза авто-обнаруживается). Опционально: добавить вagentblock пермишены (create_changelog: trueдляgeneral)create_release.pyв video_uniq и voice_assistant — отдельные issue (экстрактор)Вне scope
create_release.py(video_uniq, voice_assistant) — отдельные issueКритерии приемки
.opencode/tools/create-changelog.tsсоздан, следует паттернуcreate-issue.tstests/test_create_changelog_tool.py— тесты: happy path, invalid version, no Cyrillic, multi-line entry, forbidden patterns, missing CHANGELOG, missing pyproject.opencode/skills/release/SKILL.mdобновлён: использует тулзу, Шаг 3.5 возвращён, "НЕ обновляй pyproject" убраноruff check+mypyпроходят (если применимо к TS —tsc --noEmitили аналог)