Условия и проверки
when:, check: и files_gate: — три директивы, которые гейтят шаги и фазы пайплайна. Они используют типизированную форму условия/действия — полный каталог предикатов и действий см. в Условия и действия; эта страница описывает семантику интеграции с пайплайном деплоя.
Содержание
Заголовок раздела «Содержание»when:(предусловие)check:(постусловие)check: auto(инверсияwhen:)files_gate:(предусловие по файлам)
when: (предусловие)
Заголовок раздела «when: (предусловие)»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: (постусловие)
Заголовок раздела «check: (постусловие)»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 (инверсия when:)
Заголовок раздела «check: auto (инверсия when:)»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: (предусловие по файлам)
Заголовок раздела «files_gate: (предусловие по файлам)»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Справочник полей:
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
state | readable | missing | (обязательно) | readable: запускается тогда и только тогда, когда все выбранные файлы разрешаются (файл существует). missing: запускается, когда ни один не разрешается. |
command | string | step.cmd | ID целевой команды, чей блок files: пробится. Если не указан, используется собственный cmd шага (самопроба). |
require | string | list | required | Какие файлы участвуют в пробе: required (файлы с required: true или read_write), all (все читаемые файлы) или явный список [id1, id2]. |
with | mapping | step.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Определение команды один раз:
commands: dump-download: type: shell files: dump: access: read candidates: - glob: "services/main/.backups/dump_*.sql.gz" sort: modtime_desc required: true