GitLab CI/CD

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

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

О 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 полностью конфигурируется с помощью одного файла в формате 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 в каждом джобе будет разный.