Перейти к содержимому

Условия и проверки

when:, check: и files_gate: — три директивы, которые гейтят шаги и фазы пайплайна. Они используют типизированную форму условия/действия — полный каталог предикатов и действий см. в Условия и действия; эта страница описывает семантику интеграции с пайплайном деплоя.

when:предусловие, вычисляемое до запуска фазы или шага. Ложный результат пропускает фазу/шаг без выполнения. Это типизированное условие в трёх формах:

Билтин-предикаты — проверяют состояние файловой системы, используя реестр предикатов:

when:
type: builtin
cmd: "dir-empty services/main/src"

Доступные предикаты: dir-exists, dir-missing, dir-empty, dir-not-empty, file-exists, file-missing, generated-missing (принимает <svc> <field>, а не путь). Они отличаются от билтинов движка (service_configs_render и т. д.), используемых в телах шагов и действиях check:; полное различие см. в conditions.md. Реестр предикатов использует жёстко заданный sh -c для POSIX-переносимости независимо от настроенного в проекте shell.

Shell-команды — выполняют shell-команду; код выхода 0 = true, ненулевой = false:

when:
type: shell
cmd: "test -f services/main/src/vendor/autoload.php"

Shell-команды также используют жёстко заданный sh -c (а не ShellBin) для переносимости.

Template-выражения — синтаксис Go template, вычисляемый на этапе плана на объединённом DweConfig:

when:
type: template
expr: "{{ .Services.second.Enabled }}"

Template-условия не поддерживают check: в том же шаге (нет побочных эффектов на этапе плана). Они предназначены только для проверок идемпотентности вида «пропустить эту фазу, если фича не включена», когда результат известен до выполнения. Полную поверхность шаблонов (helpers, sprout registries, appURL) см. в Шаблоны.

check:пост-действие, вычисляемое после успеха шага. Это типизированное действие — та же форма type: / cmd: / with:, что и у тел шагов, но его успех/падение определяет, рапортуется ли шаг как успешный или упавший.

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

Пример: проверить, что конфиги развёрнуты

- name: render-configs
type: builtin
cmd: service_configs_render
with:
service: main
check:
type: builtin
cmd: service_configs_render_check
with:
service: main

Пример: проверить, что shell-команда производит ожидаемый вывод

- name: run-migration
type: command
cmd: services.main.migrate
check:
type: shell
cmd: "test -f services/main/src/migrations/.done"

Поведение continue_on_error совместно с check::

  • Когда тело шага падает и установлено continue_on_error: true, check: не вычисляется. Шаг рапортуется как упавший, а пайплайн продолжается.
  • Когда тело шага успешно, но check: падает, шаг рапортуется как упавший. Если continue_on_error: true, пайплайн продолжается; иначе прерывается.

check: auto — единственная скалярная форма, которую принимает check:. Она разворачивается в логическую инверсию собственного when: шага — «шаг сделан, когда условие, потребовавшее его запуска, перестало выполняться»:

- name: clone-source
type: shell
cmd: "git clone ${vars.source.repo} services/backend/src"
when:
type: shell
cmd: "[ ! -e services/backend/src/.git ]"
check: auto

что в точности эквивалентно записанному вручную отрицанию:

check:
type: builtin
cmd: shell
with:
cmd: "test -e services/backend/src/.git"

Только по явному согласию, никогда не выводится сам. when: («надо ли запускать сейчас») и check: («не сделано ли уже») часто совпадают, но это не один и тот же вопрос, поэтому DWE никогда не выводит одно из другого молча — шаг с when: и намеренно без check: продолжает вести себя ровно как раньше.

Только when: {type: shell}. Две другие формы условия отвергаются на этапе загрузки, каждая по своей причине:

ФормаРезультат на загрузке
check: auto без when:отвергается — инвертировать нечего
check: auto с when: {type: builtin}отвергается — регистр предикатов и регистр builtin’ов для check: не пересекаются; нет действия, выражающего «НЕ dir-empty foo»
check: auto с when: {type: template}отвергается — template-условия вычисляются на этапе плана и шаг удаляется при false, значит любой дошедший до исполнения шаг имел when == true, и его инверсия падала бы всегда

Принимается только точный скаляр auto; Auto, AUTO и "auto " дают обычную ошибку «action must be a mapping».

Как разрешается. Инверсия строится на этапе разрешения плана из отрендеренной команды when: — той самой строки, которую увидит вычисление во время выполнения, поэтому пара никогда не разойдётся в том, что за команда имеется в виду — и оборачивается по переводам строк (! (\n<cmd>\n)), а не встроенно: встроенный ! ( <cmd> ) превращает when: с завершающим # комментарием в синтаксическую ошибку вместо инверсии.

Выведенный check — это действие {type: builtin, cmd: shell}, то есть он выполняется под жёстко зашитым sh -c в корне проекта — тот же shell и тот же рабочий каталог, что и у when: — и он не ограничен по времени (timeout: "0"), как и when:, который он инвертирует, а не как 10-секундный дефолт builtin’а shell.

Вывод плана показывает то, что вы написали, а не машинерию: dwe deploy plan печатает [check: auto (inverse of when)].

Поведение журнала идентично явному check. Сентинел существует начиная с загрузки, поэтому check: auto заставляет шаг перезапускаться на каждом деплое ровно так же, как любой другой check:. Одно замечание про миграцию: сырое значение check: участвует в хеше конфигурации проекта/сервиса, поэтому перевод шага с написанной вручную инверсии на check: auto сдвигает этот хеш и вызывает однократный перезапуск шагов сервиса.

files_gate: пробирует существование или отсутствие файлов перед запуском шага. В отличие от when: (общего предиката) или check: (валидирующего после успеха), files_gate: решает, запускать ли, на основе того же блока files:, объявленного в определении команды, делая файловую спецификацию команды единственным источником истины.

Кейс: пропустить шаг деплоя, если артефакт уже существует, или запустить его только при наличии предзагруженного кеша. Пример: «снять дамп БД только если файла дампа ещё нет» (продьюсер с state: missing) или «загрузить кеш только если он предзагружен» (консьюмер с state: readable).

Короткая форма:

- name: db-dump
type: command
cmd: services.main.db.dump
files_gate: readable # runs iff dump file exists

Длинная форма:

- name: db-load
type: command
cmd: services.main.db.load
files_gate:
state: missing # required: runs iff dump file does NOT exist
command: services.main.db.dump # optional: target command (default: step.cmd)
require: all # optional: which files to probe (default: required)
with: # optional: params for file resolution (default: step.with)
database: test_db

Справочник полей:

ПолеТипПо умолчаниюОписание
statereadable | missing(обязательно)readable: запускается тогда и только тогда, когда все выбранные файлы разрешаются (файл существует). missing: запускается, когда ни один не разрешается.
commandstringstep.cmdID целевой команды, чей блок files: пробится. Если не указан, используется собственный cmd шага (самопроба).
requirestring | listrequiredКакие файлы участвуют в пробе: required (файлы с required: true или read_write), all (все читаемые файлы) или явный список [id1, id2].
withmappingstep.withПереопределения параметров для шаблонов разрешения файлов. Сливаются с step.with для целевой команды.

Семантика:

  • Нет ошибок файлов → пропуск, не падение. Если state: readable и ни один файл не совпал, шаг пропускается (не падает). Конфигурационные ошибки (плохой шаблон, плохой glob, отсутствующие параметры) приводят к ошибке и падению шага.

  • И-объединён с when: — оба должны быть выполнены, чтобы шаг запустился. Если when: ложен, гейт никогда не вычисляется (короткое замыкание). Если when: истинен, но гейт не удовлетворён, шаг пропускается.

  • Взаимодействие с пропуском по журналу (асимметричное по state:) — взаимодействие гейта с оптимизацией пропуска «уже задеплоено» зависит от state::

    • state: missing (паттерн продьюсера) обходит пропуск по журналу. Гейт сам решает, запускать ли шаг, на каждом деплое. Шаг-продьюсер с state: missing перезапускается после удаления его артефакта между деплоями, потому что источником истины является состояние файловой системы — а не журнал.
    • state: readable (паттерн консьюмера) уважает пропуск по журналу. Журнал учитывается первым; если он зафиксировал успешный запуск, шаг пропускается без проверки гейта. Гейт фактически срабатывает только на первом запуске, после чего нагрузку несёт журнал. Это сохраняет идемпотентность деструктивных консьюмеров (например, drop + restore) по умолчанию. Чтобы принудительно переоценивать на каждом запуске, добавьте явную директиву check: — тот же рычаг, что и у любого другого шага.
    • Шаги без гейта пропускаются по журналу как раньше.

    Добавление или изменение директивы files_gate: инвалидирует записанный хеш шага, поэтому следующий запуск переоценит с нуля независимо от state:.

  • Область пробы — участвуют только файлы с access: read или access: read_write. Файлы с access: write отклоняются на этапе валидации плана, если перечислены в спецификации require: гейта.

Пример «до и после»:

Без files_gate: — дублированная логика glob+regex:

# Deploy step: hard-coded shell condition duplicating the command's file logic
- name: dump-download
type: command
cmd: services.main.db.dump-download
when:
type: shell
cmd: "test -f services/main/.backups/dump_*.sql.gz" # duplicated glob logic

С files_gate: — единый источник истины:

# Deploy step: references the command's canonical file spec
- name: dump-download
type: command
cmd: services.main.db.dump-download
files_gate: readable # probes the dump_*.sql.gz from command definition

Определение команды один раз:

workspace/commands/services/main/db.yml
commands:
dump-download:
type: shell
files:
dump:
access: read
candidates:
- glob: "services/main/.backups/dump_*.sql.gz"
sort: modtime_desc
required: true