ESLint в GitLab CI

ESLint используется как статический анализатор кода, который выявляет ошибки, нарушения стиля и потенциально проблемные конструкции в JavaScript и TypeScript-проектах. При использовании в пайплайнах GitLab CI/CD линтинг перестаёт быть локальной практикой разработчика и становится обязательным этапом проверки качества кода на уровне репозитория.

Основная цель интеграции заключается в том, чтобы любые изменения проходили автоматическую проверку до попадания в основную ветку. Это снижает вероятность накопления технического долга и стандартизирует кодовую базу.


Базовая модель запуска ESLint в CI

В контексте GitLab CI ESLint обычно выполняется как отдельная job в пайплайне, которая:

  • устанавливает зависимости проекта
  • запускает линтер
  • завершает job с ошибкой при наличии нарушений

Минимальная логика сводится к следующему принципу: любое нарушение правил = падение pipeline.


Подготовка проекта к CI-линтингу

Перед подключением ESLint в GitLab CI важно, чтобы локальная конфигурация уже существовала:

  • .eslintrc.js / .eslintrc.json / eslint.config.js
  • корректно установленные зависимости
  • npm-скрипт для запуска линтера

Пример package.json:

{
  "scripts": {
    "lint": "eslint ."
  }
}

Такой подход позволяет унифицировать запуск: CI вызывает те же команды, что и разработчик локально.


Базовая конфигурация .gitlab-ci.yml

Типовой pipeline для ESLint выглядит следующим образом:

stages:
  - lint

eslint:
  stage: lint
  image: node:20
  cache:
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run lint

Ключевые элементы:

image

  • фиксирует версию Node.js
  • обеспечивает воспроизводимость окружения

cache

  • ускоряет установку зависимостей
  • снижает нагрузку на CI

script

  • выполняет установку зависимостей
  • запускает ESLint через npm-скрипт

Оптимизация установки зависимостей

В CI важно различать npm install и npm ci:

  • npm install может менять lock-файл
  • npm ci гарантирует строгое соответствие package-lock.json

В контексте CI предпочтителен именно npm ci, поскольку он:

  • быстрее
  • детерминирован
  • исключает неожиданные изменения зависимостей

Отдельный stage для качества кода

В зрелых пайплайнах ESLint выделяется в отдельную стадию:

stages:
  - install
  - lint
  - test

install:
  stage: install
  image: node:20
  script:
    - npm ci

lint:
  stage: lint
  image: node:20
  script:
    - npm ci
    - npm run lint

Такой подход позволяет:

  • переиспользовать установку зависимостей
  • параллелить проверки
  • чётко разделять ответственность стадий

Работа с monorepo

В монорепозиториях ESLint часто запускается выборочно:

Вариант с фильтрацией путей

lint:
  script:
    - npm ci
    - npx eslint "packages/**/src/**/*.{js,ts}"

Вариант с Turborepo / Nx

При использовании систем управления монорепо ESLint интегрируется как задача графа зависимостей:

  • lint запускается только для изменённых пакетов
  • используется caching между пайплайнами
  • уменьшается время CI

Использование кэширования ESLint

Помимо node_modules, можно кэшировать внутренние данные ESLint (особенно в больших проектах).

Пример:

cache:
  paths:
    - node_modules/
    - .eslintcache

Запуск:

eslint . --cache

Преимущества:

  • повторный запуск анализирует только изменённые файлы
  • значительное ускорение CI на больших кодовых базах

Fail-fast стратегия

В CI ESLint должен работать в режиме строгой валидации:

  • warnings трактуются как ошибки
  • процесс завершается с ненулевым exit code

Пример:

eslint . --max-warnings=0

Это исключает ситуацию, когда код с предупреждениями попадает в основную ветку.


Форматы отчётов ESLint для GitLab

GitLab CI поддерживает артефакты, которые можно использовать для отображения результатов линтинга.

JSON-отчёт

eslint . -f json -o eslint-report.json

JUnit-формат (через плагин)

eslint . -f junit -o eslint-junit.xml

В .gitlab-ci.yml:

lint:
  script:
    - npm ci
    - npm run lint -- -f json -o eslint-report.json
  artifacts:
    reports:
      codequality: eslint-report.json

Code Quality интеграция в GitLab

GitLab может отображать результаты линтинга в Merge Request через Code Quality отчёты.

Для этого ESLint вывод должен быть преобразован в формат GitLab Code Climate.

Пример использования конвертера:

npx eslint . -f codeclimate > gl-code-quality-report.json

Конфигурация CI:

artifacts:
  reports:
    codequality: gl-code-quality-report.json

Результат:

  • аннотации в Merge Request
  • inline-комментарии
  • визуализация проблем прямо в diff

Разделение линтинга по типам файлов

В крупных проектах ESLint часто запускается отдельно:

lint-js:
  script:
    - eslint "src/**/*.js"

lint-ts:
  script:
    - eslint "src/**/*.ts"

Это позволяет:

  • изолировать проблемы разных языков
  • ускорить диагностику
  • параллелить выполнение jobs

Интеграция с pre-commit и CI

Хотя CI является финальной точкой проверки, ESLint часто дублируется на уровне pre-commit:

  • Husky
  • lint-staged

CI при этом остаётся источником истины:

  • локальные проверки могут быть отключены
  • CI всегда выполняет полный анализ

Управление правилами в CI

Иногда требуется различать локальный и CI-режимы:

Строгий CI-конфиг

eslint . --config .eslintrc.ci.json

Особенности CI-конфига:

  • запрещены предупреждения
  • активированы дополнительные security rules
  • отключены компромиссные правила разработки

Параллельное выполнение с тестами

ESLint job часто запускается параллельно с тестами:

stages:
  - lint
  - test

lint:
  stage: lint
  script:
    - npm run lint

test:
  stage: test
  script:
    - npm test

Такой pipeline сокращает общее время выполнения за счёт параллелизма.


Ошибки интеграции и типовые проблемы

Увеличенное время CI

Причины:

  • отсутствие cache
  • использование npm install
  • отсутствие ограничения scope линтинга

Разные версии ESLint

Проблема возникает при:

  • глобальной установке локально
  • несовпадении lock-файла

Решение:

  • всегда использовать npx eslint или npm script
  • фиксировать версии зависимостей

Конфликты конфигурации

При монорепо возможны ситуации:

  • несколько .eslintrc
  • разные правила в пакетах

Решение:

  • единая root-конфигурация
  • использование overrides

Масштабирование ESLint в CI

При росте проекта ESLint становится узким местом, поэтому применяются:

  • incremental linting
  • caching .eslintcache
  • разделение по пакетам
  • запуск только изменённых файлов через git diff

Пример:

eslint $(git diff --name-only origin/main | grep '\.js$')

Поведение при Merge Request pipeline

В GitLab CI ESLint часто запускается только на MR:

lint:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Это снижает нагрузку на main-ветку и ускоряет feedback loop для разработчиков.


Связь ESLint с качеством доставки

Встраивание ESLint в GitLab CI/CD превращает его из инструмента локального анализа в механизм управления качеством:

  • стандартизация кода на уровне команды
  • предотвращение деградации архитектуры
  • автоматическое enforcement правил
  • единый источник истины для стиля и безопасности кода