Files
Zimin A.N. b76997e170 ci: bump infra image.tag прямым коммитом в main вместо auto-MR
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 больше не нужен.
2026-05-21 19:25:58 +03:00

7.9 KiB
Raw Permalink Blame History

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

  1. 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)
  2. 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:

  1. 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 в protected main; Developer-роль push в protected branch не имеет)
    • Scopes: write_repository
    • Expiry: 1 год
  2. Add CI variable в ordinis project (367):

    • Key: INFRA_PROJECT_TOKEN
    • Value: (token из шага 3)
    • Flags: Masked , Protected
  3. 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. Конфиг исправлен — оставлены только canonical BREAKING 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 отдельно.