Merge branch 'ci/semantic-release-automation' into 'main'
ci: semantic-release automation for tag/CHANGELOG (Option D) See merge request 2-6/2-6-4/terravault/ordinis!50
This commit is contained in:
@@ -11,6 +11,7 @@ stages:
|
|||||||
- build
|
- build
|
||||||
- publish
|
- publish
|
||||||
- trigger-deploy
|
- trigger-deploy
|
||||||
|
- release
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
|
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
|
||||||
@@ -366,3 +367,51 @@ trigger-deploy-prod:
|
|||||||
rules:
|
rules:
|
||||||
- if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/'
|
- if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/'
|
||||||
when: manual
|
when: manual
|
||||||
|
|
||||||
|
# =============================================================
|
||||||
|
# Release automation — semantic-release.
|
||||||
|
# =============================================================
|
||||||
|
# Анализирует conventional commits с последнего tag'а, решает bump (patch/
|
||||||
|
# minor/major), генерирует CHANGELOG.md, bump'ит package.json, создаёт git tag
|
||||||
|
# vX.Y.Z и GitLab Release. Tag pipeline далее автоматически собирает images
|
||||||
|
# и ждёт manual gate на trigger-deploy-prod.
|
||||||
|
#
|
||||||
|
# Запускается ТОЛЬКО на main, ТОЛЬКО после успешного staging deploy.
|
||||||
|
# Если нет релизных commits (только chore/test/ci/docs/style) — exit 0 без
|
||||||
|
# tag'а. Loop prevention: коммит `chore(release): vX.Y.Z [skip ci]` —
|
||||||
|
# `[skip ci]` стандартный GitLab marker, новый pipeline не триггерится.
|
||||||
|
#
|
||||||
|
# Setup ONE-TIME (см. RELEASE.md):
|
||||||
|
# 1. Settings → Access Tokens → create Project Access Token
|
||||||
|
# - role: Maintainer
|
||||||
|
# - scopes: write_repository, api
|
||||||
|
# - expiry: 1 год (renew раз в год)
|
||||||
|
# 2. Settings → CI/CD → Variables → add:
|
||||||
|
# GITLAB_TOKEN = <token> (Masked, Protected)
|
||||||
|
#
|
||||||
|
# Tuning: чтобы НЕ релизить feat: автоматом — добавь в commit message
|
||||||
|
# `[skip release]` и semantic-release пропустит этот commit (см. parserOpts).
|
||||||
|
release:
|
||||||
|
stage: release
|
||||||
|
image: node:22-alpine
|
||||||
|
needs:
|
||||||
|
- job: trigger-deploy-staging
|
||||||
|
artifacts: false
|
||||||
|
rules:
|
||||||
|
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||||
|
when: on_success
|
||||||
|
variables:
|
||||||
|
# semantic-release требует full git history для commit analysis.
|
||||||
|
GIT_DEPTH: "0"
|
||||||
|
# GL_TOKEN — @semantic-release/gitlab plugin requires this name specifically.
|
||||||
|
GL_TOKEN: $GITLAB_TOKEN
|
||||||
|
before_script:
|
||||||
|
- apk add --no-cache git ca-certificates
|
||||||
|
- npm install -g --silent pnpm@9.15.4
|
||||||
|
- cd ordinis-admin-ui
|
||||||
|
- pnpm install --frozen-lockfile --silent
|
||||||
|
script:
|
||||||
|
- npx semantic-release
|
||||||
|
# Не блокирует следующие pipelines если release fail'нул (e.g. нет
|
||||||
|
# релизных commits). Manual investigation если нужно.
|
||||||
|
allow_failure: true
|
||||||
|
|||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
# 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` будет работать.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Skip release for specific commit
|
||||||
|
|
||||||
|
Если хочешь смержить `feat:` или `fix:` но **не** делать release сейчас —
|
||||||
|
добавь `[skip ci]` в commit message ИЛИ используй non-release type
|
||||||
|
(`chore:`, `docs:`, etc).
|
||||||
|
|
||||||
|
```
|
||||||
|
chore(deps): bump axios 1.7 -> 1.8
|
||||||
|
```
|
||||||
|
|
||||||
|
## Loop prevention
|
||||||
|
|
||||||
|
Release job создаёт commit `chore(release): vX.Y.Z [skip ci]`. `[skip ci]` —
|
||||||
|
стандартный GitLab marker, новый pipeline не триггерится. Версия package.json
|
||||||
|
+ CHANGELOG.md обновляются в этом коммите.
|
||||||
|
|
||||||
|
## Branch policy
|
||||||
|
|
||||||
|
Релизы создаются ТОЛЬКО с `main`. Feature branches (`feat/*`, `fix/*`) собираются
|
||||||
|
для staging но НЕ создают tag'и. Релиз = merge в main + успешный staging deploy +
|
||||||
|
наличие релизных commits.
|
||||||
|
|
||||||
|
## Local dry-run
|
||||||
|
|
||||||
|
Проверить что semantic-release решит сделать без push:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ordinis-admin-ui
|
||||||
|
pnpm install
|
||||||
|
npx semantic-release --dry-run --no-ci
|
||||||
|
```
|
||||||
|
|
||||||
|
Покажет следующую версию + preview CHANGELOG entries.
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
Если случайно зарелизили — удали tag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git tag -d v1.3.1
|
||||||
|
git push origin :refs/tags/v1.3.1
|
||||||
|
```
|
||||||
|
|
||||||
|
GitLab Releases UI — удали release object отдельно.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"branches": ["main"],
|
||||||
|
"tagFormat": "v${version}",
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"@semantic-release/commit-analyzer",
|
||||||
|
{
|
||||||
|
"preset": "conventionalcommits",
|
||||||
|
"releaseRules": [
|
||||||
|
{ "type": "feat", "release": "minor" },
|
||||||
|
{ "type": "fix", "release": "patch" },
|
||||||
|
{ "type": "perf", "release": "patch" },
|
||||||
|
{ "type": "refactor", "release": "patch" },
|
||||||
|
{ "type": "revert", "release": "patch" },
|
||||||
|
{ "type": "docs", "release": false },
|
||||||
|
{ "type": "style", "release": false },
|
||||||
|
{ "type": "chore", "release": false },
|
||||||
|
{ "type": "test", "release": false },
|
||||||
|
{ "type": "build", "release": false },
|
||||||
|
{ "type": "ci", "release": false },
|
||||||
|
{ "breaking": true, "release": "major" }
|
||||||
|
],
|
||||||
|
"parserOpts": {
|
||||||
|
"noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/release-notes-generator",
|
||||||
|
{
|
||||||
|
"preset": "conventionalcommits",
|
||||||
|
"presetConfig": {
|
||||||
|
"types": [
|
||||||
|
{ "type": "feat", "section": "✨ Features" },
|
||||||
|
{ "type": "fix", "section": "🐛 Fixes" },
|
||||||
|
{ "type": "perf", "section": "⚡ Performance" },
|
||||||
|
{ "type": "refactor", "section": "♻️ Refactoring" },
|
||||||
|
{ "type": "revert", "section": "⏪ Reverts" },
|
||||||
|
{ "type": "docs", "section": "📝 Docs", "hidden": false },
|
||||||
|
{ "type": "chore", "hidden": true },
|
||||||
|
{ "type": "test", "hidden": true },
|
||||||
|
{ "type": "ci", "hidden": true },
|
||||||
|
{ "type": "build", "hidden": true },
|
||||||
|
{ "type": "style", "hidden": true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/changelog",
|
||||||
|
{
|
||||||
|
"changelogFile": "CHANGELOG.md",
|
||||||
|
"changelogTitle": "# Ordinis Release Notes\n\nAuto-generated by semantic-release based on conventional commits.\nSee `.releaserc.json` for release rules."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/npm",
|
||||||
|
{
|
||||||
|
"npmPublish": false,
|
||||||
|
"tarballDir": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/git",
|
||||||
|
{
|
||||||
|
"assets": ["package.json", "CHANGELOG.md"],
|
||||||
|
"message": "chore(release): v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/gitlab",
|
||||||
|
{
|
||||||
|
"gitlabUrl": "https://git.nstart.cloud"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -48,6 +48,12 @@
|
|||||||
"tw-animate-css": "^1.4.0"
|
"tw-animate-css": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
|
"@semantic-release/commit-analyzer": "^13.0.0",
|
||||||
|
"@semantic-release/git": "^10.0.1",
|
||||||
|
"@semantic-release/gitlab": "^13.2.4",
|
||||||
|
"@semantic-release/npm": "^12.0.1",
|
||||||
|
"@semantic-release/release-notes-generator": "^14.0.1",
|
||||||
"@tailwindcss/vite": "^4.0.0-beta.7",
|
"@tailwindcss/vite": "^4.0.0-beta.7",
|
||||||
"@tanstack/router-vite-plugin": "^1.86.0",
|
"@tanstack/router-vite-plugin": "^1.86.0",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
@@ -59,6 +65,7 @@
|
|||||||
"@types/react-dom": "^19.0.0",
|
"@types/react-dom": "^19.0.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"jsdom": "^29.1.1",
|
"jsdom": "^29.1.1",
|
||||||
|
"semantic-release": "^24.2.1",
|
||||||
"tailwindcss": "^4.0.0-beta.7",
|
"tailwindcss": "^4.0.0-beta.7",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.7.2",
|
||||||
"vite": "^6.0.5",
|
"vite": "^6.0.5",
|
||||||
|
|||||||
Generated
+2465
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user