Проверьте готовность релиза до нажатия кнопки
Полный автоматизированный workflow релиза: предполётная проверка, тесты, ревью, версионирование, changelog, PR. Используйте когда готовы к релизу и нужно убедиться, что ничего не забыто.
Как агент работает
Состав релиза собирается механически из диффа, а не из памяти: человек помнит то, над чем работал, и не помнит приехавшего мержем или оставшегося от отменённого эксперимента. Диапазон берётся от merge-base, иначе влитая в фичу основная ветка добавит чужие коммиты и релиз распухнет на глазах у ревьюера. Грязное дерево — блокер: локальные .env, дампы и .DS_Store разбираются отдельно от релизных правок, а непустой stash list — повод спросить, не лежит ли там половина фичи.
Фраза «оно и до меня падало» без доказательства стоит один инцидент. Доказательство — прогон того же теста на базовой ревизии в изолированной копии дерева через worktree или git restore --source, но не через stash. Дальше падение классифицируется: падает на HEAD и проходит на base — своё, блокер; падает одинаково — предсуществующее, идёт в реестр рисков; падает иначе — своё, замаскированное, и это тоже блокер. «Так же» означает совпадение имени теста, типа исключения и строки падения, одного имени недостаточно.
Обязательность ревью определяет состав диффа, а не важность релиза: инженерное — на любой код, построчное — от 300 изменённых строк или правок в ядре, продуктовое — на новую функцию и изменение тарифа или лимитов, дизайнерское — на интерфейс вместе с текстами ошибок и пустыми состояниями. Персональные данные и платежи вынесены отдельно потому, что обработка ПДн регулируется законом о персональных данных, а фискализация — законом о применении ККТ. Каждое ревью закрывается строкой с автором, датой, вердиктом и остатком.
Ломающим считается то, после чего работающий клиент перестаёт работать, сам не изменившись: сужение принимаемых значений, ужесточение валидации, число, ставшее строкой, смена сортировки по умолчанию, изменённая семантика того же поля. Внешний API версионируется отдельно от продукта — ломающее изменение заводит v2, а v1 живёт с объявленным сроком, для SMB-интеграций не меньше 6 месяцев. Вебхуки тоже внешний API. Откат готовится до выката: тег release-версии, отдельно описанный откат схемы, перечисленные флаги и заранее названный порог решения.
Финальный список жёсткий: недоказанное падение теста, сборка не на чистой копии, незакоммиченные релизные правки, ломающее изменение без отражения в версии, миграция без downgrade или несовместимая со старым кодом, непроставленная переменная окружения, секрет в диффе, непройденный руками ключевой сценарий, выкат в пятницу вечером или в пик. Любой пункт — стоп, а не усмотрение. Принятые риски записываются с именем принявшего: пустая графа значит, что риск не принят, а забыт.
Граница с соседними навыками
| Вопрос | Навык |
|---|---|
| CI/CD с нуля, раннеры, секреты | setup_deploy_ru |
| Выкатить, наблюдать, откатить по факту | deploy_ru |
| Архитектура и качество ветки | eng_review_ru |
| Построчное ревью диффа | code_review_ru |
| Продуктовая целесообразность | ceo_review_ru |
| UI/UX, состояния интерфейса | design_review_ru |
1. Состав релиза берётся из диффа, а не из памяти
Человек помнит то, над чем работал, и не помнит того, что приехало мержем, что подтянул чужой rebase и что осталось от отменённого эксперимента. Собирай состав механически (sandbox_bash или git_ops):
merge-base, а не голый origin/main..HEAD: если основную ветку вливали в фичу, простой диапазон покажет ещё и чужие коммиты, и релиз распухнет на глазах у ревьюера.
1.2 Грязное дерево и расхождение
Грязное дерево — блокер. Не «закоммить всё скопом»: разбери, что относится к релизу, что мусор (.DS_Store, локальные .env, дампы), что чужое. Непустой stash list — повод спросить, не лежит ли там половина фичи. Конфликты, найденные на подготовке, — это работа; найденные при мерже — работа под давлением.
2. Тесты: своё падение или предсуществующее
«Оно и до меня падало» без доказательства — самая дорогая фраза в чек-листе: она стоит один инцидент, когда изменение сломало тест, падавший до этого по другой причине, и оба падения слились в одно.
2.1 Методика доказательства
Доказательство — прогон того же теста на базовой ревизии, в изолированной копии дерева:
Почему worktree, а не git stash + checkout:
Для одного-двух файлов — git restore --source=<base> -- <files> во временную копию. stash для baseline не использовать никогда.
2.2 Классификация
| На HEAD | На base | Вердикт | Что делать |
|---|---|---|---|
| падает | проходит | своё | блокер, чинить |
| падает | падает так же | предсуществующее | в реестр рисков, релиз возможен |
| падает | падает иначе | своё, замаскированное | блокер: изменился характер падения |
| падает через раз | — | флак | см. 2.3 |
«Так же» — совпадение имени теста, типа исключения и строки падения; совпадения одного имени недостаточно.
2.4 Что ещё должно сойтись
- Сборка — на чистой копии: инкрементальный кэш прячет забытый файл, не попавший в коммит.
- Ручной прогон сценариев, которые приносят деньги или блокируют работу. Для российского SMB это обычно вход в кабинет, подключение маркетплейса, выгрузка отчёта, оплата и получение чека. Тест, который «наверное, покрывает», не заменяет один живой проход.
3. Ревью: что обязательно для этого релиза
Обязательность определяет состав диффа, а не важность релиза.
| Ревью | Обязательно, если в диффе есть | Навык |
|---|---|---|
| Инженерное | любой код | eng_review_ru |
| Построчное | >300 изменённых строк или правки в ядре | code_review_ru |
| Продуктовое | новая функция, изменение тарифа/лимитов, удаление функции | ceo_review_ru |
| Дизайн | интерфейс, включая тексты ошибок и пустые состояния | design_review_ru |
| Безопасность | аутентификация, права, ПДн, платежи, выгрузки, ключи | eng_review_ru с явным фокусом |
Персональные данные и платежи вынесены отдельно не из вежливости: обработка ПДн регулируется законом о персональных данных, фискализация — законом о применении ККТ, и изменение состава хранимых данных или порядка формирования чека проверяют до выката.
Каждое ревью заканчивается строкой <ревью> — <кто> — <дата> — <вердикт> — <что осталось>; «проведено» без вердикта не считается.
4. Версионирование по существу
Схема MAJOR.MINOR.PATCH очевидна; неочевидно, что считать ломающим. Ломающее — то, после чего работающий клиент перестаёт работать, не изменившись сам.
4.1 Неочевидные ломающие изменения
- Сужение принимаемых значений. Поле принимало любую строку — стало принимать перечисление из пяти. Клиент, слàвший шестое, сломан.
- Ужесточение валидации. Обязательный флаг там, где был дефолт; проверка формата ИНН, которой не было; ограничение длины поля.
- Изменение формата ответа. Число стало строкой. Дата
2026-07-28стала ISO с таймзоной. Плоский объект стал вложенным. Переименование поля с сохранением старого — тоже ломающее, если старое перестало обновляться. - Смена сортировки по умолчанию. Клиент, берущий первый элемент, получает другой. Молча, без ошибки — худший класс поломки.
- Изменение семантики без изменения формы: тот же
status, ноdoneнаступает раньше; та же сумма, но теперь без НДС. Сюда же смена часового пояса или валюты по умолчанию: отчёт считался по московскому времени, стал по UTC — цифры за сутки поедут, и заметят это на сверке с маркетплейсом, а не в тестах. - Удаление или переименование поля, эндпойнта, переменной окружения.
Не ломающее: новое необязательное поле в ответе, новый необязательный параметр, новый эндпойнт, расширение перечисления на входе. Расширение перечисления на выходе — ломающее для клиента со строгим разбором.
4.2 Внешний API версионируется отдельно от продукта
Версия продукта и версия публичного API (/api/v1) — разные сущности с разным темпом. Продукт может выпускать мажор ежемесячно; внешний API — почти никогда: за ним чужие интеграции, не обязанные переписываться по твоему графику.
- Ломающее изменение не выпускается внутри существующей версии пути: заводится
v2,v1живёт параллельно и получает объявленный срок жизни. Ориентир для SMB-интеграций — не меньше 6 месяцев с момента объявления: на той стороне обычно подрядчик по 1С или один разработчик на аутсорсе. - До объявления посмотри, кто реально ходит на старую версию за 30 дней. Три интеграции — договорись персонально и не плоди
v2. - Вебхуки — тоже внешний API. Изменение формата события ломает приёмник в чужом контуре. Новое поле можно; изменение существующего — новая версия события.
5. Changelog для двух читателей
5.1 Пользовательский
Требуемое действие пользователя — выделенный блок в начале, а не пункт в середине списка: переподключить кабинет, обновить приложение, сменить формат выгрузки.
5.2 Технический
Читатель — тот, кто будет дежурить. Ему нужны: ломающие изменения списком в начале, миграции с обратимостью, новые и изменённые переменные окружения, изменения внешнего API и вебхуков, новые зависимости и требования к инфраструктуре, известные проблемы и предсуществующие падения из раздела 2.
Черновик собирается из коммитов, но как есть не публикуется:
Сообщения коммитов писались для автора в момент работы: fix: убрал лишний if не годится ни одному из читателей. Каждую строку либо переписывай под читателя, либо выбрасывай. Нигде не пиши имён сотрудников в негативном контексте, ссылок на внутренние трекеры, деталей уязвимости до обновления всех клиентов и обещаний сроков следующего релиза.
6. Миграции — блокирующее условие
По каждой миграции нужны ответы:
Отдельный класс блокеров: код пишет значение, которого не пропускает ограничение в применённой схеме. На свежей базе не ловится — там применена вся цепь. Ловится сверкой множества значений в коде с ограничением на живой схеме.
7. Переменные окружения и секреты
Переменная готова, когда:
- она есть в
.env.exampleс пояснением и безопасной заглушкой, а её изменение отражено в техническом changelog; - она проставлена в целевом окружении до выката — иначе приложение упадёт на старте, и это будет выглядеть как «релиз сломал всё»;
- определено поведение при её отсутствии: падать на старте с внятным сообщением (обязательные) или брать дефолт (необязательные); молчаливый
None, доезжающий до середины запроса, — худший вариант; - секреты не попали в репозиторий:
Ключ, попавший в историю, скомпрометирован даже после удаления коммита — его ротируют, а не «убирают из диффа».
8. Совместимость с установленными клиентами
Сервер обновляется мгновенно, клиенты — нет.
9. Частично готовая функциональность: флаг, а не ветка
Долгоживущая ветка дорожает нелинейно: чем дольше живёт, тем больше конфликтов, тем поверхностнее ревью, тем выше шанс, что её вольют разом и без разбора. Правильно — код едет в основную ветку выключенным под флагом.
- Выключен по умолчанию, включается без передеплоя (конфиг, БД, переменная окружения — но не пересборка).
- Есть владелец и дата снятия: флаг без даты становится вечным
if, и через год никто не помнит, какая ветка живая. - Обе ветки кода собираются и покрыты тестами. Выключенная ветка, которая не собирается, — мина.
- Не оставляет следов в выключенном состоянии: ни колонок, ни событий, ни писем, ни записей в чужие системы.
- Влияет на деньги, документы или данные во внешней системе — включение начинается с одного тестового аккаунта, а не с процента трафика.
В changelog функциональность под выключенным флагом не попадает: для пользователя её не существует.
10. Откат готовится до выката
- Точка возврата зафиксирована:
git tag -a release-<версия>до выката, не после. - Откат схемы БД описан отдельно. Код откатывается легко, база — нет. Миграция необратима по природе (удалены данные) — запиши прямо: «откат кода возможен, откат данных — только из бэкапа от <времени>», и проверь, что такой бэкап есть: момент, когда на бэкап смотрят впервые, не должен совпасть с моментом, когда он нужен.
- Флаги перечислены: часто быстрый откат — это выключить флаг, а не откатывать релиз, и занимает он секунды.
- Порог решения назван заранее — при каком признаке откатываемся: это экономит спор в момент, когда спорить некогда.
11. Жёсткий список: релиз не готов
Любой пункт — стоп, не «на усмотрение».
- Тест падает, и не доказано, что он падал на базовой ревизии так же.
- Сборка не проходит на чистой копии.
- Есть незакоммиченные изменения, относящиеся к релизу.
- Состав релиза не сверен с диффом.
- Ломающее изменение не отражено в версии и changelog.
- Миграция без
downgradeили без проверки на копии реальных данных. - Миграция несовместима со старым кодом, а выкат не разбит на этапы.
- Новая переменная окружения не проставлена в целевом окружении.
- Секрет попал в дифф.
- Обязательное по разделу 3 ревью не проводилось.
- Изменение ломает установленные мобильные клиенты, и нет ни минимальной версии, ни экрана обновления.
- Нет плана отката или не проверен бэкап под необратимую миграцию.
- Ключевой сценарий не пройден руками ни разу.
- Выкат в пятницу вечером или в пик нагрузки без человека, который останется наблюдать.
Пункт 14 не суеверие: цена инцидента складывается из времени до обнаружения. В российском SMB пик — утро понедельника, конец месяца (закрытие, сверки, отчётность) и распродажи маркетплейсов (11.11, «чёрная пятница», предновогодние недели); релиз, трогающий выгрузки или расчёты, в эти окна не едет.
13. Реестр принятых рисков
| Риск | Вероятность | Что будет | Признак срабатывания | Кто принял | Срок |
|---|---|---|---|---|---|
| Падает тест X (предсуществующее) | — | сценарий Y не покрыт | — | ||
| Флак Y, 2 из 10 | средняя | ложные падения CI | красный CI |
Незаписанный риск через месяц выглядит как ошибка, которую никто не заметил. Пустая графа «кто принял» значит, что риск не принят, а забыт: требуй имя.
Похожие навыки
Попробуйте этот навык
Зарегистрируйтесь и используйте навык «Чек-лист релиза» бесплатно.