GitHub/GitLab, CODEOWNERS, обязательные проверки, боты и борьба с их шумом. Что умеет статический анализ — в курсе Pro
Инструмент не меняет поведение команды. Меняет его настройка репозитория: то, что нельзя обойти, и то, что видно, не открывая документации.
Вы научитесь переносить договорённости из документов в конфигурацию, где они начинают действовать; настраивать уведомления так, чтобы их читали; и распознавать шум от ботов до того, как он обесценит человеческие замечания.
Что именно способны проверить анализаторы и линтеры — в теме Автоматизация курса Pro. Здесь — про встраивание в процесс.
Главная мысль урока: любое правило, которое команда согласовала, надо перенести в настройки. Иначе оно живёт в чьей-то памяти и работает избирательно.
| Договорённость | Где живёт технически |
|---|---|
| «Один ревьюер, два — для биллинга» | Правила защиты ветки + CODEOWNERS |
| «CI обязателен» | Обязательные проверки состояния |
| «Не мержим в устаревшую ветку» | «Require branches to be up to date» |
| «Не пушим в main напрямую» | Запрет прямого push, включая администраторов |
| «Описание PR обязательно» | Шаблон PR + проверка непустого описания |
| «PR до 400 строк» | Бот, помечающий размер меткой |
| «Секретов в коде нет» | gitleaks в обязательных проверках |
| «Багфикс = тест» | Покрытие изменённых строк в обязательных |
Пункт про администраторов важнее, чем кажется: если правила не распространяются на тимлида, они читаются как необязательные. «Include administrators» — одна галочка, меняющая восприятие всего процесса.
# .github/CODEOWNERS
* @team/backend
/billing/ @team/billing
/app/domains/auth/ @team/security
/infra/ @team/platform
*.sql @team/dba
/docs/ @team/backend @team/docsПорядок строк значим: применяется последнее совпадение, а не первое. Это источник неожиданностей — правило * в конце файла отменит все предыдущие.
Проверьте себя. Откройте настройки защиты ветки своего репозитория и сравните с тем, что команда считает обязательным. Найдётся расхождение.
Частая ошибка. Оставлять правила необязательными для администраторов. Это ровно те люди, чей пример определяет норму.
Обязательной проверка становится, когда её нарушение действительно должно останавливать мерж. Всё остальное — предупреждение.
Разумный состав обязательных: тесты, линтер и форматирование, типизация, сканер секретов, аудит зависимостей на высокую критичность, покрытие изменённых строк.
Разумный состав предупреждающих: общее покрытие проекта, метрики сложности, размер сборки, дублирование, уязвимости низкой критичности.
Критерий разделения: если проверка иногда падает по причинам, не связанным с качеством изменения, она не может быть обязательной. Нестабильная проверка в обязательных приводит к перезапускам «до зелёного», а это привычка, которая обесценивает все проверки сразу.
Отдельно про скорость. Обязательные проверки определяют минимальное время до мержа. Если CI идёт 25 минут, цикл из трёх раундов — это больше часа только ожидания. Что помогает: параллельные задачи вместо последовательных, быстрые проверки первыми (линтер за 10 секунд отсеет часть PR до запуска тестов), кэш зависимостей, запуск тестов только по затронутым областям на монорепозитории.
Проверьте себя. Сколько идёт ваш CI на PR? Сколько из этого времени — установка зависимостей?
Частая ошибка. Держать в обязательных нестабильную проверку. Одна такая учит команду перезапускать не глядя.
Автоматический комментарий работает, пока его читают. Порог наступает быстрее, чем кажется.
Что делает бота полезным:
payments.py:41-58» — из такого сообщения понятно, что делать.Что делает бота вредным: напоминание в каждом PR об одном и том же; дублирование того, что уже подсвечено в редакторе; замечания с высокой долей ложных срабатываний; поздравление с мержем.
Практический показатель здоровья: доля исправленных замечаний бота. Если девять из десяти закрываются как неактуальные, бот не помогает, а тренирует игнорировать предупреждения — включая настоящие.
Проверьте себя. Посмотрите последние десять PR: сколько комментариев от ботов и сколько от людей? Соотношение больше трёх к одному — повод сокращать.
Частая ошибка. Оценивать бота по числу найденного. Оценивать надо по доле исправленного.
Уведомления ломаются одинаково во всех командах: канал, куда падает всё, читать невозможно, поэтому его выключают, а вместе с ним теряются важные события.
Работающее правило: уведомление отправляется конкретному человеку и требует от него действия.
| Событие | Кому | Куда |
|---|---|---|
| Вас назначили ревьюером | ревьюеру | личное сообщение |
| Автор ответил на ваши замечания | ревьюеру | личное сообщение |
| Ваш PR получил замечания | автору | личное сообщение |
| PR ждёт дольше SLA | ревьюеру, затем в канал команды | эскалация |
| Сборка основной ветки упала | дежурному | личное + канал |
| Уязвимость высокой критичности | владельцу кода | личное |
| Новый PR открыт | никому | не уведомлять |
Последняя строка — самая полезная. Уведомление о каждом открытом PR не требует действия ни от кого конкретно и потому только приучает игнорировать канал.
Отдельный механизм, который стоит внедрить: ежедневная сводка PR, ждущих дольше SLA, с именами. Не как способ давления, а потому что забывают все, а список видят все.
Проверьте себя. Спросите двух коллег, читают ли они канал уведомлений о PR. Ответ покажет, работает ли схема.
Частая ошибка. Отправлять всё в общий канал вместо личных сообщений. Уведомление без адресата — не уведомление.
Несколько возможностей платформ, которые команды не используют, хотя они закрывают частые проблемы:
Черновики PR. PR, открытый как черновик, не запрашивает ревью, но показывает работу и запускает CI. Снимает потребность в комментариях «пока не смотри».
Предложение изменения. Ревьюер предлагает конкретную правку, автор применяет одной кнопкой. Уместно для мелочей — экономит раунд. Неуместно для содержательных замечаний: автор применит не разобравшись.
Стек PR. Второй PR открывается в ветку первого. Позволяет не ждать мержа предыдущего и разбивать работу без простоя.
Автомерж после проверок. Автор ставит галочку, PR мержится сам, когда CI зелёный и одобрения получены. Убирает ожидание «кто нажмёт кнопку».
Автоматическое переназначение. Если ревьюер не ответил в срок, запрос уходит следующему. Решает проблему отпусков без ручного вмешательства.
Проверьте себя. Какие из пяти пунктов используются в вашей команде?
Частая ошибка. Пользоваться предложением изменения для архитектурных замечаний. Автор применит и не поймёт, зачем.
Команда внедрила инструменты за квартал. Результат: время до мержа выросло с одного дня до трёх, канал уведомлений выключили все.
# .github/workflows/pr.yml
on: [pull_request]
jobs:
quality:
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt # 4 минуты, без кэша
- run: ruff check .
- run: mypy app/
- run: pytest # 18 минут, последовательно
- run: sonar-scanner
- uses: reviewdog/action-suggester@v1
with:
reporter: github-pr-review
level: info # комментирует всё
filter_mode: nofilter # включая нетронутые строкиПравила защиты ветки main:
✅ Require 2 approvals
✅ Require status checks: quality, sonar, codecov, size-limit, license-check
✅ Require conversation resolution before merging
✅ Dismiss stale approvals on new commits
❌ Include administratorsSlack #dev-notifications:
• PR opened • PR closed • commit pushed
• review requested • comment added • CI started
• CI finished • PR merged • branch deletedЧто видит опытный участник. Каждая настройка по отдельности разумна. Вместе они дают паралич.
CI идёт 25 минут, из них 4 — установка зависимостей без кэша, 18 — последовательные тесты. При трёх раундах это 75 минут чистого ожидания.
Dismiss stale approvals on new commits в сочетании с двумя обязательными одобрениями и медленным CI даёт замкнутый круг: автор правит опечатку, оба одобрения сбрасываются, надо снова искать двух людей и снова ждать 25 минут. Именно эта комбинация — главная причина роста до трёх дней.
Require conversation resolution делает блокирующим каждый комментарий, включая nit и info от reviewdog. А reviewdog настроен на level: info и filter_mode: nofilter — то есть комментирует всё подряд, включая строки, которых автор не касался. Получается: бот оставил сорок информационных замечаний по чужому коду, и все сорок надо закрыть руками, чтобы смочь смержить.
Пять обязательных проверок, среди которых license-check и size-limit — они падают по причинам, не связанным с качеством изменения, и потому не должны блокировать.
Include administrators выключено: правила не распространяются на тех, чьё поведение задаёт норму.
В Slack девять типов событий, включая commit pushed и CI started. Канал нечитаем, поэтому выключен, — и вместе с ним потеряны уведомления о падении основной ветки.
Комментарии к конфигурации:
Правила ветки · blocker
Dismiss stale approvals+ 2 обязательных одобрения + CI на 25 минут — это и есть три дня до мержа. Правка опечатки сбрасывает оба одобрения и требует полного цикла заново. Предлагаю: одно обязательное одобрение (два — только для/billingи/auth) и сброс одобрений только при изменениях в коде, а не в любом коммите.
pr.yml:8· blockerfilter_mode: nofilterзаставляет бота комментировать строки, которых автор не касался. Вместе сRequire conversation resolutionэто означает, что для мержа надо вручную закрыть десятки информационных замечаний по чужому коду. Нуженfilter_mode: addedиlevel: warning.
Require conversation resolution · major Делает блокирующим любой комментарий, включая
nit. Это противоречит договорённости, чтоnitне блокирует мерж. Предлагаю выключить и полагаться на явныеblockerв тексте.
pr.yml:5· major 4 минуты на установку зависимостей без кэша, 18 минут последовательных тестов. Кэш плюс разбиение тестов на параллельные задачи сократит CI до 6–7 минут. При трёх раундах это экономия часа на каждом PR.
Обязательные проверки · major
license-checkиsize-limitпадают по причинам, не связанным с качеством изменения. В обязательных они приведут к привычке перезапускать не глядя. Перевести в предупреждающие.
Include administrators · major Правила не действуют на администраторов. Это читается командой как «правила необязательные», и никакие объяснения этого не перебьют. Включить.
Slack · major Девять типов событий в один канал. Канал уже выключили все, а значит, потеряны уведомления о падении main. Оставить в канале только эскалацию по SLA и падение основной ветки; назначение ревьюером и ответы автора — в личные сообщения.
Чем закончилось.
Правила ветки main:
✅ 1 approval (2 — /billing, /auth через CODEOWNERS)
✅ Обязательные: tests, lint, types, gitleaks, diff-coverage
⚠️ Предупреждающие: sonar, size-limit, license-check
✅ Require branches to be up to date
✅ Include administrators
❌ Dismiss stale approvals (только при изменении кода)
❌ Require conversation resolution
CI: кэш зависимостей + 4 параллельные задачи → 6 минут
reviewdog: filter_mode: added, level: warning, максимум 10 замечаний
Slack #dev-alerts: только падение main и эскалация SLA
Личные сообщения: назначение ревьюером, ответы автора, критичные уязвимости
Ежедневная сводка: PR, ждущие дольше SLA, с именамиЧерез месяц: время до мержа — 5 часов, комментариев от ботов на PR — 2 вместо 40, канал #dev-alerts читают, потому что там раз в неделю появляется что-то важное.
Показательно, что ни один инструмент не был удалён. Изменились только настройки — и это вся разница между парализованным процессом и работающим.
Include administrators в правилах защиты основной ветки. Одна галочка, меняет восприятие всего процесса.Dismiss stale approvals вместе с вашим числом обязательных одобрений и временем CI. Частая скрытая причина медленного ревью.filter_mode: added для ботов, если они комментируют нетронутые строки.PR opened и commit pushed.КОНФИГУРАЦИЯ договорённости перенесены в настройки репозитория
АДМИНИСТРАТОРЫ правила распространяются на всех
НАЗНАЧЕНИЕ CODEOWNERS настроен; порядок строк проверен (последнее совпадение)
ОБЯЗАТЕЛЬНОЕ только стабильные проверки; нестабильные — предупреждающие
СКОРОСТЬ CI параллелен, зависимости кэшируются, быстрые проверки первыми
СБРОС Dismiss stale approvals согласован с числом одобрений и временем CI
БОТЫ только изменённые строки, ограничение количества, одно обновляемое сообщение
ЭФФЕКТ измеряется доля исправленных замечаний бота, а не найденных
УВЕДОМЛЕНИЯ адресные и требующие действия; в канал — только эскалация
СВОДКА ежедневный список PR, нарушивших SLA, с именамиКакие числа смотреть, чтобы понять, работает ли настроенное, — Метрики процесса. Что именно проверяют анализаторы — Автоматизация. Процессные договорённости, которые эти настройки закрепляют, — Процесс и workflow.
Ключевая мысль: паралич процесса обычно вызван не отсутствием инструментов, а сочетанием настроек, каждая из которых по отдельности разумна.
Далее: Метрики процесса review