Gitlab триггеры и для каких тестов их стоит использовать?

Саша Воробей
7 min readJul 18, 2020

--

Пришлось столкнуться с использованием триггеров в Gitlab для запуска разных тестов и хочется в данной статье рассказать какие есть виды триггеров в Gitlab, в чем их разница и для каких тестов какой вид триггера может лучше всего подойти.

План будет следующим:

  • Расскажу что такое триггер, какие виды триггеров есть в гитлаб и в чем их разница.
  • Дальше на примере тестов поделюсь мнением какие тесты каким триггером лучше всего запускать.

Кто и так знает что такое триггер, предлагаю перейти на обзор видов триггеров в Gitlab или их применение в тестировании.

О триггерах

Триггер — по-хорошему это вид задачи, которая в определенный момент времени запускает выполнение другой задачи. Триггером например может быть:

  • Задача которая отправляет запрос в Jenkins через его API для необходимости запустить пайплайн диплоя приложения при релизе какого-то компононета.
  • Задача в пайплайне Gitlab`а при старте которой запускается пайплайн из другого репозитория.

При этом обычно используя триггеры, пользователю не всегда бывает важным дождаться выполнения стриггериной задачи. Достаточно просто запустить задачу. Например: после прохождения всего пайплайна, триггер запускает задачу, которая собирает статистику по пройденному пайплайну.

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

Пример триггера, который не дожидается выполнения стригеренного пайплайна.
Триггер ожидает когда завершиться стригеренный пайплайн.

Раз речь идет про Gitlab то оставлю тут ссылку на документацию по триггерам из Gitlab.

Виды триггеров в гитлаб.

Существует два основных вида триггеров.

По факту и один и другой вид триггеров предназначен для одной и той же цели — запустить пайплайн из другого репозитория. Но у каждого из них есть явные отличия. Рассмотрим по-порядку каждый из них.

Multi-project pipelines (Cross-project triggers)

Первое что хочется отметить, что не смотря на то что в документации (на начало 2020 года) написано что этот триггер доступен для Premium и Silver плана, он на самом деле доступен для всех планов Gitlab!

  1. Для того чтобы создать триггер, необходимо добавить в файл .gitlab-ci.yml следующий код:
job:   
stage: test
trigger:
project: another/project
branch: dev-stable
# Больше примеров находится в документации.

То есть синтаксис достаточно прост, добавили слово trigger в нём указали в каком проекте триггерить пайплайн и из какой ветки.

В результате, когда пайплайн дойдет до этой джобы — триггер запустит пайплайн указанного проекта. Но в данной записи родительский пайплайн не будет ждать завершения дочернего, поэтому джоба завершиться и пайплайн пойдет выполняться дальше.

2. Для ожидания завершения пайплайна используется конструкция: strategy: depend

job:   
stage: test
trigger:
project: another/project
branch: dev-stable
strategy: depend

Всё — родитель ждет своего потомка.

3. Такой вид триггера имеет ограниченный список доступных инструкций для джобы.

Судя по документации список доступных инструкций такой:

  • stage — на каком этапе запустить джобу.
  • allow_failure — триггер, который ждет дочерний пайплайн и дочерний пайплайн завершается неудачей, влиять на правила мержа не будет
  • rules — все правила работают как и в обычной джобе. Но будьте внимательны, что when урезан, и он так же урезан с применением rules
  • only and except — работает как и для обычной джобы
  • when (only with on_success, on_failure, and always values) — вот тут интересно, то есть возможность вручную запустить джобу у данного триггера нет. Обидно =(
  • extends — работает как и для обычной джобы, но если у базовой джобы используется параметр не входящий в данный список — джоба упадет.

То есть как вы обратили внимание, в списке нет scripts, variables

Добавлю еще от себя что еще работает, но не описано в доке:

  • variables — можно в стандартном формате указать переменные окружения, при это тут важно то, что все переменные окружения указанные в родительском пайплайне будут наследованы дочерним. Поэтому будьте внимательны.
  • needs — то есть вы можете запустить триггер после определенной джобы.

4. Перезапуск триггера не поменяет статус в MergeRequest.

В тестировании часто возникают flaky тесты из-за которых иногда приходится перезапустить джобу. Но вот такой workaround не прокатит с триггером, перезапустив упавший стриггеренный пайлайн — на результат триггера это никак не повлияет.

А сама джоба триггера вообще является не кликабельной, поэтому и его самого перезапустить нельзя

5. Нет возможности запустить триггер по токену.

Здесь нужно кое что объяснить, дело в том что у всех триггеров есть ограничения на запуск дочернего пайплайна из защищенной ветки другого репозитория.

Такое ограничение сделано для безопасности. Так как банально, злоумышленник может стриггерить из своего репозитория — пайплайн вашего проекта с другими переменными окружениями и если это был пайплайн, который разворачивает приложение на прод — то жди беды.

Но это ограничение можно обойти в трех случаях:

  • Если пользователь запустивший джобу является мейнтейнром дочернего проекта.
  • Если пользователю разрешен мерж в защищенную ветку.
  • Если дочерний пайплайн тригеритися с использованием преднастроенного токена

Так вот данный вид триггера не работает с преднастроенным токеном. То есть отсюда вывод, что его возможно запустить на защищенной ветке, только если человек конкретному человеку выданы соотвествующие права.

Плюсы данного вида триггеров:

  • Умеет дожидаться завершения дочернего пайплайна
  • Прост в настройке, не требует вызова через API
  • Переменные окружения наследуются от родительского пайплайна

Минусы:

  • Нельзя перезапускать триггер, перезапуск дочернего пайплайна не влияет на триггер.
  • Нельзя сделать ручным запуском. Иногда это действительно может быть полезным.
  • Нельзя использовать токен триггера для запуска пайплайна на защищенной ветке.

Triggers through the API

Требуется чтобы в окружении в котором будет запускаться триггер была установлена утилита curl

  1. Для создания используется curl и script-секция в джобе.
job:   
stage: test
script:
- curl --request POST --form token=$TOKEN --form ref=master https://gitlab.example.com/api/v4/projects/9/trigger/pipeline

2. Нет механизма для ожидания завершения дочернего пайплайна.

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

3. Нет никаких ограничений на настройку джобы кроме variables.

Передача variables в данном типе триггера сильно отличается от предыдущего, так как их явно нужно указывать не в джобе, а в запросе. Отсюда следует то, что variables не наследуются от родительского пайплайна. Пример настройки (дока):

curl --request POST \   
--form token=$TOKEN \
--form ref=master \
--form "variables[UPLOAD_TO_S3]=true" \ https://gitlab.example.com/api/v4/projects/9/trigger/pipeline

4. Триггер через API можно перезапускать.

Так как в данном случае триггер является обычной джобой которая делает запрос в API Gitlab, то её можно перезапускать как обычную джобу.

5. Умеет триггерить джобу используя предастроенный токен.

Возможно вы обратили внимание что во всех примерах с curl в данные запроса добавлялась переменная token в которую мы как раз должны поместить сгенерированный токен из как указанно тут.

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

6. Дочерний пайплайн можно визуализировать в родительском.

Почему я вынес это в отдельный пункт? Потому что при обычном использовании данного триггера он просто отправит запрос и дочерний пайплайн запустится.

НО! Если вместо токена использовать переменную окружения $CI_JOB_TOKEN , то Gitlab запустит дочерний пайплайн и отобразит его в родительском.
Пример:

curl --request POST \   
--form token=$CI_JOB_TOKEN \
--form ref=master \ https://gitlab.example.com/api/v4/projects/9/trigger/pipeline

Почитать об этом можно тут

Плюсы данного вида триггеров:

  • Можно перезапускать триггер, перезапуск дочернего пайплайна не влияет на результат триггера.
  • Джобу с триггером можно настраивать без ограничений в доступных инструкциях
  • Можно использовать токен триггера для запуска пайплайна на защищенной ветке.

Минусы:

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

Какие виды тестов с помощью какого триггера запускать?

В данном разделе я хочу поделиться наблюдениями о том, какие тесты с помощью какого типа триггера стоит запускать и почему. И сразу хочу отметить что у всех требования к тестированию отличаются и поэтому описанное мною мнение может может не совпадать с реальными требованиями.

Тестирование безопасности и тестирование производительности

За весь мой опыт тестирования, тестирование безопасности и производительности приложений всегда находилось вне основного процесса тестирования. Под этим я понимаю то, что его не встраивают обычно в основной пайплайн и не делают тестирование влияющим на результат MRa. Чаще всего основной пайплайн с тестированием UI, API. и прочего проходил, приложение диплоилось на тестовый (stage)стенд и только после этого на него натравливалось тестирование безопасности или производительности, которые собирают данные, анализирует, составляет отчеты и по результатам отчета ответственные выносят вердикт.

Если на Вашем продукте используется такой же подход, то на данный вид тестирования отлично ложиться использование триггера через API или же можно и cross-project триггер но без ожидания завершения.

Пример:

  1. Есть два репозитория: приложения и репозиторий со скриптом тестирования на безопасность или производительности.
  2. В репозитории приложения может запуститься пайплайн проверяющий основной функционал..
  3. После успешного прохождения его мержат в в основную ветку и новый функционал разворачивается на тестовом стенде.
  4. В пайплайне где диплится приложение дергают триггером тесты и направляют их на задиплоиное приложение.
  5. Пайплайн успешно завершается и сообщает всем ответственным что приложение развернулось.
  6. В этот момент тесты на безопасность и производительность могут тестировать приложение и в конечном итоге через пару минут выдать результат.

Плюсами в данном случае я считаю то, что:

  1. Это полностью автоматизированный процесс.
  2. Разработчики не завязаны на тест безопасности и могут спокойно продолжать работать.

Тестирование интерфейсов, API

Хм, странно, зачем нам может потребоваться запускать с помощью триггера тесты на интерфейс?

Как и в тестировании безопасности мы можем запускать Happy-Path тесты после того как в основной ветки задиплоится новое приложение. Тогда в данном случае у нас могут быть два случая:

  • Во-первых эти тесты могут храниться рядом с кодом приложения и тогда достаточно в том же пайплайне настроить джобу после диплоя и там запускать эти тесты
  • Во-вторых тесты могут находиться в другом репозитории и тогда для запуска тестов триггер подойдет хорошо. Но в данном случае, от результата тестирования скорее всего зависит решение о мерже в основную ветку. Поэтому для такого тестирования стоит настроить cross-project триггер с ожиданием завершения дочернего пайплайна.

Вывод

Возможность использования триггеров сильно добавляет гибкости в настройке пайплайнов для проектов. И при этом инструкции для всех этапов могут хранится в разных репозиториях и поддерживаться разными командами.

При использовании триггеров для автоматизированного тестирования необходимо отталкиваться от требований к каждому виду тестирования. Если процесс должен зависеть от какого-то из видов тестирования то безусловно нужно выбирать тот триггер который будет ожидать окончания тестирования, в противном случае использовать обычный триггер без ожидания.

--

--

Саша Воробей

Tech Lead QA Automation at Ozon | Former Teacher at Tinkoff FinTech School | Speaker at Heisenbug