propose-prod-image-bump открывал MR в ordinis-infra на каждый release. MR никто не мерджил — накопилось 5+ открытых, image.tag в values отставал на несколько релизов, и infra deploy-prod (helm upgrade -f values-prod.yaml) откатывал prod на старый образ. Переименован в commit-prod-image-bump: коммитит bump image.tag в values-prod.yaml + values-staging.yaml напрямую в infra main с rebase-retry. Убран промежуточный MR и 405-квирк при merge вечно-manual инфра-пайплайна. Токену нужна роль Maintainer для push в protected main (было Developer); api-scope больше не нужен.
7.9 KiB
Release Automation
Ordinis uses semantic-release для автоматического создания tag'ов на основе
conventional commits. После merge в main CI анализирует commits, решает
bump (patch/minor/major), генерирует CHANGELOG.md и пушит tag vX.Y.Z.
Tag pipeline далее собирает images и ждёт manual gate на trigger-deploy-prod.
Prod deploy остаётся под human control — semantic-release создаёт tag,
human кликает Deploy.
One-time setup
-
Create Project Access Token (GitLab UI):
Settings → Access Tokens → Add new token- Name:
semantic-release - Role:
Maintainer - Scopes:
write_repository,api - Expiry: 1 год (renew annually)
-
Add CI variable:
Settings → CI/CD → Variables → Add variable- Key:
GITLAB_TOKEN - Value: (token из шага 1)
- Type:
Variable - Flags:
Masked✅,Protected✅ (только main + tag pipelines)
После этого release job в .gitlab-ci.yml будет работать.
Auto-bump image.tag в ordinis-infra (опционально)
commit-prod-image-bump job коммитит обновление image.tag в
values-prod.yaml + values-staging.yaml на свежий immutable SHA tag
(e.g. v2-16-0-abc12345) прямо в ordinis-infra main после каждого
release tag. Чинит historical bug когда manual deploys через infra repo
получали :latest (stale cache → split-brain pods).
Раньше bump шёл через auto-MR — но MR никто не мерджил, values отставали на несколько релизов, и infra
deploy-prodоткатывал prod на старый образ. Перешли на direct commit (нет ручного шага, нет 405-квирка при merge вечно-manual инфра-пайплайна).
Setup:
-
Create Group Access Token в
2-6/2-6-4/terravault:Group → Settings → Access Tokens → Add new token- Name:
ordinis-ci-infra-bump - Role:
Maintainer(нужен push в protectedmain; Developer-роль push в protected branch не имеет) - Scopes:
write_repository - Expiry: 1 год
-
Add CI variable в ordinis project (367):
- Key:
INFRA_PROJECT_TOKEN - Value: (token из шага 3)
- Flags:
Masked✅,Protected✅
- Key:
-
ordinis-infra → Protected branches →
main: убедись чтоAllowed to pushпокрывает этот токен (роль Maintainer покрывает по умолчанию).
Без этой переменной job exits early (allow_failure: true), tag pipeline
не блокируется. Ручной bump image.tag в ordinis-infra остаётся доступен
как fallback.
Commit conventions
Conventional Commits (https://www.conventionalcommits.org/):
| Type | Bump | Section в CHANGELOG |
|---|---|---|
feat: |
minor | ✨ Features |
fix: |
patch | 🐛 Fixes |
perf: |
patch | ⚡ Performance |
refactor: |
patch | ♻️ Refactoring |
revert: |
patch | ⏪ Reverts |
docs: |
none | 📝 Docs |
chore: |
none | hidden |
test: |
none | hidden |
style: |
none | hidden |
ci: |
none | hidden |
build: |
none | hidden |
Breaking changes — добавь BREAKING CHANGE: в footer commit message → major bump.
feat(api): drop legacy v1 endpoint
BREAKING CHANGE: /api/v1/* paths больше не поддерживаются.
Все клиенты должны мигрировать на /api/v2.
⚠ Lesson learned (v2.0.0 false-major): до 2026-05-12 в .releaserc.json noteKeywords содержал bare
"BREAKING". Слово «Breaking» в обычном commit body (например «Breaking down PATCH into atomic ops…») триггерило major bump. Конфиг исправлен — оставлены только canonicalBREAKING CHANGE/BREAKING CHANGES. Когда нужен major — используй точно эти триггеры в footer.
Skip release for specific commit
Если хочешь смержить feat: или fix: но не делать release сейчас —
используй non-release type (chore:, docs:, etc).
chore(deps): bump axios 1.7 -> 1.8
⚠ НЕ используй
[skip ci]в commit message — см. раздел «Skip-ci marker trap» ниже.
Loop prevention
Release job создаёт commit chore(release): vX.Y.Z. Loop prevention работает
через releaseRules в .releaserc.json — chore-тип имеет release: false →
semantic-release на release commit'е detect'ит «no releasable commits» →
exit 0 → нет нового tag → нет loop'а.
Historical note: до MR !154 (2026-05-12) сюда добавлялось
[skip ci]. Это работало для main pipeline'а, НО skip'ало и tag pipeline на том же SHA → images с tag'омv*-*-*-<sha>не собирались →commit-prod-image-bumpне запускался → manual ручной bump в infra-repo. Удалено.
⚠ Skip-ci marker trap
GitLab pipeline pattern matcher honors [skip ci] в commit subject ИЛИ body —
где угодно в message'е. semantic-release auto-генерирует release notes
из subject+body всех commit'ов с момента последнего tag'а.
Trap: если хоть один commit body содержит литеральное [skip ci] (даже
описывая фикс этого marker'а в комментариях/changelog), эта строка попадёт
в release commit body → GitLab пропустит tag pipeline → нет images →
manual escape через glab api -X POST projects/367/pipeline?ref=vX.Y.Z.
Реальный случай: v2.16.1 (2026-05-12). Commit fix(release): remove [skip ci] из semantic-release commit message — literal [skip ci] в
subject. Release notes v2.16.1 содержали эту строку → tag pipeline 6831
skipped. Pipeline пришлось trigger вручную.
Защита: CI job commit-msg-lint (см. .gitlab-ci.yml) fail'ит любой
commit с substring [skip ci] в subject или body. Запускается на MR
pipeline'ах и feature-branch push'ах.
Если нужно упомянуть skip-ci в commit message:
- ✅
fix: remove skip-ci marker(дефис вместо пробела) - ✅
docs: explain GitLab pipeline skip syntax - ✅
chore: remove the skip-ci directive from .releaserc - ❌
fix: remove [skip ci](literal — fails lint) - ❌
update [skip ci] policy(literal — fails lint)
Manually trigger skipped tag pipeline
Если tag pipeline всё-таки попал в trap (legacy commits до commit-msg-lint или CI bypass через --no-verify):
GITLAB_HOST=git.nstart.cloud glab api -X POST "projects/367/pipeline?ref=vX.Y.Z"
Создаёт новый pipeline на той же tag-ref. Escape hatch, не regular workflow.
Branch policy
Релизы создаются ТОЛЬКО с main. Feature branches (feat/*, fix/*) собираются
для staging но НЕ создают tag'и. Релиз = merge в main + успешный staging deploy +
наличие релизных commits.
Local dry-run
Проверить что semantic-release решит сделать без push:
cd ordinis-admin-ui
pnpm install
npx semantic-release --dry-run --no-ci
Покажет следующую версию + preview CHANGELOG entries.
Rollback
Если случайно зарелизили — удали tag:
git tag -d v1.3.1
git push origin :refs/tags/v1.3.1
GitLab Releases UI — удали release object отдельно.