Ctrl K
ComunidadGuías…

specs/054-template.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Spec: Template Action

## Status

Partially implemented.

Conformance covers inline and referenced templates, data resolution, stdout
and file output, and representative validation/render errors. Function
permutations and filesystem failure cases belong in executor tests.

This spec defines conformance behavior for the built-in `template.render`
action.

## Scope

This spec covers:

- `with.template` and `with.template_ref`: exactly one is required;
  `with.template` supplies the template text directly, `with.template_ref`
  names a complete scoped value reference (such as `${env.NAME}`) whose
  resolved value is used as the template text instead
- that the template text itself -- whether from `with.template` or
  resolved from `with.template_ref` -- is never run through Dagu's own
  `${...}` value substitution, unlike an ordinary `run:` script body;
  only Go's `{{ }}` template syntax is evaluated against it
- `with.data`: an object of pipeline data, resolved the same way any
  other `with:` field is (env var substitution, and so on) before being
  passed to the template as `.`
- `with.output`: a file path to write the rendered result to, instead of
  stdout, creating missing parent directories
- deterministic template functions and pipeline-friendly argument ordering
- `missingkey=error` behavior: referencing an undeclared data key fails
  the step
- build-time parsing of `with.template` text, including the hint given
  when a `with.data` key is written without its leading dot
- validation and runtime errors

This spec does not define:

- the full template function catalog
- the value-reference syntax itself (`${env.NAME}`, `${steps.*.outputs.*}`,
  and so on) -- see [Spec 007: Value Resolution Steps](007-value-resolution-steps.md)
- direct `type: template` authoring

## Goal

Workflow authors render text (configuration files, messages, generated
scripts) from structured data as a DAG step, using a template language,
without shelling out to a separate templating tool.

## Behavior

### Template source

Exactly one of `with.template` or `with.template_ref` is required.
`with.template` is the template text itself. `with.template_ref` is a
value reference that must be the entire field value (for example,
`${env.NAME}`); its resolved value becomes the template text. A
reference embedded in surrounding text (for example, `"prefix
${env.NAME} suffix"`) is rejected -- the field must be exactly one
reference.

### No double substitution

The template text is handed to Go's `text/template` engine unmodified;
Dagu does not apply its own `${...}` substitution to it first. This
differs from an ordinary `run:` script body, which does substitute
`${...}` references before executing. As a result, a template can
freely emit literal `${...}`-shaped text (for example, to generate
another workflow's YAML) without it being consumed by Dagu first.

`with.data`, by contrast, is resolved the same way any other `with:`
field is -- a bare `$VAR` or `${VAR}` inside a `with.data` value
resolves normally -- before being passed to the template as `.`.

### Parsing

Inline `with.template` text is parsed when the DAG is built, so a `{{ }}`
syntax error is reported by `dagu validate` and rejects the DAG before any
step runs. `with.template_ref` text is only known at run time and is parsed
when the step runs.

Template data is addressed through the dot: `{{ .key }}`. A bare
`{{ key }}` is a function call in Go templates. When the parse error names
an undefined function whose name is a `with.data` key, the error adds a
hint that the key needs a leading dot.

### Rendering

The template is executed with `missingkey=error`: referencing
a data key that is not present in `with.data` fails the step, rather
than rendering an empty value. The rendered result is written to stdout,
or, when `with.output` is set, to that file path (resolved relative to
the step's working directory when relative), creating any missing
parent directories first.

### Template functions

Template functions support deterministic rendering from template text and
`with.data`. Pipeline functions take the pipeline value as their last
argument. The full function catalog is outside this conformance scope.

## Errors

### Validation

Every one of these is rejected at DAG-build-time validation (`dagu
validate`), not only when the step runs:

- Neither `with.template` nor `with.template_ref` set, or both set: an
  error containing `"requires exactly one of with.template or
  with.template_ref"`.
- `with.template_ref` set to a value that is not exactly one complete
  scoped reference: an error containing `"must be one complete scoped
  value reference"`.
- `with.template` text with invalid `{{ }}` syntax: an error containing
  `"template: parse error"`. When the undefined function name is a
  `with.data` key, the error also contains `is a with.data key and needs a
  leading dot`.
- A `with` field other than `template`, `template_ref`, `data`, and
  `output`: an error containing `unexpected additional properties` and the
  field name. When a defined field is a likely misspelling of it, the error
  also suggests that field, such as `did you mean "data" instead of
  "datas"?`.

### Runtime

- A template referencing a data key that is not present in `with.data`:
  an error containing `"map has no entry for key"`.
- A `with.template_ref` template with invalid `{{ }}` syntax: an error
  containing `"template: parse error"`, with the same hint as above.

### Lifecycle and cleanup

Timeout and abort are owned by the step-run lifecycle. This spec adds no
stronger interruption or rollback guarantee. Parsing and data evaluation
complete before rendered output is emitted. A parse or missing-key error
therefore produces no rendered output. Output-directory or file-write
failures fail the step.

## Related Specs

- Value resolution and reference syntax: [Spec 007: Value Resolution
  Steps](007-value-resolution-steps.md)
- Step run scripts, for contrast with template's no-substitution
  behavior: [Spec 015: Step Run Script](015-step-run-script.md)

## Examples

Render a config file from structured data:

```yaml
steps:
  - action: template.render
    with:
      template: |
        name: {{ .service }}
        replicas: {{ .replicas }}
      data:
        service: checkout
        replicas: 3
      output: ./build/config.yaml
```

Render a template whose text comes from an environment variable:

```yaml
env:
  - MESSAGE_TEMPLATE: "Deploy {{ .version }} complete"
steps:
  - action: template.render
    with:
      template_ref: "${env.MESSAGE_TEMPLATE}"
      data:
        version: "1.4.0"
```