--- description: >- Conventional Commits EvoBGP. Триггеры commit/коммит/закоммить/staged/commit message — ОБЯЗАТЕЛЬНО сначала Shell scripts/commit/staged-context.ps1, скилл commit-message. alwaysApply: false --- # Conventional Commits (EvoBGP) Полное описание релизного пайплайна: [docs/releasing.md](../../docs/releasing.md). ## Триггеры (применить правило + скилл) Любой запрос на коммит или сообщение коммита: `commit`, `коммит`, `закоммить`, `git commit`, `commit message`, `conventional commit`, `staged`, «сгенерируй коммит», **`/commit-message`** — в т.ч. если это указано в плане или [AGENTS.md](../../AGENTS.md). ### Не путать с кнопкой ✨ в Source Control Команда **`cursor.generateGitCommitMessage`** (sparkle в поле commit message) **не** читает Rules, Skills и `staged-context.ps1` — только staged diff и история коммитов ([ограничение Cursor](https://forum.cursor.com/t/how-to-set-prompt-for-generate-commit-message/148606)). **Замена для EvoBGP:** Agent → `/commit-message` или команда [`.cursor/commands/commit-message.md`](../commands/commit-message.md). ## Обязательный запуск скрипта (MUST) 1. Прочитать скилл [`.cursor/skills/commit-message/SKILL.md`](../skills/commit-message/SKILL.md). 2. **Первым действием** выполнить Shell (из корня репо): ```powershell powershell -NoProfile -File scripts/commit/staged-context.ps1 ``` 3. Сообщение коммита строить **только** по JSON из stdout скрипта (`groups`, `diff_excerpt`, `stat`). 4. **Запрещено** генерировать commit message без успешного (exit 0) запуска скрипта; не заменять скрипт одним `git diff --cached`. ## Формат (строго) ``` (): <тело на русском: что изменено и зачем> ``` - **Заголовок** — только английский; императив, без точки в конце; ≤72 символов. - **Тело** — только русский; полные предложения; пустая строка после заголовка. - Запрещены vague-сообщения: `fix bug`, `update code`, `wip`, `misc`. ## Типы (semantic-release) | type | Когда | Версия | |------|--------|--------| | `feat` | **новая** пользовательская возможность (раньше нельзя было) | minor | | `fix` | восстановление **ожидаемого** поведения; баг, регрессия, падение UI | patch | | `perf` | ускорение без смены API | patch | | `refactor` | реструктуризация **без** новой возможности и **без** исправления бага | patch | | `docs` | только документация | — | | `test` | тесты | — | | `ci` | CI/CD (`.gitea/`, workflows); правки, из‑за которых нужны новые образы | patch | | `chore` | обслуживание, deps, `.cursor/` | — | ### Выбор type: semver, а не «красивые слова» **Главный вопрос:** что изменится для пользователя после релиза? 1. Появилось **новое** действие / экран / API / настройка, которых не было → `feat` 2. То, что **должно было работать**, не работало (кнопки, диалоги, сохранение, 500) → `fix` 3. Только перестройка кода или UI на другой паттерн, поведение для пользователя то же → `refactor` (patch, без новых функций) 4. Ускорение без изменения контракта → `perf` **Не путать с формулировкой diff:** | В diff / задаче часто пишут | Неверный type | Верный type, если… | |-----------------------------|---------------|---------------------| | enhance, improve, polish UI | `feat` | …только чиним сломанное после прошлого PR → `fix` | | refactor pages, unify tables | `feat` | …новой возможности нет, лишь перенос на AppDataTable → `refactor` | | follow-up после feat(web) | `feat` | …исправляем баги того же экрана → `fix` | **Follow-up rule:** коммит сразу после `feat` в той же области, который **не добавляет** новую возможность, а устраняет дефект (effect loop, не открывается dialog, confirm не срабатывает) — **`fix`**, не `feat`. **Split при смешанном diff:** новая страница/flow → `feat`; отдельным коммитом правки багов → `fix`. Не объединять в один `feat`. **Breaking changes** — только `feat!` / `fix!` / `BREAKING CHANGE:` когда пользователь **обязан** менять конфиг, API или привычный workflow. ### Обязательно в пояснении агенту При каждом предложении коммита указать: - **Semver impact:** `minor` | `patch` | `none` | `major` - **Почему не другой type** (одно предложение), если diff большой или формулировка двусмысленная Пример неправильно / правильно: ``` # Плохо — patch-фикс, minor-bump feat(web): enhance module entry dialogs and selection handling # Хорошо fix(web): stop effect loop breaking module action buttons Исправлен effect_update_depth_exceeded и bind:open у Dialog; кнопки редактирования/удаления снова работают. ``` ``` # Плохо — рефакторинг без новой фичи feat(web): migrate modules list to AppDataTable # Хорошо — если не было нового user-facing refactor(web): migrate modules list to AppDataTable Единый паттерн таблиц; поведение списка модулей без изменений. Semver: patch. ``` ``` # Хорошо feat — действительно новое feat(web): add module create dialog on /modules Диалог создания модуля с POST /v1/modules; раньше создание было только через API. ``` ## Breaking changes - Заголовок: `feat!` / `fix!` **или** в теле строка `BREAKING CHANGE:` (на английском ключевое слово) + описание impact **на русском**. ## Scope (EvoBGP) Выбирать по доминирующему пути из staged diff: | Префикс | scope | |---------|-------| | `internal/httpapi/` | `httpapi` | | `internal/store/`, `internal/repository/`, `internal/db/` | `store` | | `internal/jobs/` | `jobs` | | `internal/pipeline/` | `pipeline` | | `internal/birdfmt/` | `birdfmt` | | `internal/birddeploy/` | `birddeploy` | | `internal/bundle/`, `internal/signing/` | `bundle` | | `cmd/` | `cmd` | | `web/` | `web` | | `docs/openapi.yaml`, `redocly.yaml` | `openapi` | | `docs/` (остальное) | `docs` | | `migrations/` | `db` | | `.gitea/` | `ci` | | `deploy/` | `deploy` | | `.cursor/` | `chore` | | прочее в корне | `chore` | **Запрещено:** несколько scope через запятую (`refactor(web, httpapi): …`) — semantic-release не распознает `type`, релиз не будет (см. [docs/releasing.md](../../docs/releasing.md)). `type` определять по **содержимому diff**, не только по пути. ## Multi-change - Несвязанные области → **отдельные коммиты** (auto-split по скиллу). - Одна логическая фича через несколько scope (OpenAPI + httpapi + web) → **один** коммит, scope по главной области. ## Обязательный вывод агенту Для каждого коммита: **1. Готовое сообщение** (копировать в `git commit -m` / HEREDOC): ``` (): <тело RU> ``` **2. Пояснение (RU):** semver impact (`minor`|`patch`|`none`|`major`); почему выбран type; риск/impact; был ли split. ## Примеры ``` feat(httpapi): add version endpoint and wire web footer Добавлен GET /v1/version. В Web UI версия в footer берётся из API вместо захардкоженного значения. ``` ``` fix(auth): correct token validation edge case Исправлена ложная 401 при истёкшем refresh-токене с валидной сессией. ```