Code Quality и статический анализ
Подключаем встроенный анализ качества кода и понимаем, как он попадает в Merge Request.
Code Quality — встроенная в GitLab фича, которая прогоняет анализаторы кода и показывает в MR появившиеся и исправленные замечания.
Зачем автоматическое качество
Ревьюеру тяжело держать в голове все правила стиля, цикломатическую сложность и дублирование. Автоматический анализатор делает это последовательно и беспристрастно, а GitLab показывает разницу: какие замечания добавил именно этот MR, а какие исправил. Это смещает фокус ревью с придирок к стилю на смысл изменений.
За этим стоит важная мысль о разделении труда между машиной и человеком. Машина блестяще ловит формальное: длинные функции, дубли, нарушения стиля, подозрительные конструкции — то, что описывается правилами. Человек незаменим там, где нужен контекст: правильно ли выбрана абстракция, понятно ли имя, нет ли логической ошибки в бизнес-правиле. Когда анализатор берёт на себя формальную часть, ревью перестаёт вырождаться в споры о пробелах и переносится на содержание. Команды, которые этого не сделали, часто тонут в «бикешеддинге» — бесконечных придирках к мелочам, потому что мелочи проще заметить, чем разобраться в сути изменения.
Подключение через шаблон
GitLab поставляет готовый шаблон, который достаточно включить:
include:
- template: Code-Quality.gitlab-ci.yml
# джоба code_quality придёт из шаблона и запустится в стадии testШаблон добавляет джобу code_quality, которая под капотом запускает движок анализа (на базе Code Climate) и выдаёт отчёт в стандартном формате codequality.
Стоит понимать, что прячется за одной строкой include. Шаблон — это кусок готового YAML, который GitLab подмешивает в ваш пайплайн на этапе сборки конфигурации. Внутри он описывает джобу, которая запускает контейнер с движком Code Climate; движок сам определяет языки в репозитории и подбирает подходящие плагины-анализаторы. Удобство в том, что вам не надо знать, какой линтер для какого языка нужен. Платой становится непрозрачность: джоба тянет дополнительный образ и под капотом обычно нуждается в Docker (часто через dind), а на ограниченных раннерах это не всегда заводится сразу. Поэтому на практике многие команды для своего основного языка предпочитают второй путь — отдать отчёт от собственного линтера.
Свой анализатор
Можно и не использовать шаблон, а отдать отчёт качества от своего линтера, приведённый к нужному формату:
lint:
stage: test
image: node:20
script:
- npm ci
- npx eslint . -f gitlab -o gl-code-quality-report.json
artifacts:
reports:
codequality: gl-code-quality-report.jsonКлюч reports: codequality заставляет GitLab показать замечания в diff Merge Request: рядом со строками появятся иконки с найденными проблемами.
Ключевая деталь — флаг -f gitlab (форматтер). ESLint по умолчанию печатает отчёт в своём виде, который GitLab не понимает. Форматтер gitlab приводит вывод к требуемому JSON-формату codequality: списку объектов с описанием проблемы, путём к файлу, номером строки и отпечатком (fingerprint). Многие популярные линтеры (ESLint, RuboCop, golangci-lint и другие) либо имеют такой форматтер из коробки, либо умеют отдавать формат Code Climate, совместимый с GitLab. Этот путь прозрачнее шаблона: вы точно знаете, какой линтер и с какими правилами запускается, и контролируете его конфигурацией в репозитории.
Про fingerprint стоит сказать отдельно, потому что от него зависит корректность дельты. Каждое замечание получает стабильный отпечаток — хэш, который не меняется, если проблема та же, даже когда строки сдвинулись из-за правок выше по файлу. Благодаря этому GitLab понимает, что замечание «то же самое», а не «исчезло и появилось новое», и не показывает ложных «исправлений» при простом сдвиге кода.
Что это меняет в процессе
В виджете MR появляется блок «Code Quality» с числом ухудшений и улучшений. Команда может договориться не сливать MR, ухудшающий метрики, превращая качество в измеримый критерий, а не вкусовщину.
Здесь важно не перегнуть палку. Жёсткий гейт «ни одного нового замечания» звучит дисциплинированно, но на легаси-базе с тысячами накопленных проблем он парализует работу: любой невинный MR краснеет из-за чужого долга. Зрелые команды настраивают политику по принципу «не ухудшать»: блокируют только новые замечания, внесённые именно этим MR, а старый долг разгребают отдельными задачами. Так качество растёт постепенно и не превращается в стену, об которую разбивается каждая поставка.
Как работает под капотом
Джоба анализа формирует JSON-отчёт в формате codequality (список замечаний с файлом, строкой и описанием). GitLab сравнивает отчёт текущей ветки с отчётом целевой ветки и вычисляет дельту — что добавилось, что ушло. Эту дельту он рендерит в виджете MR и в самом diff. Полный список замечаний при этом не блокирует, если вы сами не настроите гейт.
Сравнение работает по тем самым fingerprint-ам. GitLab берёт множество отпечатков из отчёта целевой ветки и множество из текущей и считает разницу множеств: отпечатки, которых не было в целевой, — это новые замечания (ухудшение); отпечатки, что были в целевой, но исчезли, — исправленные (улучшение). Поэтому виджет показывает не сухой счётчик «всего проблем», а именно вклад данного MR. И именно поэтому стабильность fingerprint так важна: сломанный отпечаток превратил бы каждый сдвиг строк в фантомную дельту.
Сравнение с GitHub Actions
Как и с тестами, разница в степени «встроенности». В GitHub Actions нет родного виджета Code Quality в pull request: линтеры запускают через сторонние actions, а замечания выводят либо в лог, либо как аннотации к строкам через специальный вывод, либо подключают внешние платформы вроде SonarCloud или того же Code Climate отдельным сервисом. GitLab же держит весь цикл — анализ, отчёт, дельту, отображение в diff — в одной платформе, без внешних интеграций и токенов. Минус прежний: гибкость и каталог готовых проверок у экосистемы Actions шире, тогда как у GitLab вы получаете цельный, но более рамочный опыт из коробки.
Частые ошибки
- Ожидать, что Code Quality сам заблокирует MR — по умолчанию он информирует, а не блокирует; гейт настраивают отдельно.
- Отдавать отчёт не в формате
codequality— тогда виджет ничего не покажет. - Запускать тяжёлый анализ на каждый push без необходимости — лучше ограничить
rulesна MR. - Забыть форматтер (например,
-f gitlabу ESLint) — линтер отработает, но виджет останется пустым. - Ставить гейт «ноль замечаний» на легаси-базе — он заблокирует невинные MR из-за чужого накопленного долга.
Итоги
- Code Quality показывает в MR дельту замечаний: что добавил и что исправил данный MR.
- Подключается готовым шаблоном
include: templateили своим линтером с отчётомcodequality. - По умолчанию информирует, а не блокирует; гейт настраивают отдельно.
- Дельта считается по стабильным fingerprint-ам замечаний, а не по номерам строк.
- Разумный гейт блокирует только новые замечания MR, а не весь накопленный долг.