Release notes на GitHub: сгенерировать и сделать читаемыми
6 мин чтения
Release notes на GitHub это описание, прикреплённое к релизу на странице Releases репозитория, и GitHub умеет написать их первый черновик за вас из pull request, влитых после предыдущего тега. Черновик это список заголовков pull request, сгруппированных по меткам, со строкой участников и ссылкой на сравнение. Он точен, полон и написан для людей, которые эти pull request вливали. Чтобы превратить его в текст, который сможет прочитать пользователь проекта, нужны файл .github/release.yml и короткий проход правки, и оба описаны ниже.
| Способ получить заметки | Где работает | Что получаете |
|---|---|---|
| Кнопка “Generate release notes” | Форма релиза в веб-интерфейсе | Заголовки PR после последнего тега, сгруппированные по категориям из release.yml |
gh release create v1.4.0 --generate-notes | GitHub CLI, локально или в CI | Тот же черновик, создаваемый вместе с релизом одной командой |
POST /repos/{owner}/{repo}/releases/generate-notes | REST API | Черновик текстом, без создания релиза, для вашего собственного конвейера |
| release-please, semantic-release, conventional-changelog | GitHub Actions или задача релиза | Заметки из сообщений коммитов вместо заголовков PR, плюс повышение версии и CHANGELOG.md |
| Написанные вручную | Форма релиза | Всё, что вы напечатаете, без ссылки обратно на pull request |
Как автоматически сгенерировать release notes на GitHub?
Откройте форму релиза, выберите или создайте тег и нажмите “Generate release notes”. GitHub находит предыдущий тег релиза, перечисляет каждый pull request, влитый в целевую ветку между ними, и пишет по одной строке на pull request с его заголовком, автором и номером. Из командной строки gh release create <tag> --generate-notes делает то же самое и публикует релиз одним шагом; --notes-start-tag переопределяет, с какого более раннего тега начинается диапазон.
Функция работает от pull request, поэтому репозиторий, который вливает прямо в main без pull request, получает пустой черновик. Squash merge подходит, потому что pull request всё равно существует. Merge-коммиты из долгоживущей ветки в main дают одну строку для вливающего pull request, без тех pull request, которые раньше были влиты в эту ветку. Если диапазон выглядит неверно, обычная причина это отсутствующий или неправильно упорядоченный предыдущий тег; генератор берёт последний релиз в целевой ветке, а тег без прикреплённого релиза игнорируется.
Страница GitHub Docs об автоматически генерируемых release notes описывает кнопку, а руководство gh release create описывает флаги CLI.
Что меняет release.yml?
.github/release.yml говорит генератору, какие pull request пропустить и как сгруппировать остальные. Без него каждый pull request попадает в один список, включая Dependabot. С ним pull request раскладываются по категориям по меткам, а шум с метками или от ботов исчезает.
# .github/release.yml
changelog:
exclude:
labels:
- skip-changelog
authors:
- dependabot
- renovate
categories:
- title: Breaking changes
labels:
- breaking-change
- title: New
labels:
- enhancement
- title: Fixed
labels:
- bug
- title: Other changes
labels:
- "*"
Три правила, которые стоит знать. Категории сопоставляются по порядку, так что pull request с метками breaking-change и bug одновременно попадает под первый подходящий заголовок. Категория-ловушка "*" обязательна, если вы хотите, чтобы pull request без меток вообще появлялись; без неё они молча отбрасываются. И файл влияет только на то, что пишет генератор, поэтому его изменение не трогает уже существующие заметки. Команды, которые уже ставят метки на pull request для проверки changelog в CI, могут использовать здесь те же метки.
Почему сгенерированные release notes на GitHub плохо читаются?
Потому что заголовок pull request написан для ревьюера, до того как изменение закончено, и описывает код. “Refactor export worker to use streaming” это хороший заголовок pull request и бесполезная заметка о релизе, потому что человек, читающий релиз, хочет знать, что экспорты больше 100 МБ больше не отваливаются по таймауту.
Вторая причина в том, что каждый влитый pull request получает одинаковый вес. Однострочное исправление опечатки стоит рядом с новым потоком аутентификации, в том порядке, в каком они влились. Читателю приходится просматривать весь список, чтобы найти три строки, которые его касаются.
Третья в том, что у черновика нет вступления. Список из сорока строк без единого предложения над ним никому не говорит, безопасно ли брать этот релиз, нужна ли миграция или он существует только ради закрепления зависимости.
Что должен изменить проход правки?
Сохраните сгенерированный список и дополняйте его, а не переписывайте с нуля. Список это журнал аудита; номера pull request это то, по чему строку возводят к диффу. Проход правки добавляет то, чего генератор знать не может.
- Напишите два-три предложения сверху. Для чего этот релиз, требует ли обновление каких-то действий и что читать первым. Если есть breaking change, скажите об этом в первой строке.
- Перепишите строки, которые людям важны, со стороны читателя: симптом, который исчез, то, что теперь можно сделать, настройка, которая переехала. Номер pull request оставьте в конце строки. Полную форму даёт статья как писать release notes; строки об исправлениях отдельно разбирает статья release notes об исправлении багов.
- Вынесите всё, что читатель должен сделать, в отдельный раздел, с точной командой или настройкой. Breaking change, закопанный в списке “Other changes”, это тикет в поддержку через неделю.
- Ничего не удаляйте из сгенерированного списка. Сверните его под заголовком “Full list of changes”, если он длинный, но сохраните, потому что им пользуются участники самого проекта.
Сделанные так release notes на GitHub занимают около десяти минут правки для типичного релиза, и заметки служат обеим аудиториям: сводка сверху для пользователей, список ниже для участников.
Должен ли релиз на GitHub быть вашим changelog?
Только если все, кому нужно знать об изменении, уже читают страницу Releases. Для библиотеки, которую разработчики получают через менеджер пакетов, это часто так, и страницы Releases плюс CHANGELOG.md в репозитории достаточно. Для продукта с пользователями, которые никогда не открывают GitHub, нет: страница релиза написана не на том уровне, живёт за URL для разработчиков, и на неё не может подписаться человек без аккаунта GitHub.
Схема, которая держится, это считать релиз на GitHub записью для разработчиков, а changelog продукта записью для читателей, где релиз ссылается на запись changelog. Как эти три записи выстраиваются друг с другом, объясняет статья git-теги, релизы и changelog. Если changelog продукта генерируется из тех же коммитов, генератор changelog даёт черновик и для этой стороны, а разделение changelog vs release notes объясняет, какая деталь куда относится.
Как версионировать сами release notes?
Опубликованный релиз на GitHub можно редактировать в любой момент, и правка не оставляет видимой истории на странице. Для большинства проектов это нормально. Для проектов, где заметки это запись, на которую опираются комплаенс или клиенты, помогают две привычки: держать канонический текст в репозитории (CHANGELOG.md или папка docs/releases/) и ссылаться на него из тела релиза, и включить неизменяемые релизы в репозитории, если ваш план это позволяет, что блокирует тег и артефакты после публикации. GitHub Docs об управлении релизами описывают черновики, предрелизы и метку “latest”, которая назначается по порядку семантических версий, если вы не задали её вручную.
FAQ
Можно ли генерировать release notes на GitHub автоматически?
Да. Кнопка “Generate release notes” на форме релиза, флаг --generate-notes у gh release create и REST-endpoint generate-notes создают черновик из pull request, влитых после предыдущего тега релиза. Файл .github/release.yml управляет группировкой и исключениями.
Почему мои сгенерированные release notes пустые? Генератор перечисляет pull request, поэтому прямые коммиты в ветку не появляются, а диапазон начинается с последнего релиза в целевой ветке, а не с последнего тега. Проверьте, что предыдущий релиз существует и что изменения пришли через pull request.
Применяется ли release.yml к уже существующим релизам? Нет. Он задаёт форму только заметкам, сгенерированным после появления файла. Тела существующих релизов остаются как были, пока кто-то их не отредактирует.
Что использовать: release notes на GitHub или CHANGELOG.md? Оба, если у проекта есть участники и пользователи. Страница релиза это то, куда смотрят разработчики и где лежат артефакты; файл в репозитории переживёт переезд с GitHub и читается офлайн. Генерируйте release notes, держите файл актуальным и ссылайтесь из одного на другое.
Технические утверждения в этой статье не проходили независимую проверку. Если здесь что-то не так, сообщите нам, и мы исправим.