Gitlab триггеры и для каких тестов их стоит использовать?
Пришлось столкнуться с использованием триггеров в Gitlab для запуска разных тестов и хочется в данной статье рассказать какие есть виды триггеров в Gitlab, в чем их разница и для каких тестов какой вид триггера может лучше всего подойти.
План будет следующим:
- Расскажу что такое триггер, какие виды триггеров есть в гитлаб и в чем их разница.
- Дальше на примере тестов поделюсь мнением какие тесты каким триггером лучше всего запускать.
Кто и так знает что такое триггер, предлагаю перейти на обзор видов триггеров в Gitlab или их применение в тестировании.
О триггерах
Триггер — по-хорошему это вид задачи, которая в определенный момент времени запускает выполнение другой задачи. Триггером например может быть:
- Задача которая отправляет запрос в Jenkins через его API для необходимости запустить пайплайн диплоя приложения при релизе какого-то компононета.
- Задача в пайплайне Gitlab`а при старте которой запускается пайплайн из другого репозитория.
При этом обычно используя триггеры, пользователю не всегда бывает важным дождаться выполнения стриггериной задачи. Достаточно просто запустить задачу. Например: после прохождения всего пайплайна, триггер запускает задачу, которая собирает статистику по пройденному пайплайну.
В связи с этим есть триггеры которые просто вызывают другое событие и успешно завершаются, а есть триггеры, которые будут ждать пока стриггереная задача (пайплайн)завершиться и только тогда завершаются сами.
Раз речь идет про Gitlab то оставлю тут ссылку на документацию по триггерам из Gitlab.
Виды триггеров в гитлаб.
Существует два основных вида триггеров.
- Multi-project pipelines (Cross-project triggers) — https://docs.gitlab.com/ee/ci/multi_project_pipelines.html
- Triggers through the API — https://docs.gitlab.com/ee/ci/triggers/README.html#adding-a-new-trigger
По факту и один и другой вид триггеров предназначен для одной и той же цели — запустить пайплайн из другого репозитория. Но у каждого из них есть явные отличия. Рассмотрим по-порядку каждый из них.
Multi-project pipelines (Cross-project triggers)
Первое что хочется отметить, что не смотря на то что в документации (на начало 2020 года) написано что этот триггер доступен для Premium и Silver плана, он на самом деле доступен для всех планов Gitlab!
- Для того чтобы создать триггер, необходимо добавить в файл .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 урезан, и он так же урезан с применением rulesonly
andexcept
— работает как и для обычной джобыwhen
(only withon_success
,on_failure
, andalways
values) — вот тут интересно, то есть возможность вручную запустить джобу у данного триггера нет. Обидно =(extends
— работает как и для обычной джобы, но если у базовой джобы используется параметр не входящий в данный список — джоба упадет.
То есть как вы обратили внимание, в списке нет scripts, variables
Добавлю еще от себя что еще работает, но не описано в доке:
variables
— можно в стандартном формате указать переменные окружения, при это тут важно то, что все переменные окружения указанные в родительском пайплайне будут наследованы дочерним. Поэтому будьте внимательны.needs
— то есть вы можете запустить триггер после определенной джобы.
4. Перезапуск триггера не поменяет статус в MergeRequest.
В тестировании часто возникают flaky тесты из-за которых иногда приходится перезапустить джобу. Но вот такой workaround не прокатит с триггером, перезапустив упавший стриггеренный пайлайн — на результат триггера это никак не повлияет.
А сама джоба триггера вообще является не кликабельной, поэтому и его самого перезапустить нельзя
5. Нет возможности запустить триггер по токену.
Здесь нужно кое что объяснить, дело в том что у всех триггеров есть ограничения на запуск дочернего пайплайна из защищенной ветки другого репозитория.
Такое ограничение сделано для безопасности. Так как банально, злоумышленник может стриггерить из своего репозитория — пайплайн вашего проекта с другими переменными окружениями и если это был пайплайн, который разворачивает приложение на прод — то жди беды.
Но это ограничение можно обойти в трех случаях:
- Если пользователь запустивший джобу является мейнтейнром дочернего проекта.
- Если пользователю разрешен мерж в защищенную ветку.
- Если дочерний пайплайн тригеритися с использованием преднастроенного токена
Так вот данный вид триггера не работает с преднастроенным токеном. То есть отсюда вывод, что его возможно запустить на защищенной ветке, только если человек конкретному человеку выданы соотвествующие права.
Плюсы данного вида триггеров:
- Умеет дожидаться завершения дочернего пайплайна
- Прост в настройке, не требует вызова через API
- Переменные окружения наследуются от родительского пайплайна
Минусы:
- Нельзя перезапускать триггер, перезапуск дочернего пайплайна не влияет на триггер.
- Нельзя сделать ручным запуском. Иногда это действительно может быть полезным.
- Нельзя использовать токен триггера для запуска пайплайна на защищенной ветке.
Triggers through the API
Требуется чтобы в окружении в котором будет запускаться триггер была установлена утилита curl
- Для создания используется 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 триггер но без ожидания завершения.
Пример:
- Есть два репозитория: приложения и репозиторий со скриптом тестирования на безопасность или производительности.
- В репозитории приложения может запуститься пайплайн проверяющий основной функционал..
- После успешного прохождения его мержат в в основную ветку и новый функционал разворачивается на тестовом стенде.
- В пайплайне где диплится приложение дергают триггером тесты и направляют их на задиплоиное приложение.
- Пайплайн успешно завершается и сообщает всем ответственным что приложение развернулось.
- В этот момент тесты на безопасность и производительность могут тестировать приложение и в конечном итоге через пару минут выдать результат.
Плюсами в данном случае я считаю то, что:
- Это полностью автоматизированный процесс.
- Разработчики не завязаны на тест безопасности и могут спокойно продолжать работать.
Тестирование интерфейсов, API
Хм, странно, зачем нам может потребоваться запускать с помощью триггера тесты на интерфейс?
Как и в тестировании безопасности мы можем запускать Happy-Path тесты после того как в основной ветки задиплоится новое приложение. Тогда в данном случае у нас могут быть два случая:
- Во-первых эти тесты могут храниться рядом с кодом приложения и тогда достаточно в том же пайплайне настроить джобу после диплоя и там запускать эти тесты
- Во-вторых тесты могут находиться в другом репозитории и тогда для запуска тестов триггер подойдет хорошо. Но в данном случае, от результата тестирования скорее всего зависит решение о мерже в основную ветку. Поэтому для такого тестирования стоит настроить cross-project триггер с ожиданием завершения дочернего пайплайна.
Вывод
Возможность использования триггеров сильно добавляет гибкости в настройке пайплайнов для проектов. И при этом инструкции для всех этапов могут хранится в разных репозиториях и поддерживаться разными командами.
При использовании триггеров для автоматизированного тестирования необходимо отталкиваться от требований к каждому виду тестирования. Если процесс должен зависеть от какого-то из видов тестирования то безусловно нужно выбирать тот триггер который будет ожидать окончания тестирования, в противном случае использовать обычный триггер без ожидания.