feat(job): declarative YAML job files for named relspec workflows
Add `relspec job list` and `relspec job run <name>` driven by YAML job manifests (relspec.yml / relspec.<name>.yml), so multi-file merge and conversion workflows can be expressed declaratively instead of as long shell command lines. v1 contract (see docs/JOB_FILES.md): - `command` is a closed allow-list (convert, merge, scripts-list); no field accepts a shell string or executable path. - Deterministic discovery: default file first, then named files sorted lexically; all files merged into one namespace; duplicate job names across files are a hard error. - Every path resolves relative to the job file's directory; absolute, home-relative and directory-escaping paths are rejected at validation. - Database credentials referenced by env-var name via `conn_env:`; connection strings are never stored and are redacted from logs/plan. - Full validation (version, unknown fields, command/format, per-command input/output shape, path traversal, depends_on targets, dependency cycles) runs before anything is read, written or executed; per-job pre-flight then checks input existence, script dirs, env vars and the output overwrite policy for the whole plan. - `depends_on` closure runs in deterministic topological order; `--no-deps` runs only the named job. - `--dry-run` (alias `--plan`) prints the resolved plan and exits 0 without touching inputs, outputs or databases. - A failing job propagates the underlying non-zero exit status, logs FAILED (never OK), and writes no success marker. pkg/jobs is side-effect free (discovery/parse/validate/plan only); execution adapters live in cmd/relspec/job.go. Includes unit tests for discovery, validation, planning and path safety, plus CLI tests for end-to-end convert/merge, scripts-list across multiple directories, dry-run, dependency chains, exit-code propagation and log redaction. Deferred: live `scripts execute` from jobs, split/inspect/diff/templ commands, job-to-job output wiring, log rotation/retention. Refs #20 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
4115a11845
commit
4d299fda98
@@ -106,6 +106,49 @@ Modes: `database` (default) · `schema` · `table` · `script`
|
||||
|
||||
Template functions: string utils (`toCamelCase`, `toSnakeCase`, `pluralize`, …), type converters (`sqlToGo`, `sqlToTypeScript`, …), filters, loop helpers, safe access.
|
||||
|
||||
### `job` — Declarative job files
|
||||
|
||||
Run named jobs from a `relspec.yml` manifest instead of repeating long command lines.
|
||||
|
||||
```bash
|
||||
# List jobs discovered in ./relspec.yml and ./relspec.<name>.yml (deterministic)
|
||||
relspec job list
|
||||
|
||||
# Validate and print the plan without running anything
|
||||
relspec job run build-schema --plan
|
||||
|
||||
# Run a job (and its declared dependencies)
|
||||
relspec job run build-schema
|
||||
```
|
||||
|
||||
```yaml
|
||||
# relspec.yml
|
||||
version: 1
|
||||
jobs:
|
||||
build-schema:
|
||||
command: convert # closed allow-list: convert | merge | scripts-list
|
||||
description: Merge the DBML sources and emit PostgreSQL DDL
|
||||
inputs:
|
||||
- path: schema/core.dbml
|
||||
format: dbml
|
||||
- path: schema/tenant.dbml
|
||||
format: dbml
|
||||
output:
|
||||
format: pgsql
|
||||
path: build/schema.sql
|
||||
overwrite: true
|
||||
options:
|
||||
flatten_schema: false
|
||||
logfile: .relspec/log/build-schema.log
|
||||
```
|
||||
|
||||
The job system is **not** a shell: `command` is a fixed enum, every path is
|
||||
resolved relative to the job file and may not escape it, and remote database
|
||||
credentials are referenced by environment-variable name (`conn_env:`) and
|
||||
redacted from logs. The whole plan — unknown commands/formats, duplicate job
|
||||
names, missing inputs, path traversal, dependency cycles — is validated before
|
||||
any job runs. See [docs/JOB_FILES.md](docs/JOB_FILES.md).
|
||||
|
||||
### `edit` — Interactive TUI editor
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user