From 03b3b59e6ff2ba391f9dfc42a039a96d0d84c1c9 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Mon, 12 Oct 2026 10:17:53 +0300 Subject: [PATCH] fix: align workflow commitlint policy (#27) --- .ai/conventions/engineering-workflow.md | 17 ++++++++++------- commitlint.config.cjs | 6 +++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.ai/conventions/engineering-workflow.md b/.ai/conventions/engineering-workflow.md index 35504c4..e45df73 100644 --- a/.ai/conventions/engineering-workflow.md +++ b/.ai/conventions/engineering-workflow.md @@ -51,15 +51,18 @@ performance → `perf`. Номер обязателен для новых раб | --- | --- | | Implementation → Commit | Одна связанная задача на commit, проверить staged paths/diff. Заголовок Conventional Commits с осмысленным subject и ссылкой на Issue: `feat(portfolio): add transaction import (#123)` или `ci: align gates (WealthLedger/main#27)`. Scope только при полезной области. | -Commitlint проверяет Conventional Commits и присутствие ссылки; не может -проверить существование Issue, её смысл или корректный repo. Использовать `#N` -только для локальной Issue и `WealthLedger/repo#N` для чужой. Без `fixes`, +Commitlint требует распознаваемую conventional-commits-parser ссылку, но не +проверяет числовой формат, существование Issue, её смысл или корректный repo. +Использовать `#N` только для локальной Issue и `WealthLedger/repo#N` для чужой; +это формат команды, проверяемый при review. Не добавлять custom validator +ради более строгой регулярной проверки. Без `fixes`, `closes`, `resolves` в сообщении: не закрывать задачу первым коммитом. Ссылка в footer тоже принимается commitlint; размещение в заголовке остаётся правилом команды. Если заголовок PR после squash станет commit title, оставить -в нём ссылку. Служебный squash title для release — исключение. -Релизные `chore(release): X.Y.Z`, созданные release-it, и служебные merge/sync -коммиты сохраняют действующую процедуру. Историю не переписывать ради формата. +в нём ссылку. `chore(release): X.Y.Z` освобождён только при точном SemVer +заголовке release-it. Стандартные Gitea merge commits освобождаются по точному +шаблону merge message; sync PR используют обычный review/merge process. +Историю не переписывать ради формата. ## Pull Request Process @@ -128,7 +131,7 @@ Frontend/backend запускают их как jobs в едином `verify.yml | Правило | Уровень на момент принятия документа | | --- | --- | -| Conventional Commits и наличие распознаваемого Issue reference в PR title и новых commits | CI-проверка через существующий commitlint; блокировка merge **только если** check обязателен в branch protection. Release title исключён; ссылка может быть в footer. Локальные hooks не гарантируют server-side. | +| Conventional Commits и parser-recognized Issue reference в PR title/commits | CI-проверка через существующий commitlint; блокировка merge **только если** check обязателен в branch protection. Не гарантирует numeric reference, существование или соответствие Issue. Точный release SemVer title и штатные Gitea merge messages исключены. Локальные hooks не гарантируют server-side. | | PR вместо прямого push; successful checks перед merge | Enforced только в repos/ветках, где Gitea branch protection настроена и проверена владельцем. YAML сам по себе не защищает ветку. | | Поиск актуальной Issue, AC, корректный repo, branch name/source, соответствие ссылки, SDD selection, scope, статус | Agent-guided; templates и текст не могут гарантировать соответствие. | | Значимое review, соответствие AC/контракту, исключения и closure после всех PR | Manual; approval может быть required в Gitea, если есть независимый reviewer. | diff --git a/commitlint.config.cjs b/commitlint.config.cjs index 2a6c08b..512700c 100644 --- a/commitlint.config.cjs +++ b/commitlint.config.cjs @@ -1,6 +1,10 @@ module.exports = { extends: ["@commitlint/config-conventional"], - ignores: [(message) => /^chore\(release\): \d+\.\d+\.\d+/.test(message)], + defaultIgnores: false, + ignores: [ + message => /^chore\(release\): \d+\.\d+\.\d+$/.test(message.trim()), + message => /^Merge pull request ['"].+['"] \(#\d+\) from .+ into .+$/.test(message.trim()), + ], rules: { "type-enum": [2, "always", ["feat", "fix", "perf", "docs", "spec", "refactor", "build", "ci", "test", "style", "chore", "revert"]], "references-empty": [2, "never"],