Files
mdm-ordinis/RELEASE.md
T
Zimin A.N. 1da515276c ci(lint): forbid literal skip-ci marker в commit messages
GitLab платформа skip'ает pipeline на любом commit'е чей subject или body
содержит pattern с square brackets вокруг 'skip ci'. Trap: semantic-release
включает release notes из всех commit'ов в release commit body — если хотя
бы один commit имеет этот pattern в subject/body, release tag pipeline
скипается → нет images → нет auto-PR.

Реальный случай: v2.16.1 — commit fix(release): 'remove ... из semantic-
release commit message' содержал паттерн дословно. Pipeline 6831 (v2.16.1
tag) skipped → пришлось trigger через API.

Новый CI job 'commit-msg-lint' (stage: test):
- Запускается на MR pipeline'ах и feature-branch push'ах
- Скипает chore(release) commit'ы (semantic-release auto-bot)
- Для каждого commit'а в range проверяет subject+body на square-bracket
  skip-ci pattern
- Fails CI с ясной подсказкой (как переформулировать) при match

RELEASE.md обновлён с разделом 'Skip-ci marker trap': примеры
правильных формулировок (skip-ci marker, the directive, etc) и
escape hatch (manual API trigger).
2026-05-13 00:54:19 +03:00

7.2 KiB
Raw 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-PR в ordinis-infra (опционально)

propose-prod-image-bump job открывает MR в ordinis-infra после каждого release tag — bump'ит image.tag в values-prod.yaml на свежий immutable SHA tag (e.g. v2-16-0-abc12345). Чинит historical bug когда manual deploys через infra repo получали :latest (stale cache → split-brain pods).

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: Developer
    • Scopes: write_repository, api
    • Expiry: 1 год
  2. Add CI variable в ordinis project (367):

    • Key: INFRA_PROJECT_TOKEN
    • Value: (token из шага 3)
    • Flags: Masked , Protected

Без этой переменной job exits early (allow_failure: true), tag pipeline не блокируется. Manual MR в 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> не собирались → propose-prod-image-bump auto-PR не запускался → manual ручной MR в 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 отдельно.