Add runtime HCL expression evaluation #6
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Testing
go test ./...Prompt
Task 5: Integrate Template Evaluation for HCL Taskfiles
Purpose: Task currently supports Go templating in Taskfiles (e.g. using {{ }} for dynamic values or
injecting variables). We must ensure the same templating mechanism works for HCL files as it does for YAML
files. The challenge is that the HCL parser expects valid syntax, so template placeholders must be
resolved before parsing.
• Implementation:
• Locate where YAML Taskfile templating is handled. Typically, the process is: read file as text ->
run text/template (with Task’s custom functions/vars) -> then YAML decode. This templating step should be
reused for HCL: apply it to the raw HCL file content before handing off to the HCL parser.
• If not already abstracted, factor out a common function like ExecuteTemplates(input []byte)
([]byte, error) that takes the file content and applies the Go template engine. This function should be
called for both YAML and HCL loading. Use the same data context so that {{.VAR}}, {{.ENV}}, and Task’s
custom template functions work consistently.
• Be careful that template output yields syntactically correct HCL. For example, if a template
inserts a string without quotes into HCL, it could break parsing. In documentation, users likely will
quote their template expressions appropriately (just as in YAML). We should document or enforce that (e.g.
if template produces a bare word in HCL, it might be interpreted as identifier; ideally, encourage
templates to produce strings or numbers as needed).
• Update the HCL loader flow:
1. Read the file content ([]byte).
2. Run the template expansion on it (with proper context, e.g. environment variables, user-provided
vars, etc.).
3. Then parse the resulting content via HCL as implemented in Tasks 3-4.
4. If template rendering fails (syntax error in {{}}), report the error. If the rendered content
fails HCL parse, report it with context (it could be user error in template output).
• Add support for any template-specific functions that were YAML-only. For instance, Task provides
fromYaml and toYaml functions in templates ; we might introduce fromHCL/toHCL if needed. Initially, this
might not be necessary – templates can still use YAML functions, but it might make sense to offer fromHCL
if users want to parse an HCL snippet in a template. This can be a future enhancement – mention it in
documentation if not doing it now.
• Validation:
• Create a test HCL Taskfile that uses templates. For example:
{{ $msg := "Hello" }}
task "echo" {
cmds = ["echo {{ $msg }} world"]
}
After loading, the task’s command should be echo Hello world. Write a test to verify that the template is
evaluated and the command contains the injected value.
"HOME"}} or {{splitLines .VAR}} inside an HCL Taskfile and ensure they behave as expected. This ensures
the template engine context is the same for both formats.
• Ensure that a syntax error in a template inside an HCL file yields a clear error (ideally
mentioning it’s a template error). Similarly, an error in HCL content after template expansion should
still point to the correct location (which might be tricky if templates alter line numbers – as a stretch
goal, we could improve error messages by mapping them back to original file lines, but that may be outside
this scope).
• Verify that disabling templating (if Task has an option to turn it off) works uniformly for HCL.
✅ Task 5 (Corrected): Implement HCL Runtime Expression Evaluation
Goal:
Evaluate all previously captured HCL expressions at runtime — lazily — using an hcl.EvalContext. This
replaces Go templating for HCL Taskfiles.
⸻
🔧 Changes Required
Create a struct:
type HCLEvaluator struct {
EvalCtx *hcl.EvalContext
}
Populate it with:
• Task-level vars (cty.StringVal)
• Global vars
• Environment vars (via cty.StringVal(os.Getenv("FOO")))
• Add support for built-in functions via EvalCtx.Functions = map[string]function.Function{} —
consider adding:
• upper(string)
• lower(string)
• join(list, delimiter)
• split(string, delimiter)
• env(string) to fetch environment variables
Use cty from HashiCorp and follow examples from Terraform and Docker Bake.
⸻
Update the task execution logic (likely in internal/compiler or executor) to:
• If the task is HCL:
• For each cmd hcl.Expression, call expr.Value(ctx)
• For each var or env, call expr.Value(ctx)
• Set the resulting string into the actual cmd or shell env before execution
This runtime eval should mirror how templating is done in YAML, but via native HCL.
⸻
To match YAML behavior with {sh: "echo hi"}, allow an HCL function like:
vars = {
COMMIT = sh("git rev-parse HEAD")
}
Register sh(string) string in EvalContext.Functions, and inside it run the shell command and return the
output.
For now, support only basic static HCL expressions and simple functions like upper.
⸻
✅ Acceptance Criteria
• Running this Taskfile:
task "build" {
vars = {
FOO = "bar"
}
cmds = ["echo ${upper(FOO)}"]
}
Should print:
echo BAR
• HCL expressions should resolve only at runtime, not during file load
• env("HOME") should fetch the actual environment variable
• If a variable or function is missing, runtime should return a clear error message with filename
and line
⸻
🧪 Tests
• ✅ Add tests that call expr.Value(ctx) and check output for:
• ${FOO}
• ${upper(FOO)}
• ${env("HOME")}
• ✅ Run task -t Taskfile.hcl hello and assert correct output of interpolated values
• ❌ Assert that YAML Taskfiles still use Go templates, not HCL
• ❌ Do not allow ${} expressions in YAML Taskfiles — ensure evaluator is only used for HCL tasks
https://chatgpt.com/codex/tasks/task_e_68920bfe9d64833089e812053af74717