fix(release): extract only current version section for release notes #24

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

Контекст

Скрипт scripts/create_release.py (строки 34-35, 48) делает note = f.read() — читает весь CHANGELOG.md (21 строка, 962 символа) и пихает в body релиза на Forgejo. Включает шапку "# Changelog", boilerplate про Keep a Changelog, self-referential ссылку [0.1.0]: https://git.slaid098.dev/.../releases/tag/v0.1.0 внизу (ссылка на страницу, на которой пользователь уже находится).

Forgejo уже показывает тег и дату релиза в UI — дублирование. Та же проблема что в video_uniq (issue #9), тот же фикс.

Задача

  1. Заменить note = f.read() в scripts/create_release.py на экстрактор секции текущей версии.
  2. Экстрактор: парсит CHANGELOG.md, находит секцию по тегу, срезает заголовок/дату/шапку/links, возвращает чистый bullet-list.
  3. Сохранить идемпотентность (delete-then-create) — уже реализована, не трогать.

Контракты

Экстрактор (встроить в create_release.py)

Вход: CHANGELOG.md + tag (из GITHUB_REF_NAME или GITHUB_REF, формат vX.Y.Z)

Логика:

  1. Прочитать CHANGELOG.md
  2. Извлечь версию из тега: v0.1.00.1.0
  3. Найти секцию: regex r"^## \[0\.1\.0\]" (экранированная версия)
  4. Взять контент от этой строки до следующего ^## \[ (или конца файла)
  5. Срезать первую строку (## [0.1.0] — 2026-08-11 — тег+дата, Forgejo показывает)
  6. Срезать шапку если попала (# Changelog, Все заметные изменения..., Формат: [Keep a Changelog...)
  7. Срезать trailing links: r"^\[.*\]:\s*https://.*$" (self-referential)
  8. Результат: только ### Добавлено / ### Исправлено + bullet-points

Fallback: если секция не найдена — вернуть весь CHANGELOG (как сейчас) + залогировать предупреждение. Не падать — релиз должен выйти.

Пример:

Вход CHANGELOG.md (21 строка):
# Changelog
Все заметные изменения проекта голосового помощника.
Формат: [Keep a Changelog 1.1.0]...
## [0.1.0] — 2026-08-11
### Добавлено
- Голосовой помощник для слабовидящих пользователей. Русский язык.
- Wake word: openWakeWord (нейронный, ONNX, слово «вики»)
...
[0.1.0]: https://git.slaid098.dev/slaid098/voice_assistant/releases/tag/v0.1.0

Выход (body релиза v0.1.0):
### Добавлено
- Голосовой помощник для слабовидящих пользователей. Русский язык.
- Wake word: openWakeWord (нейронный, ONNX, слово «вики»)
...

Что НЕ меняется

  • name поля релиза = tag (Forgejo дефолтит в тег — нормально)
  • Идемпотентность (delete-then-create) — не трогать
  • Загрузка zip-attachment — не трогать

Инварианты

  • Экстрактор не падает на отсутствующем CHANGELOG — fallback на пустую строку
  • Экстрактор не падает на отсутствующей секции — fallback на весь файл + предупреждение
  • Версия из тега извлекается безопасно (regex, не string slicing)
  • Выходной текст — UTF-8, без trailing whitespace
  • Скрипт остаётся детерминированным: одинаковый CHANGELOG + тег → одинаковый body
  • Логика идентична video_uniq issue #9 — экстрактор тот же, различия только в имени репо и asset filename

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

  • CHANGELOG.md не существует → body = "" (релиз без нот, не падать)
  • Секция не найдена (версия в теге не совпадает с CHANGELOG) → fallback на весь файл + warning в лог
  • CHANGELOG с тире вместо дефиса - в заголовке (## [0.1.0] — 2026-08-11) → regex должен покрывать оба: r"^## \[VERSION\]\s*[-—]\s*\d{4}-\d{2}-\d{2}"
  • Пустая секция (только заголовок ## [0.1.0] — дата, без bullet-points) → body = ""
  • CHANGELOG с русской шапкой ("Все заметные изменения...") → тоже срезать

Влияние на связанные компоненты

  • scripts/create_release.py — единственный файл изменений
  • .github/workflows/release.yml — не трогать (вызывает скрипт как есть)
  • CHANGELOG.md — не трогать (источник, не приёмник)
  • Тест: добавить tests/test_create_release.py (или test_release_extractor) — проверка экстрактора на тестовых CHANGELOG

Вне scope

  • Тулза create-changelog (opencode-config) — issue #59
  • Удаление старых релизов на Forgejo — отдельный issue
  • Переписывание существующих записей в CHANGELOG — не трогаем
  • video_uniq create_release.py — issue #9 (тот же фикс, другой репо)

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

  • scripts/create_release.pyf.read() заменён на экстрактор
  • Экстрактор: находит секцию по тегу, срезает заголовок/дату/шапку/links
  • Fallback: секция не найдена → весь файл + warning
  • Fallback: CHANGELOG отсутствует → пустая строка, не падать
  • Тесты: happy path, секция не найдена, CHANGELOG отсутствует, пустая секция, тире вместо дефиса
  • ruff check + mypy проходят
  • Тесты проходят
## Контекст Скрипт `scripts/create_release.py` (строки 34-35, 48) делает `note = f.read()` — читает весь `CHANGELOG.md` (21 строка, 962 символа) и пихает в `body` релиза на Forgejo. Включает шапку "# Changelog", boilerplate про Keep a Changelog, self-referential ссылку `[0.1.0]: https://git.slaid098.dev/.../releases/tag/v0.1.0` внизу (ссылка на страницу, на которой пользователь уже находится). Forgejo уже показывает тег и дату релиза в UI — дублирование. Та же проблема что в video_uniq (issue #9), тот же фикс. ## Задача 1. Заменить `note = f.read()` в `scripts/create_release.py` на экстрактор секции текущей версии. 2. Экстрактор: парсит CHANGELOG.md, находит секцию по тегу, срезает заголовок/дату/шапку/links, возвращает чистый bullet-list. 3. Сохранить идемпотентность (delete-then-create) — уже реализована, не трогать. ## Контракты ### Экстрактор (встроить в create_release.py) **Вход:** `CHANGELOG.md` + `tag` (из `GITHUB_REF_NAME` или `GITHUB_REF`, формат `vX.Y.Z`) **Логика:** 1. Прочитать `CHANGELOG.md` 2. Извлечь версию из тега: `v0.1.0` → `0.1.0` 3. Найти секцию: regex `r"^## \[0\.1\.0\]"` (экранированная версия) 4. Взять контент от этой строки до следующего `^## \[` (или конца файла) 5. Срезать первую строку (`## [0.1.0] — 2026-08-11` — тег+дата, Forgejo показывает) 6. Срезать шапку если попала (`# Changelog`, `Все заметные изменения...`, `Формат: [Keep a Changelog...`) 7. Срезать trailing links: `r"^\[.*\]:\s*https://.*$"` (self-referential) 8. Результат: только `### Добавлено` / `### Исправлено` + bullet-points **Fallback:** если секция не найдена — вернуть весь CHANGELOG (как сейчас) + залогировать предупреждение. Не падать — релиз должен выйти. **Пример:** ``` Вход CHANGELOG.md (21 строка): # Changelog Все заметные изменения проекта голосового помощника. Формат: [Keep a Changelog 1.1.0]... ## [0.1.0] — 2026-08-11 ### Добавлено - Голосовой помощник для слабовидящих пользователей. Русский язык. - Wake word: openWakeWord (нейронный, ONNX, слово «вики») ... [0.1.0]: https://git.slaid098.dev/slaid098/voice_assistant/releases/tag/v0.1.0 Выход (body релиза v0.1.0): ### Добавлено - Голосовой помощник для слабовидящих пользователей. Русский язык. - Wake word: openWakeWord (нейронный, ONNX, слово «вики») ... ``` ### Что НЕ меняется - `name` поля релиза = `tag` (Forgejo дефолтит в тег — нормально) - Идемпотентность (delete-then-create) — не трогать - Загрузка zip-attachment — не трогать ## Инварианты - Экстрактор не падает на отсутствующем CHANGELOG — fallback на пустую строку - Экстрактор не падает на отсутствующей секции — fallback на весь файл + предупреждение - Версия из тега извлекается безопасно (regex, не string slicing) - Выходной текст — UTF-8, без trailing whitespace - Скрипт остаётся детерминированным: одинаковый CHANGELOG + тег → одинаковый body - Логика идентична video_uniq issue #9 — экстрактор тот же, различия только в имени репо и asset filename ## Граничные случаи - `CHANGELOG.md` не существует → `body = ""` (релиз без нот, не падать) - Секция не найдена (версия в теге не совпадает с CHANGELOG) → fallback на весь файл + warning в лог - CHANGELOG с тире `—` вместо дефиса `-` в заголовке (`## [0.1.0] — 2026-08-11`) → regex должен покрывать оба: `r"^## \[VERSION\]\s*[-—]\s*\d{4}-\d{2}-\d{2}"` - Пустая секция (только заголовок `## [0.1.0] — дата`, без bullet-points) → body = "" - CHANGELOG с русской шапкой ("Все заметные изменения...") → тоже срезать ## Влияние на связанные компоненты - `scripts/create_release.py` — единственный файл изменений - `.github/workflows/release.yml` — не трогать (вызывает скрипт как есть) - `CHANGELOG.md` — не трогать (источник, не приёмник) - Тест: добавить `tests/test_create_release.py` (или `test_release_extractor`) — проверка экстрактора на тестовых CHANGELOG ## Вне scope - Тулза `create-changelog` (opencode-config) — issue #59 - Удаление старых релизов на Forgejo — отдельный issue - Переписывание существующих записей в CHANGELOG — не трогаем - video_uniq `create_release.py` — issue #9 (тот же фикс, другой репо) ## Критерии приемки - [ ] `scripts/create_release.py` — `f.read()` заменён на экстрактор - [ ] Экстрактор: находит секцию по тегу, срезает заголовок/дату/шапку/links - [ ] Fallback: секция не найдена → весь файл + warning - [ ] Fallback: CHANGELOG отсутствует → пустая строка, не падать - [ ] Тесты: happy path, секция не найдена, CHANGELOG отсутствует, пустая секция, тире вместо дефиса - [ ] `ruff check` + `mypy` проходят - [ ] Тесты проходят
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/voice_assistant#24
No description provided.