CI / changes (push) Successful in 7s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Has been skipped
CI / go (push) Successful in 40s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m37s
Follow-up для semantic-release: правки overview/sheet и dispatch-ошибок уже в fb108ec, заголовок с запятой в scope не парсился. Уточнена формулировка verify в releasing.md.
Semver: patch.
Co-authored-by: Cursor <[email protected]>
96 lines
6.1 KiB
Markdown
96 lines
6.1 KiB
Markdown
# Релизы и версионирование EvoBGP
|
||
|
||
EvoBGP использует [Conventional Commits](https://www.conventionalcommits.org/) и [semantic-release](https://semantic-release.gitbook.io/) для полностью автоматических релизов на Gitea (`git.shts.su`). Ручное повышение версии в коде не требуется.
|
||
|
||
## Как определяется версия
|
||
|
||
| Тип коммита | Bump |
|
||
|-------------|------|
|
||
| `feat` | minor (1.0.0 → 1.1.0) |
|
||
| `fix`, `perf`, `ci`, `refactor` | patch (1.5.1 → 1.5.2) |
|
||
| `feat!`, `fix!` или `BREAKING CHANGE:` в теле | major (1.0.0 → 2.0.0) |
|
||
| `docs`, `chore`, `test` | без релиза |
|
||
|
||
**Scope:** один идентификатор **без запятых** (`web`, `httpapi`, `api`). Заголовок `refactor(a, b): …` **не парсится** semantic-release → релиз не создаётся (commitlint на PR это тоже отклонит). Подробнее — раздел «Scope и semantic-release» ниже.
|
||
|
||
`refactor` — patch без новых функций: перестройка кода/UI при том же поведении для пользователя. По semver на одном уровне с `fix`, но семантически «мельче» `feat` (не minor).
|
||
|
||
Отдельного суффикса `1.x.y.fix` в semver нет: «fix» в Conventional Commits означает **patch** (третья цифра). Для починки пайплайна без смены продукта — `fix(ci):` или `ci:` (оба дают patch после настройки `.releaserc.json`).
|
||
|
||
Первый релиз при отсутствии git-тегов — **1.0.0**, если есть releasable-коммиты.
|
||
|
||
**Как не перепутать `feat` и `fix`:** см. раздел «Выбор type: semver, а не «красивые слова»» в [.cursor/rules/conventional-commits.mdc](../.cursor/rules/conventional-commits.mdc). Кратко: `feat` — новая возможность (minor); `fix` — починка ожидаемого поведения (patch); follow-up баги после недавнего `feat` — всегда `fix`, даже если diff большой.
|
||
|
||
Подробные правила сообщений коммитов: [.cursor/rules/conventional-commits.mdc](../.cursor/rules/conventional-commits.mdc).
|
||
|
||
## CI-пайплайн (один push в main)
|
||
|
||
```text
|
||
push/merge в main
|
||
→ CI: openapi, web, go, bird2 (параллельно)
|
||
→ job release (в том же workflow, после quality gates):
|
||
→ semantic-release: git tag vX.Y.Z на текущий commit (без доп. commit)
|
||
→ Gitea Release + CHANGELOG.md как attachment
|
||
→ docker buildx bake с VERSION=X.Y.Z
|
||
→ образы: latest, vX.Y.Z, X.Y.Z, sha-*, короткий SHA
|
||
```
|
||
|
||
Pull request: только quality gates + commitlint; релиз и образы **не** публикуются.
|
||
|
||
Workflow: [.gitea/workflows/ci.yaml](../.gitea/workflows/ci.yaml) (job **release**).
|
||
|
||
Конфиг semantic-release: [.releaserc.json](../.releaserc.json) — без `@semantic-release/git` (CHANGELOG не коммитится в репозиторий).
|
||
|
||
## Секреты Gitea
|
||
|
||
Один PAT — **`ACTIONS_PAT`** (Settings → Actions → Secrets).
|
||
|
||
| Право PAT | Зачем |
|
||
|-----------|--------|
|
||
| push tags | git tag `vX.Y.Z` на commit merge |
|
||
| releases | Gitea Release + notes |
|
||
| packages (Container Registry) | push образов |
|
||
|
||
Fallback: **`gitea.token`** (нужны права на releases и packages).
|
||
|
||
## Источник правды для версии в runtime
|
||
|
||
Semver из git-тега пробрасывается в Go-бинарники через `-ldflags` при сборке Docker (`deploy/docker/gobinary/Dockerfile`). Пакет [`internal/version`](../internal/version/version.go):
|
||
|
||
- локально (`go run`) — `version: "dev"`
|
||
- в образе после релиза — совпадает с тегом (например `1.2.3`)
|
||
|
||
API: `GET /version`, `GET /v1/version` — поля `version`, `git_sha`, `build_time`.
|
||
|
||
Web UI показывает версию из API (footer sidebar, страница «Мониторинг»).
|
||
|
||
## Scope и semantic-release
|
||
|
||
Парсер [conventional-commits-parser](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser) (его использует semantic-release) **не понимает запятые в scope**:
|
||
|
||
| Заголовок | Парсится | Релиз |
|
||
|-----------|----------|-------|
|
||
| `refactor(web): fix layout` | да, `refactor` | patch |
|
||
| `refactor(NetworkOverviewTab, NetworkSpeakersCard): fix layout` | **нет**, `type: null` | **нет** |
|
||
|
||
Правило: **один scope** из таблицы в [.cursor/rules/conventional-commits.mdc](../.cursor/rules/conventional-commits.mdc) (`web`, `httpapi`, `api`, …).
|
||
|
||
На push в `main` job **release** запускает `scripts/commit/verify-release-commits.mjs` — в логе будут предупреждения о непарсящихся коммитах.
|
||
|
||
Если релиз «не создался», а CI зелёный: смотрите лог release — часто `No releasable commits`. Исправление: новый коммит с корректным заголовком (например `refactor(web): …`).
|
||
|
||
## CHANGELOG
|
||
|
||
Release notes — в Gitea Release; файл `CHANGELOG.md` генерируется в CI и прикрепляется как asset, **не** попадает в git history.
|
||
|
||
## Проверка после релиза
|
||
|
||
1. Один run workflow **CI** на push в main: job **release** зелёный.
|
||
2. Gitea: тег `vX.Y.Z` на том же commit, что и merge; Release с notes.
|
||
3. Container Registry: `evobgp-api:vX.Y.Z`, `evobgp-api:X.Y.Z`, `evobgp-api:latest`.
|
||
4. `curl http://localhost:8080/version` → `"version":"X.Y.Z"`.
|
||
|
||
## Первый релиз (bootstrap)
|
||
|
||
Merge в `main` с `feat(release): ...` → **v1.0.0** в том же CI run.
|