feat(release): create-changelog tool with Russian validation #59

Closed
opened 2026-08-12 14:55:06 +03:00 by slaid098 · 0 comments
Owner

Контекст

Текущий процесс релизов создаёт мусорные 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). Паттерн: агент вызывает тулзу → тулза валидирует → не прошло → возврат с ошибками → агент исправляет → повтор.

Задача

  1. Создать .opencode/tools/create-changelog.ts — детерминированный инструмент валидации и записи CHANGELOG.
  2. Обновить .opencode/skills/release/SKILL.md — использовать create-changelog тулзу вместо ручного bash, вернуть потерянный Шаг 3.5 (бамп pyproject + __init__), убрать правило "НЕ обновляй pyproject.toml version".
  3. Добавить тесты 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):

  1. version — regex /^v\d+\.\d+\.\d+$/
  2. Минимум одна секция непустая
  3. Каждая запись — Cyrillic check: /[\u0400-\u04FF]/.test(entry) → true (русский)
  4. Каждая запись — одна строка (без \n)
  5. Каждая запись — длина ≤ 200 символов
  6. Запрещены паттерны: /\(PR#\d+\)/, /Closes #\d+/, /^\*\*[^*]+\*\*:/ (префикс **Category**:)
  7. Если запись содержит латиницу > 30% символов → предупреждение (но не блокировка, технические термины допустимы)

Действие после валидации:

  • Прочитать CHANGELOG.md (если нет — создать с нуля)
  • Переименовать ## [Unreleased] → ## [X.Y.Z] - YYYY-MM-DD (дата = сегодня)
  • Добавить новый пустой ## [Unreleased] сверху (после шапки)
  • Вставить секции: ### Добавлено / ### Изменено / ### Исправлено / ### Удалено с bullet-points
  • Бамп pyproject.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 (возвращаются при ошибке):

Rules:
- version: формат vX.Y.Z (с префиксом v)
- секции: added, changed, fixed, removed (ключи на английском, минимум одна непустая)
- записи: русский язык, одна строка, ≤ 200 символов
- запрещено: (PR#N), Closes #N, **Category**: префиксы
- технические термины на латинице допустимы (ffmpeg, PyInstaller и т.д.)

release/SKILL.md

  • Шаг 3: использовать create-changelog тулзу вместо ручного bash
  • Шаг 3.5 (вернуть): бамп pyproject.toml + __init__.__version__ (теперь делает тулза)
  • Убрать: "НЕ обновляй pyproject.toml version"
  • Добавить: стандарт записей — одна строка, русский, без мусора

Инварианты

  • Тулза не создаёт git commit / tag / push — это ответственность агента через скилл
  • Тулза не удаляет старые записи в CHANGELOG — только переименовывает Unreleased и добавляет новый
  • Формат CHANGELOG: ## [X.Y.Z] - YYYY-MM-DD (с дефисом, не тире)
  • Если CHANGELOG.md не существует — создаётся с нуля (шапка + Unreleased + версия)
  • Тулза детерминирована: одинаковые args → одинаковый результат
  • Импорты: tool from @opencode-ai/plugin, хелперы из ./_shared при необходимости

Граничные случаи

  • CHANGELOG.md не существует → создать с нуля (шапка + ## [Unreleased] + ## [X.Y.Z] - дата)
  • ## [Unreleased] отсутствует → создать сверху
  • pyproject.toml не существует → пропустить бамп (не все репо — Python)
  • __init__.py / __init__.__version__ не существует → пропустить
  • Пустые секции (передан added: []) → секция не вставляется
  • Все секции пустые → ошибка валидации "минимум одна секция непустая"
  • Запись с техническим термином (ffmpeg, PyInstaller) → допустимо (латиница < 30%)
  • Запись полностью на английском → ошибка (нет Cyrillic)
  • Версия без префикса 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 — без изменений (тулза авто-обнаруживается). Опционально: добавить в agent block пермишены (create_changelog: true для general)
  • create_release.py в video_uniq и voice_assistant — отдельные issue (экстрактор)
  • Перезапуск opencode обязателен после добавления тулзы

Вне scope

  • Экстрактор в create_release.py (video_uniq, voice_assistant) — отдельные issue
  • Удаление дубликата скилла из arena-models — отдельный issue
  • Удаление старых релизов на Forgejo — отдельный issue
  • Переписывание существующих записей в CHANGELOG (исторические) — не трогаем
  • voice-dictation (другая модель — dist branch) — не трогаем

Критерии приемки

  • .opencode/tools/create-changelog.ts создан, следует паттерну create-issue.ts
  • Валидация: version regex, Cyrillic check, one-line, ≤ 200 chars, запрещённые паттерны
  • Действие: переименование Unreleased, новый Unreleased, бамп pyproject + init
  • tests/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 или аналог)
  • Тесты проходят
## Контекст Текущий процесс релизов создаёт мусорные 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). Паттерн: агент вызывает тулзу → тулза валидирует → не прошло → возврат с ошибками → агент исправляет → повтор. ## Задача 1. Создать `.opencode/tools/create-changelog.ts` — детерминированный инструмент валидации и записи CHANGELOG. 2. Обновить `.opencode/skills/release/SKILL.md` — использовать `create-changelog` тулзу вместо ручного bash, вернуть потерянный Шаг 3.5 (бамп pyproject + `__init__`), убрать правило "НЕ обновляй pyproject.toml version". 3. Добавить тесты `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):** 1. `version` — regex `/^v\d+\.\d+\.\d+$/` 2. Минимум одна секция непустая 3. Каждая запись — Cyrillic check: `/[\u0400-\u04FF]/.test(entry)` → true (русский) 4. Каждая запись — одна строка (без `\n`) 5. Каждая запись — длина ≤ 200 символов 6. Запрещены паттерны: `/\(PR#\d+\)/`, `/Closes #\d+/`, `/^\*\*[^*]+\*\*:/` (префикс `**Category**:`) 7. Если запись содержит латиницу > 30% символов → предупреждение (но не блокировка, технические термины допустимы) **Действие после валидации:** - Прочитать `CHANGELOG.md` (если нет — создать с нуля) - Переименовать `## [Unreleased]` → `## [X.Y.Z] - YYYY-MM-DD` (дата = сегодня) - Добавить новый пустой `## [Unreleased]` сверху (после шапки) - Вставить секции: `### Добавлено` / `### Изменено` / `### Исправлено` / `### Удалено` с bullet-points - Бамп `pyproject.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 (возвращаются при ошибке):** ``` Rules: - version: формат vX.Y.Z (с префиксом v) - секции: added, changed, fixed, removed (ключи на английском, минимум одна непустая) - записи: русский язык, одна строка, ≤ 200 символов - запрещено: (PR#N), Closes #N, **Category**: префиксы - технические термины на латинице допустимы (ffmpeg, PyInstaller и т.д.) ``` ### release/SKILL.md - Шаг 3: использовать `create-changelog` тулзу вместо ручного bash - Шаг 3.5 (вернуть): бамп pyproject.toml + `__init__.__version__` (теперь делает тулза) - Убрать: "НЕ обновляй pyproject.toml version" - Добавить: стандарт записей — одна строка, русский, без мусора ## Инварианты - Тулза не создаёт git commit / tag / push — это ответственность агента через скилл - Тулза не удаляет старые записи в CHANGELOG — только переименовывает Unreleased и добавляет новый - Формат CHANGELOG: `## [X.Y.Z] - YYYY-MM-DD` (с дефисом, не тире) - Если `CHANGELOG.md` не существует — создаётся с нуля (шапка + Unreleased + версия) - Тулза детерминирована: одинаковые args → одинаковый результат - Импорты: `tool` from `@opencode-ai/plugin`, хелперы из `./_shared` при необходимости ## Граничные случаи - `CHANGELOG.md` не существует → создать с нуля (шапка + `## [Unreleased]` + `## [X.Y.Z] - дата`) - `## [Unreleased]` отсутствует → создать сверху - `pyproject.toml` не существует → пропустить бамп (не все репо — Python) - `__init__.py` / `__init__.__version__` не существует → пропустить - Пустые секции (передан `added: []`) → секция не вставляется - Все секции пустые → ошибка валидации "минимум одна секция непустая" - Запись с техническим термином (`ffmpeg`, `PyInstaller`) → допустимо (латиница < 30%) - Запись полностью на английском → ошибка (нет Cyrillic) - Версия без префикса `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` — без изменений (тулза авто-обнаруживается). Опционально: добавить в `agent` block пермишены (`create_changelog: true` для `general`) - `create_release.py` в video_uniq и voice_assistant — отдельные issue (экстрактор) - Перезапуск opencode обязателен после добавления тулзы ## Вне scope - Экстрактор в `create_release.py` (video_uniq, voice_assistant) — отдельные issue - Удаление дубликата скилла из arena-models — отдельный issue - Удаление старых релизов на Forgejo — отдельный issue - Переписывание существующих записей в CHANGELOG (исторические) — не трогаем - voice-dictation (другая модель — dist branch) — не трогаем ## Критерии приемки - [ ] `.opencode/tools/create-changelog.ts` создан, следует паттерну `create-issue.ts` - [ ] Валидация: version regex, Cyrillic check, one-line, ≤ 200 chars, запрещённые паттерны - [ ] Действие: переименование Unreleased, новый Unreleased, бамп pyproject + __init__ - [ ] `tests/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` или аналог) - [ ] Тесты проходят
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
slaid098/opencode-config#59
No description provided.