---
name: changelog-release
description: Журнал изменений и выпуск версий по Keep a Changelog 2.0.0 и Semantic Versioning — проверка формата, перенос Unreleased в версию с датой и ссылками сравнения, черновик записей из conventional commits, текст релиза для gh release. Загружать при подготовке релиза, при жалобах «в changelog непонятно что изменилось», когда версии идут не по порядку или даты отсутствуют.
---

# Журнал изменений и выпуск

## Контракт (Keep a Changelog 2.0.0)

- Шесть типов и только они: `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`,
  `Security`. Тип отвечает на «что это», текст — на «почему это важно».
- Версия: `## [1.2.3] - 2026-10-24`. Дата — ISO, иначе версии нельзя сортировать и
  связывать.
- `## [Unreleased]` сверху; при выпуске его содержимое переезжает в новую версию.
- Новые версии выше старых.
- Ссылки сравнения внизу; `Unreleased` сравнивается с последним тегом:

```markdown
[Unreleased]: https://github.com/owner/repo/compare/v1.1.0...HEAD
[1.1.0]: https://github.com/owner/repo/compare/v1.0.0...v1.1.0
```

- Ломающее изменение помечается `**Breaking:**` в самой записи, а не отдельным разделом.
- Запись адресована пользователю, а не коммиту: «счётчик дней до оплаты больше не
  ошибается на сутки», а не «fix off-by-one in ExpiryCalculator».

## Команды

```bash
python <pack>/tools/ghagent.py changelog check
python <pack>/tools/ghagent.py changelog suggest --since v1.1.0
python <pack>/tools/ghagent.py changelog release 1.2.0 --write
python <pack>/tools/ghagent.py changelog check                 # после записи
python <pack>/tools/ghagent.py changelog notes 1.2.0 > release-body.md
gh release create v1.2.0 --notes-file release-body.md --title v1.2.0
```

Коды возврата: `0` — чисто, `1` — есть ошибки формата, `2` — файла нет или версия не
SemVer.

## Что проверяет `check`

| Правило | Пример нарушения |
|---|---|
| `changelog.date-missing` | `## [1.1.0]` без даты |
| `changelog.date-format` | `## [1.1.0] - 20.10.2026` |
| `changelog.order` | версия 1.0.0 выше версии 1.1.0 |
| `changelog.duplicate` | две записи об одной версии |
| `changelog.empty-version` | заголовок версии без записей |
| `changelog.types` | раздел «Разное» вместо `Changed` |
| `changelog.link-refs` | ссылки `[1.1.0]` без разрешения внизу файла |
| `changelog.unreleased` | нет `[Unreleased]` (предупреждение) |

## Порядок выпуска

1. `check` — журнал в порядке до выпуска.
2. `suggest --since <тег>` — черновик из коммитов. Это **черновик**: назначение записи —
   сказать пользователю, что изменилось, а не пересказать лог.
3. Дописать черновик в `[Unreleased]` вручную.
4. `release <версия> --write` — перенос, дата, ссылки сравнения, автоматическая повторная
   проверка. Если после записи появились ошибки, они печатаются: молча «полувыпущенного»
   журнала не бывает.
5. `notes <версия>` — текст релиза без служебных ссылок.
6. Тег `vX.Y.Z`, подпись владельца.

## Выбор версии

| Изменение | Версия |
|---|---|
| исправление, ничего не добавляет | патч `1.2.3 → 1.2.4` |
| новая возможность, совместимо | минор `1.2.3 → 1.3.0` |
| ломающее изменение поведения или API | мажор `1.2.3 → 2.0.0` |
| проект до 1.0.0 | `0.y.z`: минор может ломать, но это нужно писать явно |

## Ловушки

| Ловушка | Признак | Что делать |
|---|---|---|
| Журнал из лога коммитов | записи вида `fix: typo`, `Merge pull request #12` | писать записи заново, по-человечески |
| Заголовки разделов по-русски и по-английски в одном файле | половина записей не находится | выбрать один язык; инструмент принимает оба набора, но не смесь |
| Дата в будущем | версия «выпущена завтра» | предупреждение `changelog.date-future` |
| Версия без раздела | пустая версия в истории | `changelog.empty-version` |
| Забыли ссылку сравнения | `[1.2.0]` не открывается | `release` добавляет её сам |

## Критерий готовности

- `changelog check` — код `0`.
- Каждая запись объясняет изменение пользователю и не пересказывает коммит.
- `notes` даёт текст, который можно отправлять как есть.
