commands/
Декларативные определения команд для DWE-проекта.
Содержание
Заголовок раздела «Содержание»- Назначение
- Структура файлов и идентификаторы команд
- Структура файла
- Жизненный цикл выполнения
- Видимость, регистрация и обнаружение
- Сквозные примеры
- Связанные команды
- Дополнительное чтение
Назначение
Заголовок раздела «Назначение»workspace/commands/ — дом для каждого переиспользуемого, скриптуемого действия, которое проект предоставляет через CLI: shell-доступ к контейнерам, шаги сборки, операции с базой данных, многошаговые сценарии, хуки деплоя, пользовательские скрипты и т. д.
Каждый YAML-файл объявляет одну или несколько именованных команд. Команды обнаруживаются автоматически обходом дерева каталогов, адресуются через точечный идентификатор и могут выполняться напрямую (dwe commands <id>) либо ссылаться из сценариев и пайплайнов (deploy.yml, lifecycle.yml).
Эта страница — точка входа в справочник по конфигурации. Директивы, типы, шаблонизация и валидация описаны на отдельных соседних страницах — см. Дополнительное чтение в конце.
Структура файлов и идентификаторы команд
Заголовок раздела «Структура файлов и идентификаторы команд»Структура каталогов определяет префикс группы, а имя файла без расширения определяет конечный сегмент. Имена файлов и подкаталогов полностью на усмотрение проекта — приведённые ниже названия иллюстративны, и допускается произвольное количество файлов любой вложенности.
workspace/commands/├── <top-group>.yml → group: <top-group>├── … → any number of top-level groups└── <parent-group>/ → optional subdirectory expands a group ├── <child>.yml → group: <parent-group>.<child> ├── <child>/ → optional deeper subdirectory │ └── <leaf>.yml → group: <parent-group>.<child>.<leaf> └── … → any number of children, any depthКонкретный проект может организовать всё, например, так — каждое имя здесь выбрано проектом, это не соглашение, навязываемое CLI:
workspace/commands/├── db.yml → group: db├── app.yml → group: app└── services/ ├── <service-a>.yml → group: services.<service-a> ├── <service-a>/ │ └── db.yml → group: services.<service-a>.db └── <service-b>.yml → group: services.<service-b>Полный идентификатор каждой команды — <group>.<name>, где <name> — ключ в карте commands: внутри файла.
Шаблон: размещайте основные команды группы в одном файле, названном по группе (services/<service>.yml), и разделяйте большие группы в соседний подкаталог только тогда, когда команд достаточно, чтобы оправдать логические подгруппы (services/<service>/db.yml, services/<service>/cache.yml). Подкаталог опционален — маленькие группы остаются в одном файле. Обязательных файлов нет: у проекта может быть ноль, одна или десятки групп на любой глубине.
# workspace/commands/db.yml → group "db"commands: cli: # full ID: db.cli type: service_exec ... dump-create: # full ID: db.dump-create type: script ...Зарезервированных имён файлов нет — каждый файл *.yml вносит сегмент, выводимый из его пути.
Структура файла
Заголовок раздела «Структура файла»У каждого файла два ключа верхнего уровня: опциональный блок метаданных group: и обязательная карта commands:.
group: title: Database description: Database container management commands
commands: <local-name>: type: <type> description: <text> # ... directives below ...| Поле | Тип | Описание |
|---|---|---|
group.title | string | Отображаемый заголовок, показываемый в dwe commands list |
group.description | string | Короткое описание, отображаемое рядом с группой |
group.hide | string | Опциональное выражение-условие; когда truthy, скрывает группу и каскадно — все её потомки (команды и подгруппы). См. Условие hide. |
commands | map | Именованные определения команд (ключ = локальное имя) |
Жизненный цикл выполнения
Заголовок раздела «Жизненный цикл выполнения»Каждая команда, независимо от типа, проходит один и тот же пайплайн выполнения:
flowchart TD
A[Разрешение параметров] --> B[Разрешение контекста]
B --> C[Вычисление путей файлов]
C --> D{Подтверждение?}
D -- да --> E[Запрос пользователя]
D -- нет --> F[Подготовка файловых эффектов]
E --> F
F --> G[Запуск раннера]
G --> H{Успех?}
H -- да --> I[Сообщение об успехе]
H -- нет --> J[Выполнение cleanup в порядке LIFO]
J --> K[Сообщение об ошибке]
Фазы:
- Разрешение параметров — для каждого объявленного параметра пробуются по очереди: переданное значение →
default_from(точечный путь в объединённый конфиг; пустой результат считается отсутствием) → литеральныйdefault→ ошибка обязательности. Затем значение приводится к объявленному типу и проверяется наpattern. - Разрешение контекста — каждый точечный путь
context.<key>.fromчитается из объединённого конфига. - Вычисление путей файлов — рендерятся шаблоны
path/candidates, пути нормализуются в абсолютные, выполняется поиск файлов. Без побочных эффектов. - Подтверждение — при
confirmation: trueзапрашивается подтверждение пользователя; запрос обходится только черезSkipConfirm(устанавливается флагом--yes/-yи наследуется дочерними шагами сценария). Иначе диспетчеризация по stdin: TTY →huh.Confirm, не-TTY → простой fallback Y/n, который автоматически отвечает «yes», когда переменная окруженияCIустановлена (в любое непустое значение). Отказ прерывает команду. Полное дерево решений см. в Поток подтверждения. - Подготовка файловых эффектов —
mkdir, проверкиoverwrite, регистрация cleanup-колбэков. - Запуск — диспетчеризация в раннер, специфичный для типа (host shell, DWE CLI, контейнерные exec/run, скрипт или сценарий).
- Успех / ошибка — выводится
messages.successилиmessages.error. При ошибке зарегистрированные cleanup-колбэки срабатывают в порядке LIFO до сообщения об ошибке.
Видимость, регистрация и обнаружение
Заголовок раздела «Видимость, регистрация и обнаружение»- Файлы под
workspace/commands/рекурсивно обнаруживаются на старте. - Каждый файл парсится и валидируется; сбой загрузки останавливает запуск со структурированной ошибкой, указывающей на файл и поле.
private: trueскрывает команды изdwe commands listи отвергает прямой вызов черезdwe commands. На приватные команды по-прежнему можно ссылаться из сценариев и пайплайнов — полезно для шагов, которые должны запускаться только как часть более крупной последовательности.
db.up: type: dwe private: true # used only inside db.start workflow cmd: "docker up db"Сквозные примеры
Заголовок раздела «Сквозные примеры»Самодостаточная команда service_exec
Заголовок раздела «Самодостаточная команда service_exec»db.create: type: service_exec description: Create a database in the db container service: db mode: exec-or-run params: database: type: string required: true pattern: ^[a-zA-Z0-9_-]+$ env: MYSQL_PWD: "${vars.db.password}" messages: success: "Database `${param.database}` is ready." error: "Failed to create database `${param.database}`." cmd: "mariadb -u${vars.db.user} -e 'CREATE DATABASE IF NOT EXISTS `${param.database}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'"Команда script с файловыми артефактами
Заголовок раздела «Команда script с файловыми артефактами»db.dump-create: type: script description: Create a database dump file params: database: type: string default_from: vars.db.database pattern: ^[a-zA-Z0-9_-]+$ dump_dir: type: string default_from: vars.db.backup_dir required: true pattern: ^[^*?\[\]]+$ dump_date: type: bool default: true env: DB_NAME: "${param.database}" DB_USER: "${vars.db.user}" MYSQL_PWD: "${vars.db.password}" files: dump: access: write path: "${param.dump_dir}/${param.database}{{ if .Params.dump_date }}_{{ now | date \"2006-01-02\" }}{{ end }}.sql.gz" mkdir: true overwrite: true on_error: remove env: DUMP_FILE script: path: workspace/scripts/db/dump-create.sh shell: bash messages: success: "Database dump created at ${files.dump.path}" error: "Failed to create database dump"Файловая спецификация чтения с fallback-ом
Заголовок раздела «Файловая спецификация чтения с fallback-ом»db.dump-deploy: type: script confirmation: true confirmation_text: "This will DROP and recreate `${param.target_database}`. Continue?" params: target_database: default_from: vars.db.database required: true dump_dir: default_from: vars.db.backup_dir required: true files: dump: access: read candidates: - glob: "${param.dump_dir}/${param.target_database}_*.sql.gz" match: '\d{4}-\d{2}-\d{2}' sort: name_desc - path: "${param.dump_dir}/${param.target_database}.sql.gz" required: true env: DUMP_FILE script: path: workspace/scripts/db/dump-deploy.sh shell: bashСценарий с условными шагами и шагом подтверждения
Заголовок раздела «Сценарий с условными шагами и шагом подтверждения»reset-and-bootstrap: type: workflow description: Drop, recreate, and bootstrap the main service steps: - confirm: "Drop and re-bootstrap `${vars.db.database}`?"
- command: db.drop with: database: "${vars.db.database}"
- command: services.main.db.create
- command: services.main.composer-install when: "file-missing services/main/src/vendor/autoload.php"
- command: services.main.migrate
- command: optional-cache-warm continue_on_error: trueПриватная композиция
Заголовок раздела «Приватная композиция»db.up: type: dwe private: true description: Start the database container in the background cmd: "docker up db"
db.wait: type: builtin private: true description: Wait for the db container to become healthy cmd: docker_wait_healthy with: services: [db] timeout: 120s interval: 2s
db.start: type: workflow private: true description: Start the database container and wait until healthy steps: - command: db.up - command: db.waitdb.start нельзя вызвать напрямую через dwe commands db.start, но bootstrap может ссылаться на неё из своих steps:. Композиция выше — каноничный шаблон: тонкий type: dwe для запуска, type: builtin для ожидания и type: workflow, связывающий их вместе.
Кастомные имена сетей + частичный
up/run. Если ваш compose-файл задаёт сети явноеnetworks.<x>.name:, учитывайте квирк docker-compose: labels сети выигрывает та команда, которая первой её материализует. Частичныйdocker up dbили шагtype: service_run(запускающийdocker compose run --rm --no-deps …), выполненный до полного подъёма стека, может создать именованную сеть с labels, которые последующийup --waitзатем отвергнет (network <x> … has incorrect label com.docker.compose.network). Это поведение самого compose, а не баг DWE — DWE не объявляет собственных сетей и передаёт один и тот же project/-fво все вызовы. Решение — порядок: поднимите весь стек (docker up --wait, встроенная финальная фаза деплоя) до любого частичногоup <svc>илиrun --rm, который трогает кастомно-именованную сеть, либо уберите явноеname:и дайте compose заскоупить сеть на проект.
Связанные команды
Заголовок раздела «Связанные команды»dwe commands list— перечислить все публичные команды, сгруппированные по файламdwe commands <id> [--set k=v] [--yes] [-- <args>]— выполнить команду (псевдоним:dwe cmd <id>). Всё, что после--, предлагается команде как${args}— включается для каждой команды отдельно, см. директивы § Сквозные аргументыdwe commands --inspect <id>(или-i) — показать разрешённое определение (params, context, env, runner)dwe docs generate— перегенерировать справочник по командам вdocs/reference/commands/
Когда dwe commands вызывается без точного идентификатора команды на интерактивном терминале, открывается интерактивный двухпанельный браузер команд. Его поведение (глубина раскрытия по умолчанию, автосворачивание во время нечёткой фильтрации, бейджи типов) настраивается через блок ui: в workspace.yml.
--inspect / -i взаимоисключающие с --set и --yes; требует точного идентификатора команды и печатает определение, не запуская её.
Дополнительное чтение
Заголовок раздела «Дополнительное чтение»- directives.md — общие поля: идентичность, подтверждение, сообщения, уведомления, params, context, env, files
- types.md — восемь типов команд и их специфичные поля, плюс разрешение workdir
- templating.md — контекст рендера, резолверы уровня команды, справочник по template-пространству
- validation.md — шпаргалка по правилам валидации и типичные подводные камни