@rt-tools/agent-kit 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -30
- package/assets/agents/business-analyst.md +74 -0
- package/assets/agents/project-manager.md +70 -0
- package/assets/agents/qa-engineer.md +72 -0
- package/assets/agents/skill-curator.md +110 -0
- package/assets/agents/spec-critic.md +44 -0
- package/assets/agents/spec-writer.md +50 -0
- package/assets/checks/board.github.mjs +329 -0
- package/assets/checks/check-board.github.mjs +181 -0
- package/assets/checks/check-doc-paths.mjs +163 -0
- package/assets/checks/check-dupes.mjs +277 -0
- package/assets/checks/check-lib-layers.mjs +573 -0
- package/assets/checks/check-reuse.mjs +208 -0
- package/assets/checks/check-schema-drift.mjs +186 -0
- package/assets/checks/check-specs.mjs +1086 -0
- package/assets/checks/check-styles.mjs +109 -0
- package/assets/checks/rt-kit-checks.config.mjs +134 -0
- package/assets/checks/task-new.github.mjs +198 -0
- package/assets/commands/skill-curator.md +70 -0
- package/assets/defaults/gate-map.sh +106 -0
- package/assets/defaults/project.sh +204 -0
- package/assets/hooks/browser-device-id.sh +0 -0
- package/assets/hooks/browser-guard-device-id.sh +2 -1
- package/assets/hooks/browser-guard-no-asking.sh +27 -0
- package/assets/hooks/browser-guard-no-listing.sh +2 -1
- package/assets/hooks/browser-guard-no-other-drivers.sh +2 -1
- package/assets/hooks/browser-guard-require-select.sh +2 -1
- package/assets/hooks/commit-msg.sh +1 -1
- package/assets/hooks/constitution-index.sh +5 -4
- package/assets/hooks/dev-server-guard.sh +8 -6
- package/assets/hooks/docs-guard.sh +223 -37
- package/assets/hooks/git-guard-delivery.sh +171 -31
- package/assets/hooks/git-guard-main.sh +1 -0
- package/assets/hooks/git-guard-push-tests.sh +34 -13
- package/assets/hooks/glossary-load.sh +23 -0
- package/assets/hooks/grill-gate.sh +96 -0
- package/assets/hooks/lint-after-edit.sh +155 -30
- package/assets/hooks/qa-dataid-guard.sh +72 -32
- package/assets/hooks/reuse-first-guard.sh +105 -34
- package/assets/hooks/skill-gate-rearm.sh +1 -0
- package/assets/hooks/skill-gate.sh +75 -15
- package/assets/hooks/skill-loaded.sh +1 -0
- package/assets/hooks/sql-guard.sh +606 -56
- package/assets/hooks/task-context-load.sh +100 -0
- package/assets/hooks/task-flow-guard.sh +118 -0
- package/assets/laws/{access.md → application/access.md} +1 -4
- package/assets/laws/{locales.md → application/locales.md} +1 -3
- package/assets/laws/application/money.md +41 -0
- package/assets/laws/application/ownership.md +32 -0
- package/assets/laws/{search-visibility.md → application/search-visibility.md} +1 -1
- package/assets/laws/code-structure.md +7 -6
- package/assets/laws/delivery.md +53 -3
- package/assets/laws/entity-editing.md +49 -55
- package/assets/laws/entity-models.md +4 -14
- package/assets/laws/frontend-application.md +5 -5
- package/assets/laws/lib-imports.md +14 -1
- package/assets/laws/lists.md +33 -0
- package/assets/laws/navigation.md +40 -0
- package/assets/laws/project-documentation.md +27 -8
- package/assets/laws/reuse-first.md +26 -21
- package/assets/laws/shared-code.md +13 -1
- package/assets/laws/verifiability.md +30 -1
- package/assets/laws/work-conduct.md +59 -0
- package/assets/patterns/admin-lists-screen.md +131 -0
- package/assets/patterns/admin-nav-item.md +71 -0
- package/assets/patterns/angular-patterns-state.md +29 -22
- package/assets/patterns/api-layer-pair.md +40 -30
- package/assets/patterns/browser-verification-measure.md +41 -38
- package/assets/patterns/browser-verification-stand.md +106 -42
- package/assets/patterns/component-structure-new.md +33 -32
- package/assets/patterns/dependencies-upgrade.md +65 -0
- package/assets/patterns/doc-style-sweep.md +65 -28
- package/assets/patterns/doc-style-write.md +36 -33
- package/assets/patterns/entity-aside.md +136 -0
- package/assets/patterns/entity-models-new.md +124 -0
- package/assets/patterns/entity-store.md +91 -0
- package/assets/patterns/git-workflow-commit.azure.md +259 -0
- package/assets/patterns/git-workflow-commit.github.md +337 -0
- package/assets/patterns/git-workflow-commit.gitlab.md +283 -0
- package/assets/patterns/git-workflow-merge.md +42 -25
- package/assets/patterns/git-workflow-migration.md +61 -31
- package/assets/patterns/git-workflow-restart.md +20 -20
- package/assets/patterns/lib-layers-move.md +50 -32
- package/assets/patterns/lib-layers-new.md +41 -29
- package/assets/patterns/ownership-scope-resolve.md +69 -0
- package/assets/patterns/permissions-procedure.md +35 -33
- package/assets/patterns/platform-access-di.md +39 -25
- package/assets/patterns/pricing-quote.md +71 -0
- package/assets/patterns/reuse-first-extend.md +22 -22
- package/assets/patterns/seo-page.md +52 -40
- package/assets/patterns/seo-verify.md +48 -29
- package/assets/patterns/shared-code-new.md +37 -31
- package/assets/patterns/spec-driven-domain.md +60 -37
- package/assets/patterns/spec-driven-rule.md +55 -40
- package/assets/patterns/styling-bem-component.md +43 -32
- package/assets/patterns/styling-bem-layout.md +30 -24
- package/assets/patterns/task-flow-close.md +154 -0
- package/assets/patterns/task-flow-resume.md +94 -0
- package/assets/patterns/task-flow-start.md +129 -0
- package/assets/patterns/testing-e2e.md +53 -51
- package/assets/patterns/testing-unit.md +70 -46
- package/assets/patterns/translations-key.md +32 -19
- package/assets/patterns/ts-procedure.md +24 -25
- package/assets/rules/angular-patterns.md +50 -27
- package/assets/rules/api-layer.md +46 -28
- package/assets/rules/browser-verification.md +67 -48
- package/assets/rules/component-structure.md +43 -27
- package/assets/rules/dependencies.md +66 -0
- package/assets/rules/doc-style.md +95 -39
- package/assets/rules/entity-conventions.md +78 -0
- package/assets/rules/entity-models.md +70 -0
- package/assets/rules/git-workflow.azure.md +116 -0
- package/assets/rules/git-workflow.github.md +123 -0
- package/assets/rules/git-workflow.gitlab.md +113 -0
- package/assets/rules/lib-layers.md +56 -30
- package/assets/rules/lists.md +73 -0
- package/assets/rules/navigation.md +78 -0
- package/assets/rules/ownership-scope.md +63 -0
- package/assets/rules/permissions.md +43 -25
- package/assets/rules/platform-access.md +57 -29
- package/assets/rules/pricing.md +64 -0
- package/assets/rules/reuse-first.md +57 -43
- package/assets/rules/seo.md +51 -30
- package/assets/rules/shared-code.md +51 -26
- package/assets/rules/spec-driven.md +107 -51
- package/assets/rules/styling-bem.md +54 -39
- package/assets/rules/task-flow.md +150 -0
- package/assets/rules/testing.md +78 -47
- package/assets/rules/translations.md +48 -31
- package/assets/rules/typescript-conventions.md +57 -27
- package/assets/skills/agent-kit.md +85 -0
- package/assets/skills/write-a-skill.md +108 -0
- package/assets/templates/gate-map.sh +23 -15
- package/assets/templates/implementation.md +14 -8
- package/assets/templates/pattern.md +1 -1
- package/assets/templates/project.sh +32 -19
- package/assets/templates/rule.md +2 -2
- package/assets/variants.json +20 -0
- package/assets/workflows/feature.js +134 -0
- package/assets/workflows/plan.js +150 -0
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +78 -5
- package/bin/agent-kit.js.map +1 -1
- package/bin/prompt.d.ts +5 -0
- package/bin/prompt.d.ts.map +1 -1
- package/bin/prompt.js +19 -7
- package/bin/prompt.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/lib/assets.d.ts +8 -3
- package/lib/assets.d.ts.map +1 -1
- package/lib/assets.js +13 -3
- package/lib/assets.js.map +1 -1
- package/lib/catalog.d.ts +52 -5
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +104 -16
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts +22 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +202 -14
- package/lib/commands.js.map +1 -1
- package/lib/companion.d.ts +5 -1
- package/lib/companion.d.ts.map +1 -1
- package/lib/companion.js +29 -2
- package/lib/companion.js.map +1 -1
- package/lib/config.d.ts +26 -9
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +41 -15
- package/lib/config.js.map +1 -1
- package/lib/freshness.d.ts +14 -0
- package/lib/freshness.d.ts.map +1 -0
- package/lib/freshness.js +116 -0
- package/lib/freshness.js.map +1 -0
- package/lib/hooks-map.d.ts +27 -0
- package/lib/hooks-map.d.ts.map +1 -0
- package/lib/hooks-map.js +77 -0
- package/lib/hooks-map.js.map +1 -0
- package/lib/integrity.d.ts +36 -0
- package/lib/integrity.d.ts.map +1 -0
- package/lib/integrity.js +44 -0
- package/lib/integrity.js.map +1 -0
- package/lib/picker.d.ts +11 -1
- package/lib/picker.d.ts.map +1 -1
- package/lib/picker.js +44 -6
- package/lib/picker.js.map +1 -1
- package/lib/sync.d.ts +26 -0
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +59 -4
- package/lib/sync.js.map +1 -1
- package/lib/variants.d.ts +44 -0
- package/lib/variants.d.ts.map +1 -0
- package/lib/variants.js +82 -0
- package/lib/variants.js.map +1 -0
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.5.0.tgz +0 -0
- package/assets/laws/admin-lists.md +0 -35
- package/assets/laws/admin-navigation.md +0 -38
- package/assets/patterns/git-workflow-commit.md +0 -175
- package/assets/rules/git-workflow.md +0 -106
- package/rt-tools-agent-kit-0.3.0.tgz +0 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-workflow-commit
|
|
3
|
+
kind: pattern
|
|
4
|
+
rule: git-workflow
|
|
5
|
+
description: Паттерн правила git-workflow. Брать на заведение задачи, ветки, коммит, пуш и создание PR — готовая команда заведения задачи со всеми четырьмя шагами, перевод задачи в колонку работы и в колонку разбора, слияние двух задач в одну, сверка очереди работ, работа от учётной записи бота, формат заголовка, строка связи с задачей, ревьювер, исполнитель и метки PR, чеклист проверок до публикации, обход требования документа. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Ветка, коммит и PR
|
|
9
|
+
|
|
10
|
+
Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
|
|
11
|
+
`docs/constitution/delivery.md`.
|
|
12
|
+
|
|
13
|
+
## Когда брать
|
|
14
|
+
|
|
15
|
+
- Заводится задача, с которой начинается правка.
|
|
16
|
+
- Заводится ветка под задачу.
|
|
17
|
+
- Готовится коммит или пуш.
|
|
18
|
+
- Открывается PR.
|
|
19
|
+
- Работа перешла на следующий шаг, и задача переставляется в другую колонку борды.
|
|
20
|
+
|
|
21
|
+
## Сначала задача на борде, потом ветка
|
|
22
|
+
|
|
23
|
+
Заведение состоит из четырёх шагов: issue, номер в его заголовке, добавление на борду,
|
|
24
|
+
первая колонка. Борда к репозиторию не привязана — `projectsV2` у него пуст, — поэтому третий
|
|
25
|
+
шаг сам не случается, и задача без него не видна ни в очереди работ, ни владельцу: так две
|
|
26
|
+
задачи и простояли месяц.
|
|
27
|
+
|
|
28
|
+
Все четыре шага делает одна команда дерева, а не рука: делить их значит забывать третий.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm run task:new -- --title 'Письма владельцу не уходят молча' \
|
|
32
|
+
--label bug --label area:api --slug mail-owner-silence < описание.md
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Тело читается со стандартного ввода, `--slug` необязателен и идёт только в подсказку с именем
|
|
36
|
+
ветки. Автор и исполнитель — учётная запись машинной работы; токен команда читает сама, из
|
|
37
|
+
файла вне репозитория.
|
|
38
|
+
|
|
39
|
+
Скрипт под этой командой заводит проект — пакет её не везёт. Что он делает вызовами `gh`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
gh issue create --title '[<КЛЮЧ>-<номер>] …' --label bug --assignee <бот> --body-file -
|
|
43
|
+
gh issue edit <номер> --title '[<КЛЮЧ>-<номер>] …' # номер известен только после создания
|
|
44
|
+
gh project item-add <номер борды> --owner <владелец> --url <адрес issue>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Последний шаг и есть тот, который забывается: без него задача заведена, но её нет в очереди.
|
|
48
|
+
|
|
49
|
+
Название тикета говорит, что не так, а не что сделать: PR потом переводит его в сделанное.
|
|
50
|
+
Номер в заголовок руками не пишется — он известен только после создания, и команда дописывает
|
|
51
|
+
его сама.
|
|
52
|
+
|
|
53
|
+
Чем сверить, что очередь работ в порядке:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm run check:board
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Она смотрит только открытое: тикеты на борде, номер и исполнителя у каждой открытой задачи,
|
|
60
|
+
а у каждого открытого PR — номер в заголовке, строку `Closes`, открытую задачу за ним и то,
|
|
61
|
+
что второго PR с тем же номером нет. Имя ветки не судит: у открытого PR его не переименовать.
|
|
62
|
+
|
|
63
|
+
Закрытые задачи сверка на борде не ищет, и добавлять их туда задним числом не надо: закрытая
|
|
64
|
+
задача уходит из очереди мержем, а колонки под неё у борды нет. О закрытой задаче сверка
|
|
65
|
+
помнит только одно — её папку в `docs/tasks/`.
|
|
66
|
+
|
|
67
|
+
## Две задачи, которые чинятся одной правкой
|
|
68
|
+
|
|
69
|
+
Если по ходу выяснилось, что правка закрывает и соседнюю задачу, — это одна задача, а не две.
|
|
70
|
+
Слить их можно, пока правка не въехала в главную ветку:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
GH=/opt/homebrew/bin/gh
|
|
74
|
+
# то, чего в поглотившей задаче не было, дописывается в её тело
|
|
75
|
+
$GH api -X PATCH repos/<владелец>/<репозиторий>/issues/<поглотившая> -f body="$(cat тело.md)"
|
|
76
|
+
# поглощённая стирается вместе с номером — две строки об одной работе хуже дыры в нумерации
|
|
77
|
+
$GH api graphql -f query='mutation { deleteIssue(input: {issueId: "<node-id>"})
|
|
78
|
+
{ repository { name } } }'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Удаление необратимо и уносит с собой ссылки вида `Closes #<номер>` из чужих тел — поэтому
|
|
82
|
+
сначала правится поглотившая задача, и только потом стирается поглощённая. После мержа
|
|
83
|
+
поглощения нет: ветка въехала, и откатывается она целиком.
|
|
84
|
+
|
|
85
|
+
## Ветка заводится отдельным вызовом
|
|
86
|
+
|
|
87
|
+
Гард главной ветки разбирает текст команды и смотрит ветку на момент запуска, поэтому
|
|
88
|
+
составная команда отклоняется целиком — ветки в ней ещё нет:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
✗ git checkout -b <КЛЮЧ>-85-guest-token && git commit -m 'feat(admin): …'
|
|
92
|
+
✓ git checkout -b <КЛЮЧ>-85-guest-token
|
|
93
|
+
✓ git commit -F -
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Имя — `<КЛЮЧ>-<номер задачи>-<короткий-slug>`, slug строчными латинскими через дефис. Гард
|
|
97
|
+
поставки разбирает его на месте и отбивает промах в форме до первого коммита, а по номеру
|
|
98
|
+
спрашивает борду: задача должна существовать, быть открытой, стоять в очереди и иметь
|
|
99
|
+
исполнителя.
|
|
100
|
+
|
|
101
|
+
Имя без номера (`feat/…`, `fix/…`) законно, пока ветка живёт локально — под пробу и разбор.
|
|
102
|
+
PR с неё не откроется: правка, доезжающая до главной ветки, начинается с задачи.
|
|
103
|
+
|
|
104
|
+
## Колонка задачи двигается вместе с работой
|
|
105
|
+
|
|
106
|
+
Ветка заведена — задача уже не в `📋 Backlog`, а в работе. PR открыт — она ждёт разбора.
|
|
107
|
+
Оба перевода делает одна команда, вторым вызовом сразу за тем, который его вызвал:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm run task:move -- 86 in-progress # сразу после git checkout -b <КЛЮЧ>-86-…
|
|
111
|
+
npm run task:move -- 86 in-review # сразу после gh pr create
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Колонки под своими именами: `backlog`, `in-progress`, `in-review`, а ещё `new`, `ready`,
|
|
115
|
+
`done` и `deployed`, через которые работа не проходит — закрытая задача уходит из очереди
|
|
116
|
+
мержем. Команда правит борду под ботом, читает токен сама и печатает, откуда куда переставила;
|
|
117
|
+
задачи не на борде и незнакомой колонки не принимает.
|
|
118
|
+
|
|
119
|
+
Перевод не откладывается на потом: очередь работ читают между шагами, а не после них. Задача
|
|
120
|
+
с открытым PR простояла в `📋 Backlog` до самой сверки — всё это время она выглядела
|
|
121
|
+
нетронутой, а разбора за неё никто не ждал.
|
|
122
|
+
|
|
123
|
+
## Коммит подписывается ботом
|
|
124
|
+
|
|
125
|
+
Токен читается в переменную и не печатается; автор и коммиттер задаются переменными той же
|
|
126
|
+
команды. `git config` не годится — конфиг общий с основным деревом и переписал бы подпись
|
|
127
|
+
владельцу:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
TOKEN=$(tr -d '\n' < ~/.config/<дерево>-bot-token)
|
|
131
|
+
|
|
132
|
+
GIT_AUTHOR_NAME="<бот>" GIT_AUTHOR_EMAIL="<номер>+<бот>@users.noreply.github.com" \
|
|
133
|
+
GIT_COMMITTER_NAME="<бот>" GIT_COMMITTER_EMAIL="<номер>+<бот>@users.noreply.github.com" \
|
|
134
|
+
git commit -F -
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Заголовок — `type(scope): description`. Типы: `feat`, `fix`, `refactor`, `docs`, `style`,
|
|
138
|
+
`test`, `chore`, `perf`. Области: `site`, `admin`, `api`, `common`, `proto`, `deploy`. Точка в
|
|
139
|
+
конце заголовка не принимается, длина — до 150 знаков.
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
feat(site): availability calendar with season prices
|
|
143
|
+
fix(api): reject overlapping booking dates
|
|
144
|
+
chore(deploy): docker-compose for vps
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Документ едет тем же коммитом
|
|
148
|
+
|
|
149
|
+
`docs-guard` требует пару и называет её сам. Обход — строка в теле, причина обязательна:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
Docs-skip: правка только в тестах хука, зеркала у него нет
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Номер задачи стоит в её заголовке и в заголовке PR
|
|
156
|
+
|
|
157
|
+
Форма одна на оба — `[<КЛЮЧ>-<номер>] <текст>`. Номер стоит в самом заголовке, а не только в
|
|
158
|
+
теле: в списке PR тела не видно, а в списке задач номер иначе приходится искать глазами по
|
|
159
|
+
колонке слева. Тот же номер несёт и имя ветки — `<КЛЮЧ>-<номер>-<короткий-slug>`, — поэтому
|
|
160
|
+
задача, ветка и PR читаются как одно.
|
|
161
|
+
|
|
162
|
+
Задача говорит, что не так; PR тем же номером отчитывается, что сделано:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
задача [<КЛЮЧ>-86] Пустой MAIL_OWNER — письма владельцу не уходят молча
|
|
166
|
+
PR [<КЛЮЧ>-86] Письмо владельцу с незаполненным адресом попадает в логи
|
|
167
|
+
|
|
168
|
+
задача [<КЛЮЧ>-101] Вернуть оверлей загрузки таблицы и включить stylelint гейтом
|
|
169
|
+
PR [<КЛЮЧ>-101] Stylelint включён гейтом
|
|
170
|
+
|
|
171
|
+
задача [<КЛЮЧ>-212] Сайт не собирается: компонентам кита проставлен префикс vm- вместо rt-
|
|
172
|
+
PR [<КЛЮЧ>-212] Виджет переписки зовёт кит его собственными именами
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Инфинитив из задачи в заголовок PR не переносится: «исправить» становится «исправлено»,
|
|
176
|
+
«вернуть» — «возвращено», «добавить» — «добавлено».
|
|
177
|
+
|
|
178
|
+
Номер в заголовке обязан совпасть с номером ветки: гард поставки сверяет их до отправки
|
|
179
|
+
команды, а сверка очереди — у каждого открытого PR.
|
|
180
|
+
|
|
181
|
+
Тип и область — `fix(site):`, `docs(common):` — в заголовок PR не идут: это формат заголовка
|
|
182
|
+
коммита, и там его сверяет `commitlint`. В списке PR он занимает место, ничего не добавляя:
|
|
183
|
+
род правки и область уже видны метками.
|
|
184
|
+
|
|
185
|
+
## PR прикрепляется к задаче
|
|
186
|
+
|
|
187
|
+
Тело начинается со строки связи — по ней на борде заполняется поле «Linked pull requests».
|
|
188
|
+
Ревьювер, исполнитель и метки задаются той же командой, и PR без них не открывается:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
GH_TOKEN="$TOKEN" gh pr create --title '[<КЛЮЧ>-86] Письмо владельцу с незаполненным адресом попадает в логи' \
|
|
192
|
+
--reviewer <владелец> --assignee <бот> --label bug --label area:api \
|
|
193
|
+
--body 'Closes #86
|
|
194
|
+
|
|
195
|
+
…'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Ревьювер — всегда владелец: без запроса разбора PR не показывается ему в очереди. Исполнитель —
|
|
199
|
+
та же учётная запись, от которой идёт машинная работа. Метки берутся у задачи целиком — и род
|
|
200
|
+
правки, и все её области; читаются они у задачи, а не выбираются по памяти:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
/opt/homebrew/bin/gh issue view 86 --json labels --jq '.labels | map(.name) | join(",")'
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Строка `Closes #<номер>` обязательна: без неё PR не прикрепляется к задаче, и сверка очереди
|
|
207
|
+
это находит. Она же и означает, что задача закрывается целиком — половину задачи одним PR не
|
|
208
|
+
выкатывают: у задачи одна ветка, и работа, которая в неё не влезает, делится на задачи до
|
|
209
|
+
того, как ветка заводится.
|
|
210
|
+
|
|
211
|
+
У уже открытого PR то же ставится тремя вызовами REST. `gh pr edit` здесь не годится: он
|
|
212
|
+
запрашивает карточки Projects (classic), получает отказ о снятом API и до правки не доходит.
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
GH=/opt/homebrew/bin/gh
|
|
216
|
+
REPO=<владелец>/<репозиторий>
|
|
217
|
+
|
|
218
|
+
$GH api -X POST "repos/$REPO/issues/205/labels" -f 'labels[]=bug' -f 'labels[]=area:api'
|
|
219
|
+
$GH api -X POST "repos/$REPO/issues/205/assignees" -f 'assignees[]=<бот>'
|
|
220
|
+
$GH api -X POST "repos/$REPO/pulls/205/requested_reviewers" -f 'reviewers[]=<владелец>'
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Тем же вызовом правится и само тело: `-f body=` переписывает его целиком, поэтому строка
|
|
224
|
+
`Closes #<номер>` пишется заново вместе с остальным текстом.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
$GH api -X PATCH "repos/$REPO/pulls/205" -f body="$(cat тело.md)"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Тело перечитывается всякий раз, когда в ветку что-то влилось после публикации: отчёт
|
|
231
|
+
утверждает про дерево, а дерево с тех пор изменилось.
|
|
232
|
+
|
|
233
|
+
## Состояние PR читается, а не додумывается
|
|
234
|
+
|
|
235
|
+
Вызовы, которыми ставятся ревьювер, метки и исполнитель, отвечают нулевым кодом и тогда, когда
|
|
236
|
+
ничего не сделали: запрос разбора на автора PR GitHub молча выбрасывает. Поэтому после них PR
|
|
237
|
+
перечитывают:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Ключи латиницей: кириллический ключ без кавычек `jq` не разбирает и падает на нём
|
|
241
|
+
$GH api "repos/$REPO/pulls/321" \
|
|
242
|
+
--jq '{author: .user.login, reviewers: [.requested_reviewers[].login], labels: [.labels[].name]}'
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Автор здесь — `<бот>`. Если им оказался владелец, ревьювера у PR не будет вовсе:
|
|
246
|
+
назначить автора ревьювером нельзя, а отказа на такой запрос не приходит. Владельцу называют
|
|
247
|
+
то, что прочитали, а не то, что заказывали.
|
|
248
|
+
|
|
249
|
+
Учётная запись, из-под которой пришлось пушить, в этот вызов не переносится: пуш и авторство
|
|
250
|
+
PR выбираются отдельно, и `GH_TOKEN` для публикации — всегда токен бота.
|
|
251
|
+
|
|
252
|
+
Открытый PR означает, что задача ждёт разбора, — колонка переставляется тем же движением:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
npm run task:move -- 86 in-review
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Голым GraphQL по идентификаторам проекта, элемента и варианта поля это не пишется: команда
|
|
259
|
+
знает их сама, а собранный по памяти запрос молча ставит не ту колонку — отказа у борды на
|
|
260
|
+
это нет.
|
|
261
|
+
|
|
262
|
+
## Что проверяется до публикации PR
|
|
263
|
+
|
|
264
|
+
Проверок на самом PR нет: выкатка запускается пушем в главную ветку, и до мержа никто не
|
|
265
|
+
гоняет ничего. Линтеры, юниты и сценарии хуков снимает гейт пуша — ниже то, чего он не знает.
|
|
266
|
+
|
|
267
|
+
1. **В ветке только та правка, за которой её заводили** — `git diff main...HEAD --stat`. Чужой
|
|
268
|
+
домен в списке файлов означает, что правка расползлась, и её надо вернуть в свои границы.
|
|
269
|
+
2. **Ни мока, ни подменённого ответа, ни отладочной строки** — `git diff main...HEAD` читается
|
|
270
|
+
целиком, а не по именам файлов. На прод они уезжают молча и портят настоящие данные.
|
|
271
|
+
3. **Документ едет тем же коммитом.** Пару называет `docs-guard`, но спек домена и правку его
|
|
272
|
+
поведения он не знает — это остаётся за автором.
|
|
273
|
+
4. **Проверки текстов и раскладки зелёные** — те, что дерево завело в `tools/`: сверка
|
|
274
|
+
сценариев с тестами, путей в документах, раскладки либ, повторов и классов без правила.
|
|
275
|
+
Какие именно есть здесь — `implementation.md` правила.
|
|
276
|
+
5. **Все приложения дерева собираются** — `nx build` по каждому. Гейт пуша сборку не гоняет:
|
|
277
|
+
она длиннее всего, что он успевает сделать между командой и пушем.
|
|
278
|
+
6. **Видимый текст заведён во всех локалях перевода** — тестом полноты словарей, если дерево
|
|
279
|
+
переводится.
|
|
280
|
+
7. **Правка вёрстки подтверждена замером**, а не взглядом, и снята при узком экране — паттерн
|
|
281
|
+
`browser-verification-measure`.
|
|
282
|
+
8. **Правка разметки публичного сайта проверена на прод-сборке по всем локалям перевода** — паттерн
|
|
283
|
+
`seo-verify`.
|
|
284
|
+
9. **Тело PR начинается строкой `Closes #<номер>`**, а метки, ревьювер и исполнитель стоят.
|
|
285
|
+
10. **Заголовок PR несёт номер задачи и называет её сделанной:** `[<КЛЮЧ>-<номер>] <Что сделано>`,
|
|
286
|
+
тем же номером, что стоит у задачи и в имени ветки. Инфинитив из задачи в него не
|
|
287
|
+
переносится, тип и область коммита — тоже.
|
|
288
|
+
11. **Очередь работ сходится** — `npm run check:board`. Задача на борде, с исполнителем и
|
|
289
|
+
номером в заголовке; PR один на задачу, и закрывает он её целиком.
|
|
290
|
+
12. **Состояние PR прочитано, а не выведено из кодов возврата** — автор `<бот>`,
|
|
291
|
+
ревьювер — владелец, метки те же, что у задачи. Владельцу называют прочитанное.
|
|
292
|
+
|
|
293
|
+
Сразу после публикации задача переставляется в разбор — `npm run task:move -- <номер>
|
|
294
|
+
in-review`, — и `npm run check:board` прогоняется ещё раз: до открытия PR колонку он не судит,
|
|
295
|
+
а после открытия расхождение видит.
|
|
296
|
+
|
|
297
|
+
Сделанное рассуждением и сделанное замером в теле PR разводятся прямо: непроверенное,
|
|
298
|
+
названное проверенным, ревьювер принимает за проверенное.
|
|
299
|
+
|
|
300
|
+
## Частые промахи
|
|
301
|
+
|
|
302
|
+
- `gh` в оболочке пользователя подменён — звать `/opt/homebrew/bin/gh` напрямую.
|
|
303
|
+
- `git add` с несколькими путями не добавляет ничего, если хоть один путь не существует:
|
|
304
|
+
команда обрывается на первом промахе целиком, а не пропускает его. Следующий
|
|
305
|
+
`git commit --amend` при этом уносит в коммит всё, что осталось в индексе, — так в коммит
|
|
306
|
+
уехало удаление файла, принадлежавшее соседней ветке. Состав коммита читается
|
|
307
|
+
`git show --stat` сразу после него, а не на разборе PR.
|
|
308
|
+
- Состав индекса читается `git diff --cached --stat` **до** коммита, а не только `git show --stat`
|
|
309
|
+
после него. Команды дерева кладут файлы в индекс сами: `npm run task:new` добавляет папку
|
|
310
|
+
задачи, и вместе с ней уезжает всё, что лежало рядом, — так в индексе оказался временный
|
|
311
|
+
каталог диагностики.
|
|
312
|
+
- `gh project` с `--owner` отвечает `unknown owner type`: владелец борды — другая учётная
|
|
313
|
+
запись, и правка идёт только через GraphQL.
|
|
314
|
+
- Заведённый тикет на борду сама она не забирает: репозиторий с ней не связан, и добавление
|
|
315
|
+
идёт отдельным вызовом. Два тикета так и остались вне очереди работ — поэтому все четыре
|
|
316
|
+
шага и делает `npm run task:new`, а не рука.
|
|
317
|
+
- Исполнитель у задачи не проставляется сам ни при заведении через веб, ни при добавлении на
|
|
318
|
+
борду: из девяноста девяти открытых задач он стоял у двух.
|
|
319
|
+
- Задача, заведённая через веб, мимо команды, на борду не попадает и гардом не отбивается —
|
|
320
|
+
он смотрит команду, а не тикет. Ловится это только сверкой очереди.
|
|
321
|
+
- Колонка задачи сама не двигается ни от заведения ветки, ни от открытия PR: борда ветки не
|
|
322
|
+
видит вовсе, а связь с PR заполняет только поле «Linked pull requests». Взятие в работу не
|
|
323
|
+
ловит и сверка — ей ветка тоже не видна.
|
|
324
|
+
- `gh api graphql --paginate` на запросе элементов борды уходит в повтор первой страницы:
|
|
325
|
+
курсор берётся из ответа руками, а полнота сверяется с `items(first: 1) { totalCount }`.
|
|
326
|
+
- Второй строкой `Closes` в одном PR задача больше не закрывается: две задачи в одной ветке
|
|
327
|
+
откатываются только вместе. Либо это одна задача — и вторая поглощается, — либо две ветки.
|
|
328
|
+
- Половина задачи, уехавшая своим PR, тоже промах: тело такого PR начинается со слов «Часть
|
|
329
|
+
#<номер>» вместо `Closes`, задача остаётся открытой, и после отката видно её целой. Работа,
|
|
330
|
+
которая в одну ветку не влезает, делится на задачи до того, как ветка заводится.
|
|
331
|
+
- PR открыт без ревьювера: он не попадает во входящие владельца вовсе, и очередь стоит,
|
|
332
|
+
выглядя работающей. Так шестнадцать PR ждали разбора, которого никто не запрашивал.
|
|
333
|
+
- Метки поставлены по названию PR, а не прочитаны у задачи: область теряется, и по борде не
|
|
334
|
+
видно, что правка задела ещё и сайт.
|
|
335
|
+
- Задача закрыта не полностью, а метки перенесены целиком: тикет остаётся открытым, и это
|
|
336
|
+
говорится в теле PR, а не подразумевается строкой `Closes`.
|
|
337
|
+
- Правка владельца ни токена, ни переменных не берёт — они только для машинной работы.
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-workflow-commit
|
|
3
|
+
kind: pattern
|
|
4
|
+
rule: git-workflow
|
|
5
|
+
description: Паттерн правила git-workflow для дерева на GitLab. Брать на заведение задачи, ветки, коммит, пуш и создание MR — заведение задачи со всеми шагами, перевод по спискам доски, слияние двух задач в одну, сверка очереди работ, работа от учётной записи машинной работы, формат заголовка, строка связи с задачей, ревьювер, исполнитель и метки MR, чеклист проверок до публикации, обход требования документа. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Ветка, коммит и MR
|
|
9
|
+
|
|
10
|
+
Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
|
|
11
|
+
`docs/constitution/delivery.md`.
|
|
12
|
+
|
|
13
|
+
## Когда брать
|
|
14
|
+
|
|
15
|
+
- Заводится задача, с которой начинается правка.
|
|
16
|
+
- Заводится ветка под задачу.
|
|
17
|
+
- Готовится коммит или пуш.
|
|
18
|
+
- Открывается MR.
|
|
19
|
+
- Работа перешла на следующий шаг, и задача переставляется в другой список доски.
|
|
20
|
+
|
|
21
|
+
## Сначала задача на доске, потом ветка
|
|
22
|
+
|
|
23
|
+
Заведение состоит из четырёх шагов: issue, номер в его заголовке, исполнитель, метка первого
|
|
24
|
+
списка доски. Доска показывает те issue, чью метку знает, — поэтому четвёртый шаг сам не
|
|
25
|
+
случается, и задача без него заведена, но в очереди работ её нет.
|
|
26
|
+
|
|
27
|
+
Все четыре делает одна команда дерева, а не рука: делить их значит забывать последний.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run task:new -- --title 'Письма владельцу не уходят молча' \
|
|
31
|
+
--label bug --label area:api --slug mail-owner-silence < описание.md
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Тело читается со стандартного ввода, `--slug` необязателен и идёт только в подсказку с именем
|
|
35
|
+
ветки. Автор и исполнитель — учётная запись машинной работы; токен команда читает сама, из
|
|
36
|
+
файла вне репозитория.
|
|
37
|
+
|
|
38
|
+
Скрипт под этой командой заводит проект — пакет её не везёт. Что он делает вызовами `glab`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
glab issue create --title '[<КЛЮЧ>-<номер>] …' --label bug --label 'status::backlog' \
|
|
42
|
+
--assignee <бот> --description-file -
|
|
43
|
+
glab issue update <номер> --title '[<КЛЮЧ>-<номер>] …' # номер известен только после создания
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Метка списка ставится при заведении, а не после: issue без неё лежит вне доски, и увидеть её
|
|
47
|
+
можно только поиском по проекту.
|
|
48
|
+
|
|
49
|
+
Чем сверить, что очередь работ в порядке:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm run check:board
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Она смотрит только открытое: метку списка, номер и исполнителя у каждой открытой задачи, а у
|
|
56
|
+
каждого открытого MR — номер в заголовке, строку `Closes`, открытую задачу за ним и то, что
|
|
57
|
+
второго MR с тем же номером нет. Имя ветки не судит: у открытого MR его не переименовать.
|
|
58
|
+
|
|
59
|
+
## Две задачи, которые чинятся одной правкой
|
|
60
|
+
|
|
61
|
+
Если по ходу выяснилось, что правка закрывает и соседнюю задачу, — это одна задача, а не две.
|
|
62
|
+
Слить их можно, пока правка не въехала в главную ветку:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# то, чего в поглотившей задаче не было, дописывается в её описание
|
|
66
|
+
glab issue update <поглотившая> --description "$(cat тело.md)"
|
|
67
|
+
# поглощённая закрывается как дубликат, со ссылкой на поглотившую
|
|
68
|
+
glab issue note <поглощённая> --message 'Дубликат #<поглотившая>: чинится той же правкой.'
|
|
69
|
+
glab issue close <поглощённая>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Закрытая как дубликат уходит из очереди работ, а её номер остаётся в истории — этим GitLab
|
|
73
|
+
отличается от хостингов, где задачу можно стереть. Ссылка на поглотившую обязательна: без неё
|
|
74
|
+
закрытая задача читается как сделанная, а сделана она не была.
|
|
75
|
+
|
|
76
|
+
После слияния ветки поглощения нет: она въехала, и откатывается целиком.
|
|
77
|
+
|
|
78
|
+
## Ветка заводится отдельным вызовом
|
|
79
|
+
|
|
80
|
+
Гард главной ветки разбирает текст команды и смотрит ветку на момент запуска, поэтому
|
|
81
|
+
составная команда отклоняется целиком — ветки в ней ещё нет:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
✗ git checkout -b <КЛЮЧ>-85-guest-token && git commit -m 'feat(admin): …'
|
|
85
|
+
✓ git checkout -b <КЛЮЧ>-85-guest-token
|
|
86
|
+
✓ git commit -F -
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Имя — `<КЛЮЧ>-<номер задачи>-<короткий-slug>`, slug строчными латинскими через дефис. Гард
|
|
90
|
+
поставки разбирает его на месте и отбивает промах в форме до первого коммита, а по номеру
|
|
91
|
+
спрашивает доску: задача должна существовать, быть открытой, стоять в очереди и иметь
|
|
92
|
+
исполнителя.
|
|
93
|
+
|
|
94
|
+
Имя без номера (`feat/…`, `fix/…`) законно, пока ветка живёт локально — под пробу и разбор.
|
|
95
|
+
MR с неё не откроется: правка, доезжающая до главной ветки, начинается с задачи.
|
|
96
|
+
|
|
97
|
+
## Список задачи двигается вместе с работой
|
|
98
|
+
|
|
99
|
+
Ветка заведена — задача уже не в первом списке, а в работе. MR открыт — она ждёт разбора.
|
|
100
|
+
Оба перевода делает одна команда, вторым вызовом сразу за тем, который его вызвал:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm run task:move -- 86 in-progress # сразу после git checkout -b <КЛЮЧ>-86-…
|
|
104
|
+
npm run task:move -- 86 in-review # сразу после glab mr create
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Списки доски — это метки, поэтому перевод обязан снять прежнюю:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
glab issue update 86 --label 'status::in-progress' --unlabel 'status::backlog'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Перевод, не снявший прежнюю метку, оставляет задачу в двух списках сразу, и очередь читается
|
|
114
|
+
неверно — в обоих местах она выглядит настоящей.
|
|
115
|
+
|
|
116
|
+
Перевод не откладывается на потом: очередь работ читают между шагами, а не после них.
|
|
117
|
+
|
|
118
|
+
## Коммит подписывается учётной записью машинной работы
|
|
119
|
+
|
|
120
|
+
Токен читается в переменную и не печатается; автор и коммиттер задаются переменными той же
|
|
121
|
+
команды. `git config` не годится — конфиг общий с основным деревом и переписал бы подпись
|
|
122
|
+
владельцу:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
TOKEN=$(tr -d '\n' < ~/.config/<дерево>-bot-token)
|
|
126
|
+
|
|
127
|
+
GIT_AUTHOR_NAME="<бот>" GIT_AUTHOR_EMAIL="<почта бота>" \
|
|
128
|
+
GIT_COMMITTER_NAME="<бот>" GIT_COMMITTER_EMAIL="<почта бота>" \
|
|
129
|
+
git commit -F -
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Заголовок — `type(scope): description`. Типы: `feat`, `fix`, `refactor`, `docs`, `style`,
|
|
133
|
+
`test`, `chore`, `perf`. Области — свои у дерева, они перечислены в `implementation.md`. Точка
|
|
134
|
+
в конце заголовка не принимается.
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
feat(site): availability calendar with season prices
|
|
138
|
+
fix(api): reject overlapping booking dates
|
|
139
|
+
chore(deploy): docker-compose for vps
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Документ едет тем же коммитом
|
|
143
|
+
|
|
144
|
+
`docs-guard` требует пару и называет её сам. Обход — строка в теле, причина обязательна:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
Docs-skip: правка только в тестах хука, зеркала у него нет
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Номер задачи стоит в её заголовке и в заголовке MR
|
|
151
|
+
|
|
152
|
+
Форма одна на оба — `[<КЛЮЧ>-<номер>] <текст>`. Номер стоит в самом заголовке, а не только в
|
|
153
|
+
теле: в списке MR тела не видно, а в списке задач номер иначе приходится искать глазами. Тот же
|
|
154
|
+
номер несёт и имя ветки, поэтому задача, ветка и MR читаются как одно.
|
|
155
|
+
|
|
156
|
+
Задача говорит, что не так; MR тем же номером отчитывается, что сделано:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
задача [<КЛЮЧ>-86] Пустой адрес владельца — письма не уходят молча
|
|
160
|
+
MR [<КЛЮЧ>-86] Письмо владельцу с незаполненным адресом попадает в логи
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Инфинитив из задачи в заголовок MR не переносится: «исправить» становится «исправлено»,
|
|
164
|
+
«вернуть» — «возвращено», «добавить» — «добавлено».
|
|
165
|
+
|
|
166
|
+
Тип и область — `fix(site):`, `docs(common):` — в заголовок MR не идут: это формат заголовка
|
|
167
|
+
коммита, и там его сверяет `commitlint`. В списке MR он занимает место, ничего не добавляя:
|
|
168
|
+
род правки и область уже видны метками.
|
|
169
|
+
|
|
170
|
+
## MR прикрепляется к задаче
|
|
171
|
+
|
|
172
|
+
Описание начинается со строки связи. Ревьювер, исполнитель и метки задаются той же командой, и
|
|
173
|
+
MR без них не открывается:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
GITLAB_TOKEN="$TOKEN" glab mr create \
|
|
177
|
+
--title '[<КЛЮЧ>-86] Письмо владельцу с незаполненным адресом попадает в логи' \
|
|
178
|
+
--assignee <бот> --reviewer <владелец> --label bug --label area:api \
|
|
179
|
+
--target-branch main --remove-source-branch \
|
|
180
|
+
--description 'Closes #86
|
|
181
|
+
|
|
182
|
+
…'
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Ревьювер — всегда владелец: без запроса разбора MR не показывается ему в очереди. Исполнитель —
|
|
186
|
+
та же учётная запись, от которой идёт машинная работа. Метки читаются у задачи, а не выбираются
|
|
187
|
+
по памяти:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
glab issue view 86 --output json | jq -r '[.labels[]] | join(",")'
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Строка `Closes #<номер>` обязательна: без неё MR не прикрепляется к задаче, и сверка очереди
|
|
194
|
+
это находит. Она же означает, что задача закрывается целиком — половину задачи одним MR не
|
|
195
|
+
выкатывают: у задачи одна ветка, и работа, которая в неё не влезает, делится на задачи до того,
|
|
196
|
+
как ветка заводится.
|
|
197
|
+
|
|
198
|
+
У уже открытого MR то же ставится правкой:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
glab mr update 205 --label bug --label area:api --assignee <бот> --reviewer <владелец>
|
|
202
|
+
glab mr update 205 --description "$(cat тело.md)"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Правка описания переписывает его целиком, поэтому строка `Closes #<номер>` пишется заново
|
|
206
|
+
вместе с остальным текстом. Тело перечитывается всякий раз, когда в ветку что-то влилось после
|
|
207
|
+
публикации: отчёт утверждает про дерево, а дерево с тех пор изменилось.
|
|
208
|
+
|
|
209
|
+
## Состояние MR читается, а не додумывается
|
|
210
|
+
|
|
211
|
+
Команды правки отвечают нулевым кодом и тогда, когда ничего не сделали: токен без права на
|
|
212
|
+
проект молча не ставит ни метку, ни ревьювера. Поэтому после них MR перечитывают:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
glab mr view 205 --output json \
|
|
216
|
+
| jq '{author: .author.username, reviewers: [.reviewers[].username], labels: .labels}'
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Владельцу называют то, что прочитали, а не то, что заказывали.
|
|
220
|
+
|
|
221
|
+
Учётная запись, из-под которой пришлось пушить, в этот вызов не переносится: пуш и авторство
|
|
222
|
+
MR выбираются отдельно, и токен для публикации — всегда токен машинной работы.
|
|
223
|
+
|
|
224
|
+
Открытый MR означает, что задача ждёт разбора, — список переставляется тем же движением:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
npm run task:move -- 86 in-review
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Что проверяется до публикации MR
|
|
231
|
+
|
|
232
|
+
Проверок на самом MR нет ровно до тех пор, пока конвейер не запущен, а запускается он пушем.
|
|
233
|
+
Линтеры, юниты и сценарии хуков снимает гейт пуша — ниже то, чего он не знает.
|
|
234
|
+
|
|
235
|
+
1. **В ветке только та правка, за которой её заводили** — `git diff main...HEAD --stat`. Чужой
|
|
236
|
+
домен в списке файлов означает, что правка расползлась, и её надо вернуть в свои границы.
|
|
237
|
+
2. **Ни мока, ни подменённого ответа, ни отладочной строки** — `git diff main...HEAD` читается
|
|
238
|
+
целиком, а не по именам файлов. На прод они уезжают молча и портят настоящие данные.
|
|
239
|
+
3. **Документ едет тем же коммитом.** Пару называет `docs-guard`, но спек домена и правку его
|
|
240
|
+
поведения он не знает — это остаётся за автором.
|
|
241
|
+
4. **Проверки текстов и раскладки зелёные** — те, что дерево завело в `tools/`. Какие именно
|
|
242
|
+
есть здесь — `implementation.md` правила.
|
|
243
|
+
5. **Все приложения дерева собираются** — `nx build` по каждому. Гейт пуша сборку не гоняет.
|
|
244
|
+
6. **Видимый текст заведён во всех локалях перевода** — тестом полноты словарей, если дерево
|
|
245
|
+
переводится.
|
|
246
|
+
7. **Правка вёрстки подтверждена замером**, а не взглядом, и снята при узком экране — паттерн
|
|
247
|
+
`browser-verification-measure`.
|
|
248
|
+
8. **Правка разметки публичного сайта проверена на прод-сборке по всем локалям перевода** —
|
|
249
|
+
паттерн `seo-verify`.
|
|
250
|
+
9. **Описание MR начинается строкой `Closes #<номер>`**, а метки, ревьювер и исполнитель стоят.
|
|
251
|
+
10. **Заголовок MR несёт номер задачи и называет её сделанной:** `[<КЛЮЧ>-<номер>] <Что
|
|
252
|
+
сделано>`, тем же номером, что стоит у задачи и в имени ветки.
|
|
253
|
+
11. **Очередь работ сходится** — `npm run check:board`.
|
|
254
|
+
12. **Состояние MR прочитано, а не выведено из кодов возврата.**
|
|
255
|
+
|
|
256
|
+
Сразу после публикации задача переставляется в разбор, и сверка очереди прогоняется ещё раз: до
|
|
257
|
+
открытия MR список она не судит, а после открытия расхождение видит.
|
|
258
|
+
|
|
259
|
+
Сделанное рассуждением и сделанное замером в теле MR разводятся прямо: непроверенное,
|
|
260
|
+
названное проверенным, ревьювер принимает за проверенное.
|
|
261
|
+
|
|
262
|
+
## Частые промахи
|
|
263
|
+
|
|
264
|
+
- Метка списка не поставлена при заведении: задача есть, а на доске её нет. Доска показывает
|
|
265
|
+
только то, чью метку знает.
|
|
266
|
+
- Перевод по списку не снял прежнюю метку: задача стоит в двух списках сразу.
|
|
267
|
+
- `glab` не видит проект: у токена область `read_api` вместо `api`. Команды правки при этом
|
|
268
|
+
отвечают успехом и не делают ничего.
|
|
269
|
+
- `git add` с несколькими путями не добавляет ничего, если хоть один путь не существует:
|
|
270
|
+
команда обрывается на первом промахе целиком. Следующий `git commit --amend` при этом уносит
|
|
271
|
+
в коммит всё, что осталось в индексе. Состав коммита читается `git show --stat` сразу после
|
|
272
|
+
него, а не на разборе MR.
|
|
273
|
+
- MR открыт без ревьювера: он не попадает во входящие владельца, и очередь стоит, выглядя
|
|
274
|
+
работающей.
|
|
275
|
+
- Метки поставлены по названию MR, а не прочитаны у задачи: область теряется, и по доске не
|
|
276
|
+
видно, что правка задела ещё и соседний домен.
|
|
277
|
+
- Вторая строка `Closes` в одном MR: две задачи в одной ветке откатываются только вместе. Либо
|
|
278
|
+
это одна задача — и вторая поглощается, — либо две ветки.
|
|
279
|
+
- Половина задачи, уехавшая своим MR: описание такого MR начинается со слов «Часть #<номер>»
|
|
280
|
+
вместо `Closes`, задача остаётся открытой, и после отката видно её целой.
|
|
281
|
+
- `--remove-source-branch` забыт: ветки задач копятся в репозитории, и по списку веток больше
|
|
282
|
+
не видно, какая работа идёт сейчас.
|
|
283
|
+
- Правка владельца ни токена, ни переменных не берёт — они только для машинной работы.
|