GitLab CI/CD

Что-то вроде GitHub Actions, но для GitLab. Настраиваем сборку проекта.

Время чтения: 8 мин

О GitLab

Секция статьи "О GitLab"

GitLab — популярный веб-сервис для совместной разработки и поддержки программного обеспечения. Вы можете работать с Git-репозиториями, управлять задачами, обсуждать правки с вашей командой, писать wiki-документацию, оценивать качество, выпускать релизы и даже мониторить работающие программы — и всё это в одном месте.

Кратко

Секция статьи "Кратко"

GitLab CI — инструмент, встроенный в GitLab для автоматизации рутинных задач, возникающих в процессе разработки программного обеспечения. Спектр таких задач огромен и отличается от проекта к проекту, но основные — это тестирование, статический анализ, проверка стиля написания кода и деплой (выпуск) приложения. GitLab CI — конкурент другого популярного инструмента, GitHub Actions. Эти два сервиса во многом похожи, но есть некоторые отличия.

Пример

Секция статьи "Пример"

Допустим, мы договорились в команде об особых правилах оформления кода при помощи EditorConfig, установили его как дев-зависимость и сделали его доступным с помощью команды npm run editorconfig. Можно запускать проверку каждый раз перед коммитом, но всегда будут ситуации, когда это забудут сделать, и код, оформленный неправильно, попадёт в репозиторий. Здесь приходит на помощь GitLab CI/CD — достаточно создать в корне проекта файл .gitlab-ci.yml со следующим содержанием:

        
          
          EditorConfig:  image: node:lts  script:    - npm ci    - npm run editorconfig
          EditorConfig:
  image: node:lts
  script:
    - npm ci
    - npm run editorconfig

        
        
          
        
      

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

Как пользоваться

Секция статьи "Как пользоваться"

Основные понятия

Секция статьи "Основные понятия"

Основной сущностью в GitLab CI/CD является пайплайн (pipeline) — конвейер, который может состоять из:

  • джобов (jobs), описывающих что нужно выполнить;
  • этапов (stages), указывающих когда или в какой последовательности нужно выполнить джобы.

Джобы в одном этапе обычно выполняются параллельно. Если все джобы завершились успешно, выполнение переходит к следующему этапу и так далее. Если любой из джобов завершился ошибкой, то выполнение останавливается, и весь пайплайн (обычно) считается проваленным.

Создаём .gitlab-ci.yml

Секция статьи "Создаём .gitlab-ci.yml"

GitLab CI полностью конфигурируется с помощью одного файла в формате YAML, который нужно создать в корне проекта — .gitlab-ci.yml.

Джобы часто могут иметь одинаковые свойства, например, образ среды, в которой выполняются действия, предварительные команды и т. д. Чтобы не повторять их каждый раз, нужно объявить их в секции default. Если какому-то джобу нужны другие параметры, можно указать их внутри этого джоба, и они перезапишут глобальные параметры.

В первую очередь нужно указать Docker-образ (подробнее в статье «Что такое Docker»), в котором будут выполняться джобы. В большинстве случаев нам подойдёт официальный образ Node.js node:lts — это означает, что наши команды будут выполняться внутри операционной системы Linux с установленными Node.js, npm и даже Yarn. Про буквы lts можно почитать в разделе про версионирование Node.js.

        
          
          default:  image: node:lts
          default:
  image: node:lts

        
        
          
        
      

Задаём подготовительные команды

Секция статьи "Задаём подготовительные команды"

При работе с CI/CD во фронтенд-проектах чаще всего перед выполнением основного действия необходимо установить зависимости. Для этого мы можем указать их в секции before_script — эти команды будут выполняться в каждом джобе перед основным действием.

        
          
          default:  image: node:lts  before_script:    - npm -v    - npm install
          default:
  image: node:lts
  before_script:
    - npm -v
    - npm install

        
        
          
        
      

Указываем этапы

Секция статьи "Указываем этапы"

Предположим, что мы хотим запускать сначала проверку кодовой базы с помощью EditorConfig и Stylelint, а потом, если они обе завершатся успешно, запустить тесты. В этом примере можно выделить два этапа: стиль кода и тесты. Определить этапы можно при помощи ключевого слова stages:

        
          
          stages:  - Стиль кода  - Тесты
          stages:
  - Стиль кода
  - Тесты

        
        
          
        
      

Описываем джобы и задаём команду

Секция статьи "Описываем джобы и задаём команду"

Теперь укажем все три джоба. Для этого мы вначале указываем название джоба, указываем его этап при помощи ключевого слова stage и передаём список команд в script. В нашем примере каждый джоб будет запускать по одному npm-скрипту.

        
          
          default:  image: node:lts  before_script:    - npm -v    - npm cistages:  - Стиль кода  - ТестыEditorConfig:  stage: Стиль кода  script:    - npm run editorconfigStylelint:  stage: Стиль кода  script:    - npm run stylelintАвтотесты:  stage: Тесты  script:    - npm run test
          default:
  image: node:lts
  before_script:
    - npm -v
    - npm ci

stages:
  - Стиль кода
  - Тесты

EditorConfig:
  stage: Стиль кода
  script:
    - npm run editorconfig

Stylelint:
  stage: Стиль кода
  script:
    - npm run stylelint

Автотесты:
  stage: Тесты
  script:
    - npm run test

        
        
          
        
      

А вот схематичное представление конфигурации выше:

Схема пайплайна
Конфигурация сначала проверяет стиль кода и, если он верный, запускает тесты.

Продвинутое использование

Секция статьи "Продвинутое использование"

Запуск вручную

Секция статьи "Запуск вручную"

Если мы хотим запускать определённый джоб вручную, то нужно добавить when: manual:

        
          
          job:  script: npm run deploy  when: manual
          job:
  script: npm run deploy
  when: manual

        
        
          
        
      

Продолжение при провале

Секция статьи "Продолжение при провале"

По умолчанию при провале любого джоба весь пайплайн отмечается как проваленный, и оставшиеся джобы не выполнятся. Однако бывают ситуации, когда этого поведения хочется избежать. Например, мы добавили джоб с тестами в только что появившейся версии Node.js и просто хотим видеть проблемы, которые потенциально нужно исправить в будущем. Здесь придёт на помощь allow_failure: true:

        
          
          job:  image: node:latest  script: npm run test  allow_failure: true
          job:
  image: node:latest
  script: npm run test
  allow_failure: true

        
        
          
        
      

Выполнение джобов по условию

Секция статьи "Выполнение джобов по условию"

GitLab даёт доступ к большому количеству переменных окружения с полезной информацией. Например, $CI_COMMIT_BRANCH содержит текущую ветку, $CI_COMMIT_SHORT_SHA — короткий хеш коммита, $CI_PIPELINE_SOURCE — источник вызова текущего пайплайна и так далее. С их помощью мы можем запускать определённые джобы при соблюдении заданных условий. Для этого нужно объявить одну или несколько секций rules.

Вот такой джоб будет выполняться только для коммитов в ветку main:

        
          
          job:  script: npm run deploy-to-production  rules:    - if: '$CI_COMMIT_BRANCH == "main"'
          job:
  script: npm run deploy-to-production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

        
        
          
        
      

Запуск по расписанию

Секция статьи "Запуск по расписанию"

В отличие от GitHub Actions, в GitLab CI/CD запуск пайплайнов по расписанию настраивается только в веб-интерфейсе. Для этого нужно открыть страницу репозитория и выбрать CI/CD → Schedules. Перед нами откроется список уже существующих правил и кнопка добавления нового. В форме добавления можно указать название правила, выбрать интервал из списка или указать свой в синтаксисе Cron. Последним важным полем является ветка — при срабатывании правила пайплайн запустится, как будто был запушен код в этой ветке. Отличие в том, что переменная $CI_PIPELINE_SOURCE будет содержать значение schedule.

Серия джобов

Секция статьи "Серия джобов"

Ещё одна типичная задача — прогнать тесты в разных версиях Node.js. Можно для каждой версии создать вручную джоб, а можно указать список переменных:

        
          
          Unit Tests:  script: node -v  image: ${NODE_VERSION}  parallel:    matrix:      - NODE_VERSION: ["node:14", "node:16", "node:17"]
          Unit Tests:
  script: node -v
  image: ${NODE_VERSION}
  parallel:
    matrix:
      - NODE_VERSION: ["node:14", "node:16", "node:17"]

        
        
          
        
      

В примере выше мы объявили список NODE_VERSION из трёх элементов. GitLab создаст три джоба с именами: «Unit Tests [node:14]», «Unit Tests [node:16]» и «Unit Tests [node:17]», а потом в каждом джобе заменит все места использования переменной NODE_VERSION. Поэтому image в каждом джобе будет разный.