GitLab CI потерял script после extends: как объединяется конфигурация

В общем CI-шаблоне есть две команды сборки. В проекте добавили третью через extends, а в журнале осталась только новая. YAML синтаксически корректен: ошибка возникла в ожидании, что список script автоматически дополнится. GitLab объединяет словари по ключам, но массив команд в дочерней job заменяет массив родителя.

Чтобы исправить конфигурацию, полезно читать её в два этапа. Include приносит определения из файлов. Extends строит job из шаблонов и её собственных полей. В результате Runner получает одно итоговое описание; порядок файлов в репозитории не превращается в последовательность выполнения команд.

Минимальное наследование

В тестовом репозитории создайте ci/base.yml и основной .gitlab-ci.yml. Первый файл содержит скрытую job .build_base: точка в начале имени исключает её самостоятельный запуск.

# ci/base.yml
.build_base:
  image: alpine:3.21
  variables:
    BUILD_MODE: release
    OUTPUT_DIR: dist
  script:
    - mkdir -p "$OUTPUT_DIR"
    - printf '%s\n' "$BUILD_MODE" > "$OUTPUT_DIR/mode.txt"
# .gitlab-ci.yml
include:
  - local: ci/base.yml

build:
  extends: .build_base
  variables:
    BUILD_MODE: debug
  script:
    - printf 'mode=%s output=%s\n' "$BUILD_MODE" "$OUTPUT_DIR"

Ожидаемый вывод — mode=debug output=dist. Переменная BUILD_MODE переопределена, OUTPUT_DIR сохранена из родителя. Но каталог dist не создаётся: собственный script полностью заменил список родителя. Попытка добавить здесь cat dist/mode.txt обнаружит отсутствие файла, а не проблему передачи artifacts.

Сохраним сборку явным действием

Если нужно переиспользовать общий список, его можно явно включить через !reference. В основном файле замените job build следующим определением:

build:
  extends: .build_base
  variables:
    BUILD_MODE: debug
  script:
    - !reference [.build_base, script]
    - cat "$OUTPUT_DIR/mode.txt"

Теперь сначала выполнятся команды базовой сборки, затем чтение файла. Его содержимое должно быть debug, потому что переменные вычисляются для итоговой job. Для достаточно сложной последовательности удобнее вынести команды в версионируемый shell-скрипт репозитория и вызывать его из нескольких jobs: так порядок проще запускать локально и читать в Git diff.

Массивы есть не только у script

Такой же вопрос возникает с rules, tags и before_script. Если переопределить массив, ожидать сохранения элементов родителя нельзя. Особенно опасно незаметно заменить rules релиза: job может начать появляться в источниках, для которых общий шаблон её исключал. Сначала посмотрите конечный набор условий, затем проверяйте, почему конкретный pipeline её добавил.

Когда extends ссылается на несколько родителей, конфликтующие ключи разрешаются с учётом порядка родителей, а собственные поля job имеют приоритет. Несколько уровней наследования делают этот порядок трудным для чтения. Если цепочка требует постоянно открывать четыре файла, сократите её или оставьте явную композицию команд.

YAML anchors и !reference решают разные задачи. Обычные anchors ограничены файлом YAML, а !reference позволяет ссылаться на секции из включённых файлов. При этом такую конструкцию должен понимать GitLab: обычный YAML-парсер без поддержки custom tags не проверяет её семантику.

Проверим конечный результат

Откройте Pipeline editor и посмотрите объединённую конфигурацию, затем запустите CI Lint в контексте проекта. Найдите итоговые image, variables, rules и script именно для build. Если include указывает на другой проект, зафиксируйте ref шаблона: изменение общего файла без изменения прикладного репозитория тоже может поменять поведение следующего pipeline.

В диагностическом запуске сравните итоговую конфигурацию с журналом: появились ли создание каталога, запись mode.txt и чтение файла в нужном порядке. Это отделяет ошибку объединения от ошибки самой команды. Удаление extends ради исправления одного массива дублирует остальные настройки; явное включение нужной последовательности сохраняет общий шаблон и делает порядок видимым.

Ещё по теме

Продолжить изучение

Хотите собрать проверяемый путь от коммита до релиза? Jobs, runners, артефакты и деплой — темы программы «GitLab CI/CD: автоматизация сборки и деплоя».

Продолжить на практике

  • GitLab CI/CD: автоматизация сборки и деплоя ↗

    От первого .gitlab-ci.yml до pipeline, который тестирует код, собирает образ и выкладывает приложение. Runners, artifacts, cache, registry, окружения и безопасный откат — на одном практическом проекте.