rules: кто запускается, а кто ждёт кнопку
Разводим выкат по веткам, ставим ручной гейт на прод и разбираемся, почему rules вытеснили only/except.
Задача
Пока пайплайн одинаковый везде: любая ветка делает то же, что main.
В работе так не бывает. Тесты гоняют всюду, черновой выкат делают для веток,
прод трогают осознанно и не автоматом.
Материалы урока:
git pull --no-rebase upstream main
cp lesson-09-rules/pipeline.yml .gitlab-ci.yml
Условие на job
deploy-review:
stage: deploy
script:
- echo "Черновой выкат для ветки $CI_COMMIT_BRANCH"
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
deploy-prod:
stage: deploy
script:
- echo "Боевой выкат из $CI_COMMIT_BRANCH"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
allow_failure: false
rules это список условий, который проверяется сверху вниз до первого
совпадения. Совпало — job попадает в пайплайн, не совпало ни одно — job
просто отсутствует, без всякого «пропущено».
Проверьте на своём проекте. Запушьте в main, потом создайте ветку:
git checkout -b feature-x
git push -u origin feature-x
Результат: у ветки пайплайн зелёный и в нём deploy-review, у main
пайплайн в состоянии Blocked и deploy-prod ждёт нажатия.
when: manual и что такое Blocked
when: manual превращает job в кнопку. Пайплайн доходит до него,
останавливается и ждёт человека. В списке пайплайнов такой пайплайн
помечен как Blocked, а не Failed: ничего не сломалось, просто дальше
нужно решение.
Кнопка живёт на странице пайплайна, значок «Run» напротив job. Если в стадии одни только ручные job, над стадией появляется «Run all manual» и запускает их разом.
Со значением allow_failure есть тонкость, на которой путаются даже в
статьях. Умолчаний три:
true, еслиwhen: manualнаписан на верхнем уровне job;false, еслиwhen: manualстоит внутриrules, как у нас;falseво всех остальных случаях.
То есть в примере выше строка allow_failure: false ничего не меняет, она
стоит как самодокументация. А вот если бы when: manual был вынесен из
rules на уровень job, падение деплоя не покрасило бы пайплайн, и вот там
эту строку писать обязательно.
Условия, которые пригодятся
Кроме ветки, rules умеют смотреть на источник запуска, изменённые файлы и
переменные:
rules:
# только в merge request
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# только если менялся фронтенд
- changes:
- src/**/*
# ручной запуск с переменной
- if: $DEPLOY_TARGET == "staging"
changes хорошо экономит минуты в монорепозиториях: правка README не
должна запускать сборку и тесты всего проекта. Одна оговорка: это правило
имеет смысл только для пайплайнов ветки и merge request. Там, где push-события
нет (по расписанию, по тегу, вручную), changes всегда истинно, и job
запустится, даже если ничего не менялось.
Явный when: never тоже бывает нужен, чтобы вырезать частный случай перед
общим правилом:
rules:
- if: $CI_COMMIT_BRANCH == "wip"
when: never
- if: $CI_COMMIT_BRANCH
Порядок важен: сработает первое подошедшее правило, остальные не смотрятся.
only и except: наследство
В старых конфигах и туториалах встречается другой синтаксис:
deploy:
script:
- echo "деплой"
only:
- main
only/except официально помечены устаревшими: они работают ради
совместимости, но могут быть удалены в одном из следующих мажорных
выпусков. Мешать их с rules в одном job нельзя, GitLab отвергнет конфиг.
Условия по переменным и по изменённым файлам они, вопреки расхожему
мнению, умеют (only:variables, only:changes). Чего у них нет, так это
связки «условие — действие»: нельзя внутри правила сказать when: manual
или allow_failure, а именно это чаще всего и нужно.
Новый конфиг пишем на rules. Старый переписываем, когда всё равно
трогаем этот job.
Если job не появился
Самая частая причина в том, что не совпало ни одно правило, и это не
ошибка, а поведение по умолчанию. Проверьте фактическое имя ветки:
CI_DEFAULT_BRANCH у новых проектов main, у старых бывает master.
Второе по частоте: merge_request_event в правиле, а вы пушите в ветку без
открытого merge request. Пайплайн ветки и пайплайн MR это разные события.
Посмотреть, как GitLab понял конфиг, можно в Build -> Pipeline
editor -> вкладка Full configuration: она раскрывает include,
extends и якоря. Учтите, что условия там считаются для гипотетического
пуша в основную ветку, а не для той, на которой вы сейчас.
Что важно запомнить
rules проверяются сверху вниз до первого совпадения; не совпало ничего —
job не создаётся вовсе.
when: manual делает из job кнопку, пайплайн при этом получает статус
Blocked.
У ручных job allow_failure по умолчанию true на уровне job и false
внутри rules; для боевого выката нужен именно false.
changes и условия по переменным экономят минуты и не дают гонять лишнее.
only/except устарели и не смешиваются с rules в одном job.
Дальше собираем разбор антипаттернов: что в пайплайнах ломается чаще всего и как это выглядит вживую.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс