CI / openapi (push) Has been cancelled
CI / web (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / go (push) Has been cancelled
CI / bird2 (push) Has been cancelled
CI / commitlint (push) Has been cancelled
CI / release (push) Has been cancelled
181 lines
9.1 KiB
Plaintext
181 lines
9.1 KiB
Plaintext
---
|
||
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`.
|
||
|
||
## Формат (строго)
|
||
|
||
```
|
||
<type>(<scope>): <short summary in English>
|
||
|
||
<тело на русском: что изменено и зачем>
|
||
```
|
||
|
||
- **Заголовок** — только английский; императив, без точки в конце; ≤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):
|
||
|
||
```
|
||
<type>(<scope>): <summary>
|
||
|
||
<тело 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-токене с валидной сессией.
|
||
```
|