@rt-tools/agent-kit 0.16.1 → 0.18.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/assets/checks/board-epics.github.mjs +123 -0
- package/assets/checks/board-gh.github.mjs +121 -0
- package/assets/checks/board-paths.github.mjs +88 -0
- package/assets/checks/board-runs.github.mjs +8 -0
- package/assets/checks/board-titles.github.mjs +66 -0
- package/assets/checks/board.github.mjs +77 -73
- package/assets/checks/check-board.github.mjs +56 -7
- package/assets/checks/check-file-size.mjs +10 -2
- package/assets/checks/check-glossary.mjs +170 -0
- package/assets/checks/check-hook-scope.mjs +126 -0
- package/assets/checks/check-profile-drift.mjs +195 -0
- package/assets/checks/check-push-gate.mjs +59 -1
- package/assets/checks/check-schema-drift.mjs +12 -5
- package/assets/checks/check-specs.mjs +1 -1
- package/assets/checks/rt-kit-checks.config.mjs +13 -0
- package/assets/checks/spec-anchors.mjs +2 -2
- package/assets/checks/spec-contract.mjs +9 -0
- package/assets/defaults/gate-map.sh +13 -4
- package/assets/defaults/project.sh +31 -108
- package/assets/defaults/shell.sh +139 -0
- package/assets/docs/GLOSSARY.md +1 -1
- package/assets/hooks/browser-device-id.sh +20 -4
- package/assets/hooks/browser-guard-device-id.sh +5 -2
- package/assets/hooks/browser-guard-no-other-drivers.sh +41 -2
- package/assets/hooks/claim-guard.sh +22 -1
- package/assets/hooks/docs-guard.sh +1 -1
- package/assets/hooks/exam-guard.sh +85 -12
- package/assets/hooks/git-guard-delivery-conflict.sh +85 -0
- package/assets/hooks/git-guard-delivery-folder.sh +19 -0
- package/assets/hooks/git-guard-delivery-signature.sh +14 -5
- package/assets/hooks/git-guard-delivery.sh +54 -2
- package/assets/hooks/git-guard-push-tests.sh +21 -1
- package/assets/hooks/grill-gate-ask.sh +25 -0
- package/assets/hooks/grill-gate.sh +75 -11
- package/assets/hooks/lint-after-edit.sh +44 -16
- package/assets/hooks/proposal-guard.sh +11 -4
- package/assets/hooks/rule-source-guard.sh +8 -13
- package/assets/hooks/skill-gate-layers.sh +7 -0
- package/assets/hooks/skill-gate.sh +29 -0
- package/assets/hooks/task-context-load.sh +32 -0
- package/assets/hooks/task-flow-context.sh +194 -0
- package/assets/hooks/task-flow-draft-guard.sh +109 -0
- package/assets/hooks/task-flow-guard.sh +27 -159
- package/assets/hooks/turn-exit-guard.sh +53 -88
- package/assets/hooks/waiting-turn-guard.sh +65 -2
- package/assets/hooks/window-fill-guard.sh +5 -1
- package/assets/hooks/work-start-guard.sh +166 -0
- package/assets/hooks/write-targets.sh +24 -0
- package/assets/laws/delivery.md +19 -0
- package/assets/laws/frontend-application.md +4 -0
- package/assets/laws/verifiability.md +44 -0
- package/assets/laws/work-conduct.md +15 -0
- package/assets/patterns/browser-verification-measure.md +3 -1
- package/assets/patterns/browser-verification-stand.md +17 -4
- package/assets/patterns/doc-style-write.md +62 -2
- package/assets/patterns/git-workflow-commit.github.md +33 -5
- package/assets/patterns/git-workflow-docker.md +22 -0
- package/assets/patterns/git-workflow-freshness.md +87 -0
- package/assets/patterns/git-workflow-merge.md +41 -0
- package/assets/patterns/git-workflow-migration.md +11 -0
- package/assets/patterns/git-workflow-pr.github.md +12 -1
- package/assets/patterns/git-workflow-restart.md +18 -0
- package/assets/patterns/git-workflow-secrets.md +14 -0
- package/assets/patterns/git-workflow-stack.md +93 -1
- package/assets/patterns/lib-layers-move.md +4 -0
- package/assets/patterns/spec-driven-domain.md +47 -2
- package/assets/patterns/spec-driven-rule.md +16 -4
- package/assets/patterns/spec-driven-sweep.md +57 -0
- package/assets/patterns/status-report-table.github.md +1 -1
- package/assets/patterns/task-flow-archive.md +58 -16
- package/assets/patterns/task-flow-close.md +106 -23
- package/assets/patterns/task-flow-handoff.md +14 -2
- package/assets/patterns/task-flow-resume.md +35 -8
- package/assets/patterns/task-flow-start.md +60 -22
- package/assets/patterns/testing-e2e.md +23 -0
- package/assets/patterns/turn-entry-map.md +1 -1
- package/assets/pitfalls/agent-kit.md +71 -3
- package/assets/pitfalls/doc-style.md +15 -0
- package/assets/pitfalls/git-workflow.github.md +88 -0
- package/assets/pitfalls/spec-driven.md +22 -0
- package/assets/pitfalls/task-flow.md +113 -0
- package/assets/pitfalls/testing.md +6 -0
- package/assets/pitfalls/turn-conduct.md +49 -0
- package/assets/rules/browser-verification.md +58 -0
- package/assets/rules/deploy-flow.azure.md +8 -0
- package/assets/rules/deploy-flow.github.md +27 -0
- package/assets/rules/deploy-flow.gitlab.md +8 -0
- package/assets/rules/doc-style.md +20 -0
- package/assets/rules/git-workflow.azure.md +22 -2
- package/assets/rules/git-workflow.github.md +127 -118
- package/assets/rules/git-workflow.gitlab.md +17 -4
- package/assets/rules/lists.md +5 -0
- package/assets/rules/observability.needs-app.md +4 -0
- package/assets/rules/reuse-first.md +14 -0
- package/assets/rules/shared-code.md +5 -0
- package/assets/rules/spec-driven.md +33 -15
- package/assets/rules/task-flow.md +132 -126
- package/assets/rules/testing.md +41 -2
- package/assets/rules/turn-conduct.md +73 -57
- package/assets/rules/turn-entry.md +6 -0
- package/assets/samples/tasks/_template/grill.md +5 -0
- package/assets/samples/tasks/_template/plan.md +3 -0
- package/assets/skills/agent-kit.md +108 -76
- package/assets/templates/postmortem.md +5 -1
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +30 -6
- package/bin/agent-kit.js.map +1 -1
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +2 -1
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +96 -7
- package/lib/commands.js.map +1 -1
- package/lib/hooks-map.d.ts +26 -0
- package/lib/hooks-map.d.ts.map +1 -1
- package/lib/hooks-map.js +58 -2
- package/lib/hooks-map.js.map +1 -1
- package/lib/sections.d.ts +6 -0
- package/lib/sections.d.ts.map +1 -1
- package/lib/sections.js +19 -0
- package/lib/sections.js.map +1 -1
- package/lib/shipment.d.ts +2 -0
- package/lib/shipment.d.ts.map +1 -1
- package/lib/shipment.fixture.d.ts +5 -0
- package/lib/shipment.fixture.d.ts.map +1 -1
- package/lib/shipment.fixture.js +7 -0
- package/lib/shipment.fixture.js.map +1 -1
- package/lib/shipment.js +13 -1
- package/lib/shipment.js.map +1 -1
- package/lib/sync.d.ts +35 -3
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +59 -8
- package/lib/sync.js.map +1 -1
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.18.0.tgz +0 -0
- package/rt-tools-agent-kit-0.16.1.tgz +0 -0
|
@@ -41,6 +41,15 @@
|
|
|
41
41
|
принимается заново.** Отменённое решение следа в работе не оставляет — по результату не видно ни
|
|
42
42
|
того, что его принимали, ни того, что от него отказались. Принятое заново оно расходится с
|
|
43
43
|
прежним молча и стоит той же работы второй раз.
|
|
44
|
+
- **Решение, которое переживёт задачу, записывается там, где оно переживёт.** Ход работы умирает
|
|
45
|
+
вместе с папкой задачи, а имя, адрес и выбранный способ, названные владельцем посреди серии
|
|
46
|
+
работ, нужны следующим её задачам. Не переехавшее решение существует только в переписке того
|
|
47
|
+
захода, в котором принято: следующий заход делает разведку честно, не находит ничего — и
|
|
48
|
+
задаёт владельцу вопрос, на который тот уже отвечал.
|
|
49
|
+
- **Инструмент, названный в просьбе, входит в просьбу.** Замена его на свой — отступление от
|
|
50
|
+
просьбы, даже когда свой даёт тот же ответ: равноценность инструментов решает тот, кто просит.
|
|
51
|
+
Одинаковый результат равноценностью не является — у названного инструмента бывает видно то,
|
|
52
|
+
чего у заменителя нет вовсе.
|
|
44
53
|
- **Понимание записано там, где идёт работа.** Оставленное в переписке живёт у одного участника и
|
|
45
54
|
до следующего дня; работу продолжает тот, у кого этой переписки нет.
|
|
46
55
|
- **Сказанное владельцем записывается его словами и задним числом не переписывается.** Пересказ
|
|
@@ -197,6 +206,12 @@
|
|
|
197
206
|
- **Уборка за работой идёт до того, как о готовности сказано.** Всё, что работа обязана убрать за
|
|
198
207
|
собой, убирается раньше просьбы включить её в общее дерево, а не после согласия. После включения
|
|
199
208
|
убирать уже некому: работа перешла к следующей задаче.
|
|
209
|
+
- **Постоянное указание среды исполнения слабее правила дерева.** Среда описывает своё
|
|
210
|
+
умолчание и о дереве не знает; дерево вправе его отменить и отменяет молча — тем, что говорит
|
|
211
|
+
иначе. Расхождение разрешается в пользу дерева, а не того из двух текстов, который строже
|
|
212
|
+
сформулирован или ближе стоит к делу. Опознаётся оно чтением обоих, а не проверкой: указание
|
|
213
|
+
среды приходит в заход текстом, и сличить его с правилом машине не по чему.
|
|
214
|
+
|
|
200
215
|
- **Пока эпик не кончился, следующая работа не выбирается, а берётся.** Выбор, предложенный
|
|
201
216
|
владельцу при назначенном порядке, — это просьба назначить его заново: он уже назначен, и
|
|
202
217
|
предлагать его повторно значит отменять собственное планирование.
|
|
@@ -67,7 +67,9 @@ description: Паттерн правила browser-verification. Брать, к
|
|
|
67
67
|
- Между кликами обязателен `await`: синхронный цикл «кликнул — прочитал DOM» читает состояние
|
|
68
68
|
до перерисовки и возвращает устаревшие значения.
|
|
69
69
|
- `select_browser` протухает через 300 секунд. На длинной проверке это срабатывает посреди
|
|
70
|
-
работы — это не сбой стенда, повторить вызов и продолжить. Закреплённый профиль —
|
|
70
|
+
работы — это не сбой стенда, повторить вызов и продолжить. Закреплённый профиль называет само дерево — переменной окружения либо своим файлом рядом с
|
|
71
|
+
настройками раскладки; спрашивается он у помощника, а не помнится: идентификатор локален для
|
|
72
|
+
машины и в пакет не едет вовсе.
|
|
71
73
|
|
|
72
74
|
## Поведение роутера воспроизводится нажатиями
|
|
73
75
|
|
|
@@ -40,6 +40,10 @@ PORT={{prodSitePort}} node dist/apps/site/server/server.mjs
|
|
|
40
40
|
Это не дев-сервер: гард ловит `nx|ng serve`, пакетные раннеры и статические серверы, а запуск
|
|
41
41
|
собранного сервера пропускает.
|
|
42
42
|
|
|
43
|
+
Поведение, зависящее от хоста — адрес владельца, увод, разный ответ на разных именах, —
|
|
44
|
+
проверяется прямо здесь одним запросом с заданным заголовком. Прокси с подменой для этого не
|
|
45
|
+
нужен: он добавляет ещё один процесс, чьё поведение придётся отделять от проверяемого.
|
|
46
|
+
|
|
43
47
|
## Стенд админки
|
|
44
48
|
|
|
45
49
|
```bash
|
|
@@ -107,8 +111,9 @@ docker run -d --name <префикс>-stand-nginx \
|
|
|
107
111
|
`nginx.conf`, — файл с расширением `.conf` в смонтированном каталоге попал бы в `include`
|
|
108
112
|
и уронил бы nginx на директиве `user`. Без него стенд поднимается на конфиге образа, и
|
|
109
113
|
предел соединений на воркер там свой.
|
|
110
|
-
-
|
|
111
|
-
|
|
114
|
+
- Чужой `Host` отбивает **дев-сервер**, а не собранное приложение: прод-сборка отвечает на него
|
|
115
|
+
тем же, чем и на свой. За настоящим прокси запросы идут со своим заголовком ровно потому, что
|
|
116
|
+
прокси стоит перед дев-сервером, — оттуда и `-H "Host: localhost"`.
|
|
112
117
|
- Переменные окружения стенда обязаны смотреть на процессы стенда. `CACHE_REFRESH_URL`,
|
|
113
118
|
направленный на {{sitePort}}, сбрасывает кэш мимо того процесса, который держит справочник
|
|
114
119
|
перенаправлений в памяти, — исправный механизм при этом выглядит сломанным.
|
|
@@ -128,8 +133,11 @@ pnpm install --frozen-lockfile # из ../<префикс>-base: node_mod
|
|
|
128
133
|
коммит — проверяют сборкой, а не тем, что он в главной ветке.
|
|
129
134
|
- Стенд второго дерева поднимают на своих портах: {{sitePort}}, {{adminPort}} и {{apiPort}} заняты владельцем, а {{ssrPort}}
|
|
130
135
|
занимать нельзя — стенд разработчика ходит по имени `ssr:{{ssrPort}}`.
|
|
131
|
-
- Оба стенда держат поднятыми
|
|
132
|
-
заметишь только то, что успел запомнить.
|
|
136
|
+
- Оба стенда держат поднятыми одновременно — ровно до конца сравнения: если сравнивать по памяти
|
|
137
|
+
между двумя запусками, заметишь только то, что успел запомнить. Со сравнением стенд второго
|
|
138
|
+
дерева гасится тем же ходом, а не оставляется до конца захода: оставленные стенды копятся
|
|
139
|
+
заходами и держат соединения к хранилищу, и правило говорит об этом ловушкой. Снятие отбито —
|
|
140
|
+
стенд называется владельцу в конце захода поимённо, с портом.
|
|
133
141
|
|
|
134
142
|
## Состояние портов снимается до первой сборки захода
|
|
135
143
|
|
|
@@ -155,6 +163,11 @@ done
|
|
|
155
163
|
это по её длительности.
|
|
156
164
|
- Свой дев-сервер не поднимать: сайт на {{sitePort}}, админка на {{adminPort}}, API на {{apiPort}} уже подняты
|
|
157
165
|
владельцем, и второй экземпляр отбивается гардом.
|
|
166
|
+
- **Дев-сервер владельца — место, где смотрят, а не место, где проверяют.** Вывод о том, что
|
|
167
|
+
экран верен, делается на прод-сборке за настоящим прокси: разметка от сервера, локали, кэш,
|
|
168
|
+
перенаправления и заголовки на дев-сервере либо другие, либо отсутствуют вовсе. Взгляд на
|
|
169
|
+
поднятый дев-сервер годится, чтобы понять, что происходит на незнакомом экране, и не годится
|
|
170
|
+
подтверждением: подтверждение — замер на стенде из прод-сборки.
|
|
158
171
|
- **Общая сборка глушит все три дев-сервера владельца, а не только API.** После
|
|
159
172
|
`nx run-many -t build` ложатся и сайт на {{sitePort}}, и админка на {{adminPort}}. Собирать надо то, что
|
|
160
173
|
проверяешь (`npx nx build site`), а не всё дерево. Если серверы легли, поднять их обратно
|
|
@@ -48,7 +48,7 @@ description: Паттерн правила doc-style. Брать при напи
|
|
|
48
48
|
|
|
49
49
|
«Не планируется», «не будет», «отдельная фича по запросу» — это намерение владельца, а не
|
|
50
50
|
свойство системы. Что не сделано — да, почему не сделано — да, что не будет сделано никогда —
|
|
51
|
-
нет. Вместо приговора — открытый вопрос `Q
|
|
51
|
+
нет. Вместо приговора — открытый вопрос `Q-<буква закона>-<номер>` с тем, что решение изменит.
|
|
52
52
|
|
|
53
53
|
Ошибка беззвучная: сверять утверждение о будущем не с чем, оно проходит любую проверку. Так в
|
|
54
54
|
первый живой спек попало «онлайн-оплаты нет и не планируется», хотя оплата в планах.
|
|
@@ -69,7 +69,40 @@ description: Паттерн правила doc-style. Брать при напи
|
|
|
69
69
|
✓ у пустого списка должен быть текст, у отказа — кнопка повтора
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
Проверка: прочитать фразу вслух. Если так не говорят — переписать.
|
|
72
|
+
Проверка: прочитать фразу вслух. Если так не говорят — переписать. Слухом это ловится в той
|
|
73
|
+
фразе, которую читают, и не ловится в файле на восемьсот строк: оборот всплывает по всему
|
|
74
|
+
тексту, и глазами он не считается.
|
|
75
|
+
|
|
76
|
+
Берётся чужой оборот оттуда, что писавший только что читал, и сильнее всего это бьёт при письме
|
|
77
|
+
в том же роде: ни одного слова вне словаря в такой фразе нет, каждое проходит вычитку по
|
|
78
|
+
отдельности, а непонятной оказывается фраза целиком. Вводный абзац поэтому пишется последним —
|
|
79
|
+
когда источник уже выветрился.
|
|
80
|
+
|
|
81
|
+
Вторая половина проверки — счёт, и там, где дерево разложило проверку слога
|
|
82
|
+
`checks/check-prose-style.mjs`, набор оборотов накоплен в ней самой: каждый признак назван
|
|
83
|
+
вместе с заменой, а находка печатается файлом и строкой. Оборот, найденный вычиткой,
|
|
84
|
+
дописывается в набор тем же ходом — иначе следующий пишущий начинает с пустого места и
|
|
85
|
+
собирает его заново из своей памяти.
|
|
86
|
+
|
|
87
|
+
Читается не только слово, но и то, одно ли у фразы прочтение. Три причины нечитаемости приходят
|
|
88
|
+
по очереди, и правка одной заводит следующую — статью закона переписывали трижды, и каждый раз
|
|
89
|
+
владелец не понимал её по новой причине:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
✗ не различать их нельзя — двойное отрицание читается наоборот сказанному
|
|
93
|
+
✗ у каждого видно, откуда он взялся — местоимение без хозяина, а «взялся» не называет действия
|
|
94
|
+
✗ либо снимается ролью, либо остаётся навсегда — два исхода через «или» без правила, по которому наступает тот или другой
|
|
95
|
+
|
|
96
|
+
✓ выданное лично снимается только лично: роль этого не трогает
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Довод «без такого устройства было бы так» в текст не идёт вовсе: он спорит с тем, чего нет, и
|
|
100
|
+
читается как «это к чему?».
|
|
101
|
+
|
|
102
|
+
Чего не видит ни слух, ни она: повтора законного оборота. Каждое его появление законно
|
|
103
|
+
поодиночке, а стоящий в тексте десятками он уже не приём, а тик — читатель перестаёт замечать
|
|
104
|
+
его вместе со смыслом. Считается это грепом по тексту, и число само по себе отказом не бывает:
|
|
105
|
+
судит его тот, кто правит следующим.
|
|
73
106
|
|
|
74
107
|
## Факт проверяется, а не вспоминается
|
|
75
108
|
|
|
@@ -79,6 +112,33 @@ description: Паттерн правила doc-style. Брать при напи
|
|
|
79
112
|
Особенно это касается отказов: «вернётся `value out of range`» продержалось в двух документах,
|
|
80
113
|
хотя такой отказ недостижим — в контракте и в колонке одна ширина.
|
|
81
114
|
|
|
115
|
+
**Утверждение о состоянии другой ветки читается из неё, а не из своей копии.** Копия, снятая при
|
|
116
|
+
отведении, отвечает на любой вопрос о содержимом файла и ни одним признаком не показывает,
|
|
117
|
+
насколько она отстала. Трижды за один заход состояние общей ветки вывели из файла на своей,
|
|
118
|
+
отставшей на семь коммитов; все три вывода неверны, один доехал до документа задачи и был назван
|
|
119
|
+
владельцу как факт. Поймано ребейзом, то есть случайно.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
git fetch origin
|
|
123
|
+
git show origin/main:<путь к файлу>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Утверждение «все N таких-то» пишется после перечисления маршрутов, которыми значение попадает в
|
|
127
|
+
место, а не после скана по одному образцу.** Скан подтверждает ровно тот маршрут, который в него
|
|
128
|
+
заложен, и молчит обо всех прочих — тем увереннее, чем точнее образец. Посчитали места по образцу
|
|
129
|
+
самого вызова, получили 22 и записали в план и в описание заявки, что порядок держится
|
|
130
|
+
устройством; мимо прошли десять вызовов обёртки, которая берёт значение аргументом. Мест
|
|
131
|
+
оказалось 32, и у десяти значение стояло числом.
|
|
132
|
+
|
|
133
|
+
**Команда, которой получено число, проверяется на том, что она мерит спрошенное.** Вывод команды
|
|
134
|
+
— не подтверждение сам по себе: инструмент отвечает на тот вопрос, который понял, и о непонятой
|
|
135
|
+
части образца молчит. Три числа подряд за один заход: граница слова, не реализованная в этой
|
|
136
|
+
сборке инструмента и не объявленная отказом, дала 278 вхождений вместо 79; счёт вызовов
|
|
137
|
+
регулярным выражением дал 32 и 42 на одном и том же, а по синтаксическому дереву их 27.
|
|
138
|
+
|
|
139
|
+
**Число, пришедшее из прошлой сессии, замером не считается.** Оно неотличимо от замеренного и в
|
|
140
|
+
документе выглядит так же уверенно; пересчитывается заново тем же ходом, которым пишется.
|
|
141
|
+
|
|
82
142
|
## Не пересказывать то, у чего есть источник
|
|
83
143
|
|
|
84
144
|
- типы и поля контракта — `libs/common/proto/proto/<область>/v1/`, ссылкой;
|
|
@@ -26,6 +26,19 @@ description: Паттерн правила git-workflow. Брать на зав
|
|
|
26
26
|
|
|
27
27
|
Все четыре шага делает одна команда дерева, а не рука: делить их значит забывать третий.
|
|
28
28
|
|
|
29
|
+
**Очередь работ спрашивается до заведения задачи, а не после.** Найденное собственной сверкой
|
|
30
|
+
ощущается новым, и это ощущение — единственное, что стоит за решением завести задачу: команда
|
|
31
|
+
заведения отвечает за свои вызовы и о содержании очереди не знает ничего. Спрашивается она
|
|
32
|
+
поиском по словам темы, вместе с закрытым за последний месяц: дефект, закрытый и вернувшийся, —
|
|
33
|
+
та же работа, а не новая. Дубль стоит дорого — по нему проходит вся работа целиком, а сводить
|
|
34
|
+
две задачи в одну потом приходится руками.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
/opt/homebrew/bin/gh issue list --state all --limit 200 --search '<слова темы>' \
|
|
38
|
+
--json number,title,state
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
29
42
|
```bash
|
|
30
43
|
npm run task:new -- --title 'Письма владельцу не уходят молча' \
|
|
31
44
|
--label bug --label area:api --slug mail-owner-silence < описание.md
|
|
@@ -102,7 +115,7 @@ $GH api graphql -f query='mutation { deleteIssue(input: {issueId: "<node-id>"})
|
|
|
102
115
|
составная команда отклоняется целиком — ветки в ней ещё нет:
|
|
103
116
|
|
|
104
117
|
```bash
|
|
105
|
-
✗ git checkout -b <КЛЮЧ>-85-guest-token && git commit -m 'feat(
|
|
118
|
+
✗ git checkout -b <КЛЮЧ>-85-guest-token && git commit -m 'feat(<область>): …'
|
|
106
119
|
✓ git checkout -b <КЛЮЧ>-85-guest-token
|
|
107
120
|
✓ git commit -F -
|
|
108
121
|
```
|
|
@@ -153,11 +166,25 @@ GIT_COMMITTER_NAME="<бот>" GIT_COMMITTER_EMAIL="<номер>+<бот>@users.n
|
|
|
153
166
|
конце заголовка не принимается, длина — до 150 знаков.
|
|
154
167
|
|
|
155
168
|
```
|
|
156
|
-
feat(
|
|
157
|
-
fix(
|
|
169
|
+
feat(<область>): availability calendar with season prices
|
|
170
|
+
fix(<область>): reject overlapping booking dates
|
|
158
171
|
chore(deploy): docker-compose for vps
|
|
159
172
|
```
|
|
160
173
|
|
|
174
|
+
## Файлы своей работы называются поимённо
|
|
175
|
+
|
|
176
|
+
Рабочее дерево одно, а работ в нём бывает несколько: чужая незакоммиченная папка, оставленный
|
|
177
|
+
черновик, правка соседнего захода. Каталог, добавленный целиком, уносит их с собой, и в главную
|
|
178
|
+
ветку уезжает то, о чём эта работа не просила.
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git add docs/tasks/<КЛЮЧ>-<номер>-<slug>/plan.md docs/tasks/<КЛЮЧ>-<номер>-<slug>/progress.md
|
|
182
|
+
git diff --cached --name-only # что действительно встало в индекс
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Проверки индекса после добавления мало: однажды добавленный чужой файл становится
|
|
186
|
+
отслеживаемым и дальше едет молча — следующий `git add` его уже не спрашивает.
|
|
187
|
+
|
|
161
188
|
## Документ едет тем же коммитом
|
|
162
189
|
|
|
163
190
|
`docs-guard` требует пару и называет её сам. Обход — строка в теле, причина обязательна:
|
|
@@ -169,6 +196,7 @@ Docs-skip: правка только в тестах хука, зеркала у
|
|
|
169
196
|
## Частые промахи
|
|
170
197
|
|
|
171
198
|
- `gh` в оболочке пользователя подменён — звать `/opt/homebrew/bin/gh` напрямую.
|
|
199
|
+
- Каталог добавлен целиком при чужом незакоммиченном рядом: чужая папка задачи уехала в главную ветку и стала отслеживаемой.
|
|
172
200
|
- `git add` с несколькими путями не добавляет ничего, если хоть один путь не существует:
|
|
173
201
|
команда обрывается на первом промахе целиком, а не пропускает его. Следующий
|
|
174
202
|
`git commit --amend` при этом уносит в коммит всё, что осталось в индексе, — так в коммит
|
|
@@ -180,13 +208,13 @@ Docs-skip: правка только в тестах хука, зеркала у
|
|
|
180
208
|
каталог диагностики.
|
|
181
209
|
- `gh project` с `--owner` отвечает `unknown owner type`: владелец борды — другая учётная
|
|
182
210
|
запись, и правка идёт только через GraphQL.
|
|
183
|
-
-
|
|
211
|
+
- Заведённую задачу на борду сама она не забирает: репозиторий с ней не связан, и добавление
|
|
184
212
|
идёт отдельным вызовом. Два тикета так и остались вне очереди работ — поэтому все четыре
|
|
185
213
|
шага и делает `npm run task:new`, а не рука.
|
|
186
214
|
- Исполнитель у задачи не проставляется сам ни при заведении через веб, ни при добавлении на
|
|
187
215
|
борду: из девяноста девяти открытых задач он стоял у двух.
|
|
188
216
|
- Задача, заведённая через веб, мимо команды, на борду не попадает и гардом не отбивается —
|
|
189
|
-
он смотрит команду, а не
|
|
217
|
+
он смотрит команду, а не задачу. Ловится это только сверкой очереди.
|
|
190
218
|
- Колонка задачи сама не двигается ни от заведения ветки, ни от открытия PR: борда ветки не
|
|
191
219
|
видит вовсе, а связь с PR заполняет только поле «Linked pull requests». Взятие в работу не
|
|
192
220
|
ловит и сверка — ей ветка тоже не видна.
|
|
@@ -96,6 +96,14 @@ docker builder prune --force --filter until=24h # вчерашний кэ
|
|
|
96
96
|
Освобождают отбором, а не общей чисткой: у сценария чистки образов сперва спрашивают, что он
|
|
97
97
|
снял бы, и только потом дают снимать.
|
|
98
98
|
|
|
99
|
+
**Снятие образов отбивает не гейт, а режим захода.** В автоматическом режиме команда с
|
|
100
|
+
необратимым удалением — снятие образа, чистка слоёв — отклоняется независимо от разрешений, и
|
|
101
|
+
разрешающее правило на ту же команду отказа не снимает. Повторный вызов отбивается так же: отказ
|
|
102
|
+
не зависит от того, как команда набрана, поэтому переформулировка тут не путь. Ходов отсюда два —
|
|
103
|
+
освободить место тем, что удаления не требует, либо назвать это владельцу: режим переключает он,
|
|
104
|
+
и снимает образы тоже он. Названное в конце захода стоит целого прогона: конвейер всё это время
|
|
105
|
+
стоит красным по нехватке места.
|
|
106
|
+
|
|
99
107
|
## Демон поднимается своим CLI
|
|
100
108
|
|
|
101
109
|
Открытие приложения виртуальную машину не поднимает: приложение считается запущенным, а демон
|
|
@@ -176,6 +184,20 @@ docker info --format 'демон: {{.ServerVersion}}'
|
|
|
176
184
|
содержимым или `403`, но не `401`. Каталог снимается в конце — раннер живёт между прогонами, и
|
|
177
185
|
пароль реестра остался бы лежать на диске владельца.
|
|
178
186
|
|
|
187
|
+
## Права токена спрашиваются до того, как конвейер на них обопрётся
|
|
188
|
+
|
|
189
|
+
Токен, которым ходят руками, и токен, которым ходит выкатка, — один и тот же ровно до первой
|
|
190
|
+
записи в реестр образов: области у него могут кончаться на чтении. Узнаётся это отказом, когда
|
|
191
|
+
весь путь выкатки уже написан, поэтому спрашивается раньше — и не догадкой, а заголовком ответа
|
|
192
|
+
хостинга:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
curl -sI -H "Authorization: Bearer <токен>" '<адрес хостинга>' | grep -i '^x-oauth-scopes:'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Первая выкатка, сделанная руками из-за такого отказа, путь выкатки не проверяет — она проверяет
|
|
199
|
+
образы. Об этом говорится владельцу прямо: иначе зелёный прод читается как пройденный конвейер.
|
|
200
|
+
|
|
179
201
|
## Образ собирается под платформу прод-сервера
|
|
180
202
|
|
|
181
203
|
Машина владельца и прод-сервер бывают разной архитектуры. Без явной платформы собирается образ
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-workflow-freshness
|
|
3
|
+
kind: pattern
|
|
4
|
+
rule: git-workflow
|
|
5
|
+
description: Паттерн правила git-workflow. Брать перед пушем, при взятии задачи и после каждого известного слияния: чтение всех своих открытых заявок разом, отделение отставания от спора в файлах, сверка локальной вершины с хостингом.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Свежесть открытых заявок
|
|
9
|
+
|
|
10
|
+
Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
|
|
11
|
+
`docs/constitution/delivery.md`. Разбор одного конфликта — паттерн `git-workflow-merge`,
|
|
12
|
+
череда веток из одного основания — `git-workflow-stack`.
|
|
13
|
+
|
|
14
|
+
## Когда брать
|
|
15
|
+
|
|
16
|
+
Три места, и в каждом чтение обязательно:
|
|
17
|
+
|
|
18
|
+
- перед пушем — вершина главной могла уйти, пока шла работа;
|
|
19
|
+
- при взятии новой задачи — прежние заявки остались открытыми и о себе не напомнят;
|
|
20
|
+
- после каждого слияния, о котором стало известно, — оно отставило все остальные разом.
|
|
21
|
+
|
|
22
|
+
## Что читается
|
|
23
|
+
|
|
24
|
+
Одной командой по всем своим открытым заявкам, а не по той, чья ветка сейчас взята:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
/opt/homebrew/bin/gh pr list --author '<машинная запись>' --state open \
|
|
28
|
+
--json number,headRefName,isDraft,mergeable,mergeStateStatus,statusCheckRollup
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Поле | Что говорит |
|
|
32
|
+
| -------------------- | --------------------------------------------------------------------------------- |
|
|
33
|
+
| `mergeable` | `MERGEABLE` — кнопку нажать можно; `CONFLICTING` — нельзя; `UNKNOWN` — ещё не посчитано |
|
|
34
|
+
| `mergeStateStatus` | `BEHIND` — отстала от главной; `DIRTY` — спор в файлах; `BLOCKED` — ждёт разбора |
|
|
35
|
+
| `isDraft` | черновик: кнопка слияния заблокирована хостингом при любом цвете прогона |
|
|
36
|
+
| `statusCheckRollup` | прогон на вершине: пустой список — прогона нет вовсе, а не «зелено» |
|
|
37
|
+
|
|
38
|
+
`UNKNOWN` означает «ещё не посчитано» и читается как «спросить снова через несколько секунд»,
|
|
39
|
+
а не как «конфликтов нет».
|
|
40
|
+
|
|
41
|
+
## Спор в файлах отделяется от отставания
|
|
42
|
+
|
|
43
|
+
Метка хостинга говорит одно — «нажать нельзя». Что именно чинить, отвечает слияние деревьев,
|
|
44
|
+
и отвечает без сети:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git fetch origin
|
|
48
|
+
git merge-tree "$(git merge-base origin/main <ветка>)" origin/main <ветка> | grep -c '^<<<<<<<'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Ноль — ветка просто отстала, и лечится это вливанием главной. Больше нуля — спор в файлах, и
|
|
52
|
+
каждый разбирается по роду файла: паттерн `git-workflow-merge`.
|
|
53
|
+
|
|
54
|
+
## Что делается с найденным
|
|
55
|
+
|
|
56
|
+
| Найдено | Что делается |
|
|
57
|
+
| -------------------------------------- | ------------------------------------------------------------------ |
|
|
58
|
+
| отстала, спора нет | главная вливается в ветку и отправляется тем же ходом |
|
|
59
|
+
| спор в файлах | разбор по роду файла, затем отправка |
|
|
60
|
+
| прогона на вершине нет | вершина перезапускается или дожидается — цвета нет ни у той, ни у другой |
|
|
61
|
+
| черновик при зелёном прогоне | черновик снимается — у него кнопка слияния заблокирована |
|
|
62
|
+
| заявка открыта человеком, а не машиной | ревьювера ей уже не поставить: заводится заново машинной записью |
|
|
63
|
+
|
|
64
|
+
Внутри одной ветки порядок один: влить главную → прогнать набор гейта → отправить → перечитать
|
|
65
|
+
состояние у хостинга. Перечитывание — часть работы, а не отчёт о ней.
|
|
66
|
+
|
|
67
|
+
## Локальная вершина сверяется с той, что на хостинге
|
|
68
|
+
|
|
69
|
+
Догнанная в рабочем дереве и не отправленная ветка работой не считается: человек видит прежнее
|
|
70
|
+
состояние.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git rev-parse HEAD
|
|
74
|
+
/opt/homebrew/bin/gh pr view <номер> --json headRefOid --jq .headRefOid
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Разошлись — отправка не сделана, и это первое, что чинится.
|
|
78
|
+
|
|
79
|
+
## Частые промахи
|
|
80
|
+
|
|
81
|
+
- Состояние заявки прочитано по памяти прошлого хода: между ходами человек влил соседнюю работу.
|
|
82
|
+
- `UNKNOWN` прочитан как «конфликтов нет» — хостинг ещё считал.
|
|
83
|
+
- Читалась заявка текущей ветки, а брошенные остались отставшими: спрашиваются все свои открытые.
|
|
84
|
+
- Главная влита в рабочем дереве и не отправлена: снаружи это «не сделано ничего».
|
|
85
|
+
- Отставание лечили разбором конфликта: спора в файлах не было вовсе, хватило бы вливания.
|
|
86
|
+
- Спор разрешили выбором стороны целиком: род файла решает приём, и стороны у него разные.
|
|
87
|
+
- Круг догоняния начат по окрику человека, а не сам: к этой минуте отстали уже все заявки.
|
|
@@ -10,6 +10,10 @@ description: Паттерн правила git-workflow. Брать, когда
|
|
|
10
10
|
Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
|
|
11
11
|
`docs/constitution/delivery.md`.
|
|
12
12
|
|
|
13
|
+
**Вызовы здесь даны клиентом GitHub.** Дерево на другом хостинге читает их как форму, а команду
|
|
14
|
+
берёт у своего клиента: имена полей и подкоманд у клиентов разные, а спрашиваемое — одно.
|
|
15
|
+
Соответствие называет редакция правила поставки, разложенная в этом дереве.
|
|
16
|
+
|
|
13
17
|
## Когда брать
|
|
14
18
|
|
|
15
19
|
- PR отмечен конфликтующим, и его надо вернуть к сливаемому состоянию.
|
|
@@ -40,6 +44,23 @@ git diff --name-only --diff-filter=U # что встало конфликт
|
|
|
40
44
|
| компаньон правила рядом со скилом | сохранением обеих сторон — те же две дописи в одну таблицу; после — `npm run check:specs` |
|
|
41
45
|
| список работ (`docs/BACKLOG.md`) | признаком отбора — паттерн `doc-style-sweep` |
|
|
42
46
|
|
|
47
|
+
## Коммит переносится черри-пиком
|
|
48
|
+
|
|
49
|
+
Ветка, которой коммит должен был уехать, ушла: влилась, была снята хостингом или заведена не под
|
|
50
|
+
ту задачу. Сам коммит при этом цел и лежит в отпавшей ветке.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
GIT_COMMITTER_NAME="<бот>" GIT_COMMITTER_EMAIL="<номер>+<бот>@users.noreply.github.com" \
|
|
54
|
+
git cherry-pick <sha>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Переменные подписи стоят на самой команде переноса. Черри-пик сохраняет автора коммита и ставит
|
|
58
|
+
коммиттером того, кто его зовёт, — то есть человека; коммиттера читает набор проверок перед
|
|
59
|
+
пушем, и чинится это уже перебазированием, а не правкой одного коммита.
|
|
60
|
+
|
|
61
|
+
Отпавшая ветка снимается с обеих сторон тем же ходом — иначе она стоит в перечне как незакрытая
|
|
62
|
+
работа.
|
|
63
|
+
|
|
43
64
|
## Что дописала ветка, видно только от точки расхождения
|
|
44
65
|
|
|
45
66
|
Конфликтный маркер показывает место, а не правку: сторона ветки в нём — её допись вместе со
|
|
@@ -98,14 +119,34 @@ PR описывал дерево на день, когда его написал
|
|
|
98
119
|
/opt/homebrew/bin/gh api -X PATCH repos/<владелец>/<репозиторий>/pulls/<номер> -f body="$(cat тело.md)"
|
|
99
120
|
```
|
|
100
121
|
|
|
122
|
+
## Зелёный прогон стареет вместе с главной веткой
|
|
123
|
+
|
|
124
|
+
Прогон говорит про то основание, на котором шёл. Пока он идёт, а заявка ждёт разбора, главная
|
|
125
|
+
ветка живёт своей жизнью, и локальная ссылка об этом молчит: она описывает день, когда её
|
|
126
|
+
подтянули. Перед тем как назвать заявку готовой к слиянию, отставание спрашивается у хранилища:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
/opt/homebrew/bin/gh api repos/<владелец>/<репозиторий>/compare/<главная>...<ветка> --jq .behind_by
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Ноль — заявка готова. Больше нуля — главная вливается, набор проверок пересматривается по тому,
|
|
133
|
+
что ветка везёт теперь, и прогон идёт заново: зелёные задания прошлого прогона после вливания не
|
|
134
|
+
значат ничего.
|
|
135
|
+
|
|
101
136
|
## Частые промахи
|
|
102
137
|
|
|
103
138
|
- «Сохранить обе стороны» применено ко всем файлам одинаково: в спеке это верно, в коде и в
|
|
104
139
|
списке работ — нет.
|
|
140
|
+
- Команда мержа взята без переменных подписи: коммит слияния подписан человеком, и отбивает его
|
|
141
|
+
набор пуша — на том шаге, где все проверки уже зелёные. Чинится это переписыванием ветки, а не
|
|
142
|
+
правкой одного коммита: за слиянием обычно уже лежат разрешения конфликтов.
|
|
105
143
|
- Сторона ветки перенесена без сверки с очередью работ: одна работа стала двумя записями.
|
|
106
144
|
- После разрешения прогнана сборка, а проверки текстов — нет: конфликта в них сборке не видно.
|
|
107
145
|
- Тело PR оставлено прежним: ревьювер читает утверждение о дереве, которого больше нет.
|
|
146
|
+
- Заявка названа готовой по зелёному прогону: задания шли от основания, которого в главной ветке
|
|
147
|
+
уже нет.
|
|
108
148
|
- Раздел, снятый главной веткой, вернулся «сохранением обеих сторон»: в спеке два экземпляра
|
|
109
149
|
одного абзаца, и снятый читается как действующий.
|
|
150
|
+
- Черри-пик взят без переменной коммиттера: автор у коммита прежний, коммиттер — человек, и отправку отбивает набор проверок.
|
|
110
151
|
- Мерж ушёл за подписью человека: переменных в команде слияния не было, а строка о подписи
|
|
111
152
|
лежит ниже команды и читается уже после коммита.
|
|
@@ -74,6 +74,11 @@ npx prisma migrate resolve --applied <новое имя>
|
|
|
74
74
|
|
|
75
75
|
## Частые промахи
|
|
76
76
|
|
|
77
|
+
- **Накат в образе настраивается файлом настройки, а не адресом в окружении.** Седьмая редакция
|
|
78
|
+
читает адрес хранилища только из своего файла настройки: ни объявление в схеме, ни переменная
|
|
79
|
+
окружения в составе прода его не заменяют. Этот файл кладётся в образ явно, рядом со схемой и
|
|
80
|
+
миграциями. Без него сборка зелёная целиком — генерация клиента на стадии сборки проходит, — а
|
|
81
|
+
отказывает первый же накат на узле.
|
|
77
82
|
- Метку времени ставит момент создания, а порядок применения лексикографический: миграция из
|
|
78
83
|
ветки, начатой раньше, встаёт перед той, от которой зависит. На существующей базе это
|
|
79
84
|
незаметно — падает только накат с нуля.
|
|
@@ -86,3 +91,9 @@ npx prisma migrate resolve --applied <новое имя>
|
|
|
86
91
|
через деплой, данные — через админку.
|
|
87
92
|
- Строки адресуются по первичному ключу, а не по маске: удаление по маске почты однажды унесло
|
|
88
93
|
вместе с тестовыми записями демонстрационные брони владельца.
|
|
94
|
+
- **Формой запроса вопрос гарда не снимается.** Условие по идентификатору он судит одинаково в
|
|
95
|
+
любой записи — что по одному, что по списку, — и на обе отвечает вопросом владельцу; отказ
|
|
96
|
+
приходит только на условие не по идентификатору. Там, где вопрос читается отказом, ход один:
|
|
97
|
+
назвать владельцу отбитую команду и попросить режим, в котором вопрос дойдёт, — а не
|
|
98
|
+
переписывать запрос, пока он не пройдёт. Иначе из захода уносят вывод о требованиях гарда,
|
|
99
|
+
которых у него нет.
|
|
@@ -177,6 +177,12 @@ $GH api "repos/$REPO/pulls/321" \
|
|
|
177
177
|
назначить автора ревьювером нельзя, а отказа на такой запрос не приходит. Владельцу называют
|
|
178
178
|
то, что прочитали, а не то, что заказывали.
|
|
179
179
|
|
|
180
|
+
Прочитанное расхождение имеет назначенное действие, а не остаётся наблюдением: автора у заявки
|
|
181
|
+
не сменить, правкой это не чинится. Заявка закрывается и открывается заново токеном машинной
|
|
182
|
+
записи — с переносом тела, меток, ревьювера и исполнителя. Номер при этом сменится, и строки,
|
|
183
|
+
которые ссылались на прежний, переписываются тем же ходом. Развилка, вынесенная тут владельцу,
|
|
184
|
+
означает, что порядок поставки прочитан и не исполнен: ход отсюда один.
|
|
185
|
+
|
|
180
186
|
Учётная запись, из-под которой пришлось пушить, в этот вызов не переносится: пуш и авторство
|
|
181
187
|
PR выбираются отдельно, и `GH_TOKEN` для публикации — всегда токен бота.
|
|
182
188
|
|
|
@@ -185,6 +191,11 @@ PR выбираются отдельно, и `GH_TOKEN` для публикац
|
|
|
185
191
|
фразой владелец успевает влить PR, и всё сказанное о нём после этого — про вчерашний день. Так
|
|
186
192
|
владельцу и было предложено влить то, что он влил часом раньше.
|
|
187
193
|
|
|
194
|
+
Читается состояние и перед пушем в ветку, у которой есть заявка, а не только перед словом о
|
|
195
|
+
ней. Влитая заявка означает, что ветки на сервере уже нет: пуш её не обновит, а заведёт заново,
|
|
196
|
+
и вклад останется вне главной ветки. Ответ пуша говорит это одной строкой — отметкой о новой
|
|
197
|
+
ветке вместо перечня коммитов, — и её читают: на удачную отправку такой ответ похож целиком.
|
|
198
|
+
|
|
188
199
|
Открытый PR означает, что задача ждёт разбора, — колонка переставляется тем же движением:
|
|
189
200
|
|
|
190
201
|
```bash
|
|
@@ -276,5 +287,5 @@ in-review`, — и `npm run check:board` прогоняется ещё раз:
|
|
|
276
287
|
выглядя работающей. Так шестнадцать PR ждали разбора, которого никто не запрашивал.
|
|
277
288
|
- Метки поставлены по названию PR, а не прочитаны у задачи: область теряется, и по борде не
|
|
278
289
|
видно, что правка задела ещё и сайт.
|
|
279
|
-
- Задача закрыта не полностью, а метки перенесены целиком:
|
|
290
|
+
- Задача закрыта не полностью, а метки перенесены целиком: задача остаётся открытой, и это
|
|
280
291
|
говорится в теле PR, а не подразумевается строкой `Closes`.
|
|
@@ -41,6 +41,24 @@ docker inspect <контейнер> --format '{{.Config.Image}}'
|
|
|
41
41
|
`integrations` из логов исчезает, хотя `API is running` остаётся на месте. После перезапуска —
|
|
42
42
|
тот же `inspect` и наличие ожидаемых строк в логе.
|
|
43
43
|
|
|
44
|
+
## Откат: тот же вызов с прежним sha
|
|
45
|
+
|
|
46
|
+
Откат — не отдельный механизм, а тот же подъём по sha, только взятому на шаг назад. Прежний sha
|
|
47
|
+
берётся у реестра, где чистка оставляет три последних, — глубже отката нет:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
docker image ls '<реестр>/<образ>' --format '{{.Tag}}\t{{.CreatedAt}}' | sort -k2 -r | head -3
|
|
51
|
+
IMAGE_TAG='<прежний sha>' docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --no-build
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Откат возвращает прежний образ, но не прежнюю схему хранилища: миграция, уехавшая с новой
|
|
55
|
+
версией, остаётся применённой, и прежний образ работает с изменённой схемой. Правка схемы
|
|
56
|
+
поэтому и делится на совместимую и несовместимую — паттерн миграции.
|
|
57
|
+
|
|
58
|
+
Откаченный прод сходится с главной веткой не сразу: главная везёт правку, которой на проде уже
|
|
59
|
+
нет. Строкой очереди работ это не видно вовсе, и владельцу называется словами, вместе с sha, на
|
|
60
|
+
который откатились.
|
|
61
|
+
|
|
44
62
|
## Частые промахи
|
|
45
63
|
|
|
46
64
|
- Вывод «прод жив, значит выкатилось» — код ответа подмену образа не показывает.
|
|
@@ -17,6 +17,20 @@ description: Паттерн правила deploy-flow. Брать при раб
|
|
|
17
17
|
- Разбирается, что именно выкачено и чего приложению не хватает для работы, — включая ключ,
|
|
18
18
|
который живёт в окружении и экрана не имеет.
|
|
19
19
|
|
|
20
|
+
## Секрет выкатки — не ключ внешней службы
|
|
21
|
+
|
|
22
|
+
Ключи из этого паттерна живут в хранилище или в составе прода, и читает их приложение. Секреты
|
|
23
|
+
выкатки — ключ доступа к узлу, пароль реестра, адрес и токен приёма — приложением не читаются
|
|
24
|
+
вовсе: их читает конвейер, лежат они в настройках репозитория, и хранилище о них не знает.
|
|
25
|
+
|
|
26
|
+
Отсюда и разный ход при промахе. Ключ службы, которого не хватает, молчит на экране: возможность
|
|
27
|
+
не работает, а приложение отвечает. Секрет выкатки, которого не хватает, роняет шаг конвейера, и
|
|
28
|
+
до приложения дело не доходит вовсе — разбирают его в журнале задания, а не в браузере.
|
|
29
|
+
|
|
30
|
+
Про то, как секрет выкатки заводится и чем проверяется его право, говорит паттерн работы с
|
|
31
|
+
образами — `git-workflow-docker`, если дерево его разложило. Здесь остаётся граница: пришедший
|
|
32
|
+
за секретом выкатки читает дальше не этот текст.
|
|
33
|
+
|
|
20
34
|
## Ключ, заводимый владельцем, живёт в хранилище, а не в окружении
|
|
21
35
|
|
|
22
36
|
Такой ключ лежит строкой в хранилище, зашифрованной ключом шифрования секретов; рядом открытая
|