Как сделать так, чтобы Gitlab CI Pipeline всегда запускал одни задания, а другие - только по мерж-реквестам?
TL/DR:
Моя цель состоит в том, чтобы иметь конвейер Gitlab (CE-12.4.2), который всегда выполняет некоторые задания только в запросах на слияние, а другие задания всегда (в запросах слияния и при всех обычных пушах). Как должен.gitlab-ci.yml
смотреть, чтобы сделать это?
Мой вариант использования: у меня есть большой конвейер, на котором выполняется множество заданий (тесты, проверка, dep, build, doc, ...). Теперь я добавил промежуточную среду (с использованием кубернетов), и конвейер построил новый образ и развернул его в промежуточной среде. Это позволяет мне мгновенно открыть измененное (веб-) приложение и посмотреть, как изменения ведут себя и выглядят, без необходимости проверять их локально. Теперь создание образа и его развертывание в промежуточной среде потребовало бы слишком больших ресурсов для выполнения каждого толчка, поэтому мне нужны развертывания в промежуточной среде только тогда, когда кто-то создает для меня запрос на слияние.
Очень упрощенный пример:
install:
script: ...
test:
script: ...
build-image:
script: ...
only: [merge_requests]
deploy-staging:
script: ...
only: [merge_requests]
Для всех обычных толчков рабочие места install
а также test
должен быть выполнен.
Для мерж-реквестов вакансии install
, test
, build-image
а также deploy-staging
должен быть выполнен.
Что я пробовал: в Gitlab есть эта функция для определенияonly: [merge_requests]
в задании это приводит к тому, что задание будет выполняться только тогда, когда конвейер выполняется для запроса слияния. Похоже, именно то, что я ищу, но есть большая загвоздка. После того, как этот атрибут применяется к одному заданию в конвейере, все другие задания в этом конвейере, у которых нет этого атрибута, будут удалены из конвейера при выполнении внутри запросов на слияние. Сначала это показалось мне ошибкой, но на самом деле это задокументированное поведение:
In the above example, the pipeline contains only a test job. Since the build and deploy jobs don’t have the only: [merge_requests] parameter, they will not run in the merge request.
Чтобы повторно ввести все остальные задания в конвейер для мерж-реквестов, я должен применить only: [merge_requests]
ко всем другим работам. Проблема с этим подходом в том, что теперь эти обычные задания больше не выполняются для обычных git-push. И у меня нет возможности повторно ввести эти регулярные задания в конвейеры для обычных push, потому что Gitlab не поддерживаетonly: [always]
или что-нибудь в этом роде.
Я также заметил, что only
синтаксис является кандидатом на устаревание, и следует предпочесть rules
синтаксис вместо этого, поэтому я взглянул на это. У такого подхода есть несколько проблем:
- Единственный способ обнаружить с помощью
rules
выполняется ли конвейер для мерж-реквеста или нет, заключается в оценке переменных, связанных с мерж-запросами, например$CI_MERGE_REQUEST_ID
. К сожалению, эти переменные существуют только тогда, когдаonly: [merge_requests]
используется, что вновь вызовет указанные выше проблемы. - Правила разрешают только условное применение других атрибутов, поэтому мне все равно придется использовать
only
,except
илиwhen
атрибуты для фактического удаления или добавления заданий из конвейера или в него. К сожалению, Gitlab не поддерживает ничего подобногоonly: [never]
илиwhen: never
, поэтому у меня нет возможности удалить или добавить вакансии.
Я также пытался, чтобы работа зависела от другого, использующего need
или dependencies
атрибуты, похоже, это не повлияло на то, включено ли задание в конвейер или нет.
Последнее, что я отчаянно пробовал, - это всегда включать все вакансии и просто отмечать их как when: manual
запускаться вручную нажатием кнопки. Это в некоторой степени работает, но очень утомительно, потому что развертывание в промежуточную стадию - это процесс, состоящий из нескольких заданий, и каждое задание занимает некоторое время. Итак, я бы увидел мерж-реквест, нажал кнопку для первого задания, подождал 5 минут, нажал следующую кнопку, снова подождал 5 минут, и только после этого смог бы использовать постановку. Для многих небольших запросов на слияние это заняло бы у меня много времени и не было бы эффективным решением. Я также не могу просто пометить первое из этих заданий как ручное, потому что Gitlab тогда просто пропустит это задание и выполнит последующие не по порядку (И сноваneeds
а также dependencies
похоже, не влияют на это при работе с заданиями, запускаемыми вручную).
Что меня немного сбивает с толку, так это то, что после поиска в сети я не нашел никого с такой же проблемой. Либо я единственный пользователь Gitlab, который хочет выполнять некоторые задания только для запросов на слияние без исключения всех других заданий (что кажется маловероятным), либо мне не хватает чего-то очевидного (что кажется более вероятным). Я что-то упустил или Gitlab действительно не поддерживает этот вариант использования?
4 ответа
Из предыдущего ответа :
Но есть проблема. В этом примере после создания MR запускаются два конвейера для каждой отправки. Один для
only: [branch]
, один дляonly: [merge_requests]
Проверьте, может ли помочь последний GitLab 13.8 (январь 2021 г.):
Используйте как ответвления, так и конвейеры MR без дублирования
Ранее было невозможно сначала запускать конвейеры для веток, а затем переключаться на конвейеры мерж-реквестов при создании MR.
Следовательно, в некоторых конфигурациях отправка в ветку могла привести к дублированию конвейеров, если в ветке уже был открыт мерж-реквест: один конвейер в ветке, а другой — для мерж-реквеста.
Теперь вы можете использовать новый
$CI_OPEN_MERGE_REQUESTS
предопределенную переменную среды в конфигурациях CI, чтобы переключаться с ответвленных конвейеров на конвейеры MR в нужное время и предотвращать избыточные конвейеры.См. Документацию и выпуск .
user2993689 указывает в комментариях к документации на аналогичный пример:
Избегайте дублирования конвейера
В трубопроводы MR можно добавлять задания. У меня есть пример отсюда: https://docs.gitlab.com/ee/ci/merge_request_pipelines/index.html
Общая идея: вы определяете only: [branch, merge_requests]
для каждого задания, а для задания развертывания перепишите его с only: [merge_requests]
.
.only-default: &only-default
only:
- branches
- merge_requests
build:
stage: build
tags:
- build
<<: *only-default
script:
- echo build
deploy mr:
stage: deploy
tags:
- build
only:
- merge_requests
script:
- echo "deploy on MR"
Но существует проблема. В этом примере запускаются два конвейера для каждого нажатия после создания MR. Один дляonly: [branch]
, один для only: [merge_requests]
. Вот какonly: [merge_requests]
работа, он запускает работу при каждой смене MR. Новый коммит - это определенно изменение.
Кажется, не существует решения, которое могло бы запускать конвейер ТОЛЬКО для определенного события - например, создания MR.
Но я думаю, что возможен обходной путь:
- Развернуть существующие промежуточные задания для каждого конвейера
- Скрипт задания проверяет, создан ли MR для текущей ветви
- Если MR создается, скрипт устанавливает метку для этого MR, например 'staging deployed'
- Если этот ярлык уже существует или MR не создан, ничего не делайте.
В этом могут помочь GitLab API, curl и jq. Если будет свободное время, обязательно постараюсь написать:).
Следующее сработало для меня. Идея состоит в том, чтобы определить значение по умолчанию для всех заданий CI с помощью ключевого слова. Затем для задания CI, которое вы хотите запускать только на MR, определите отдельный запуск (оно перезаписываетworkflow
правила этой работы).
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "push"
install:
script: ...
test:
script: ...
build-image:
script: ...
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
deploy-staging:
script: ...
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
У меня такая же проблема.
Как описано в GitLab Docs , вам необходимо настроить весь конвейер для работы в конвейерах мерж-реквестов.
Этого можно добиться, добавив следующее поверх файла .gitlab-ci.yml.
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
Надеюсь, я смог помочь!