feat: template hyphen auto-fix, config imports, and pipeline template linting#202
Merged
feat: template hyphen auto-fix, config imports, and pipeline template linting#202
Conversation
… linting
Three features to make workflow configs safer and more maintainable:
Template engine:
- preprocessTemplate() auto-rewrites hyphenated dot-access to index syntax
before Go's parser sees it (e.g., .steps.my-step.field just works)
- step/trigger helper functions for clean syntax without quoting issues
(e.g., {{ step "parse-request" "path_params" "id" }})
- 16 new tests covering preprocessor, helpers, and end-to-end
Config imports:
- imports: field in WorkflowConfig for splitting large configs into
domain-specific files with recursive loading and circular detection
- Main file definitions take precedence; modules concatenated in order
- 8 new tests covering basic imports, precedence, nesting, and errors
Pipeline template validation (wfctl template validate --config):
- Lints template expressions for undefined step references
- Warns on forward references (step referenced before it executes)
- Suggests step function syntax for hyphenated dot-access patterns
- 5 new tests for the linter
Documentation updated with template data context, hyphen handling guide,
import syntax and merge rules, and ApplicationConfig comparison.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces three complementary features to make workflow configurations more robust and maintainable: automatic template hyphen handling, config file imports for splitting large configurations, and template expression linting.
Changes:
- Template engine automatically rewrites hyphenated dot-access patterns (
.steps.my-step.field) to Go-compatibleindexsyntax, plus newstep/triggerhelper functions - Config import system allowing recursive file composition with circular detection and main-file-wins precedence
- Pipeline template validator that lints step references, detects undefined/forward references, and suggests best practices
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| module/pipeline_template.go | Adds preprocessTemplate() regex rewriter and funcMapWithContext() for step/trigger helpers |
| module/pipeline_template_test.go | 16 new tests covering preprocessing, helper functions, and end-to-end hyphenated step resolution |
| config/config.go | Implements imports field, loadFromFileWithImports() with circular detection, and processImports() merge logic |
| config/config_import_test.go | 8 comprehensive tests for import scenarios: basic, precedence, circular, nested, missing, relative paths |
| cmd/wfctl/template_validate.go | Adds validatePipelineTemplates(), collectTemplateStrings(), and validateStepRef() for expression linting |
| cmd/wfctl/template_validate_test.go | 5 new tests for step reference validation (missing, forward, hyphenated, step function) |
| DOCUMENTATION.md | Documents template data context, hyphen handling approaches, config imports syntax and merge rules |
- Fix diamond import bug: use stack-based (defer delete) circular detection so shared dependencies imported via multiple paths don't false-positive - Fix hyphenDotRe regex to match full chains (e.g. .steps.my-step.field) - Tighten stepRefFuncRe regex to avoid false positives on non-function contexts - Use unique placeholder sentinel instead of bare \x00 for string literal stripping - Differentiate self-reference from forward-reference in validation warnings - Add diamond import test case - Add self-reference validation test case - Document depth-first import merge order and ambiguous hyphen/subtraction behavior - Add clarifying comments on collectTemplateStrings and stringLiteralRe Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix validation step numbering to match execution order (1-5) - Add RE2 note to stringLiteralRe (Go regex has no backtracking/ReDoS) - Optimize placeholder restoration: use strings.Index instead of O(n*m) scan - Deduplicate modules in diamond imports (first definition wins) - Clarify comment detection: only pure block comments are skipped - Document step/trigger function nil-return semantics - Fix DOCUMENTATION.md escaped pipes in trimPrefix/trimSuffix examples - Add tests: unclosed template action, escaped quotes in string literals - Diamond import test now verifies no duplicate modules Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
Three features to make workflow configs safer and more maintainable:
{{ .steps.my-step.field }}just works — the engine auto-rewrites toindexsyntax before Go's template parser sees it. Also addsstep/triggerhelper functions as clean alternatives.imports:field in WorkflowConfig for splitting large configs (like ratchet.yaml at 2500+ lines) into domain-specific files. Recursive with circular detection, main-file-wins precedence.wfctl template validate --confignow lints template expressions — catches undefined step references, forward references, and suggests preferred syntax.Changes
Template Engine (
module/pipeline_template.go)preprocessTemplate()— regex-based rewriter that converts hyphenated dot-access chains to(index ...)beforetemplate.Parse()funcMapWithContext()— addsstepandtriggercontext-aware helper functionsConfig Imports (
config/config.go)Imports []stringfield onWorkflowConfigloadFromFileWithImports()— recursive loader withseenmap for circular detectionprocessImports()— merges imported modules (append) and maps (no-overwrite)Pipeline Template Linting (
cmd/wfctl/template_validate.go)validatePipelineTemplates()— scans step configs for{{ }}expressionsindex, andstepfunctionvalidateStepRef()— checks existence and orderingcollectTemplateStrings()— recursive string collectorDocumentation (
DOCUMENTATION.md).steps,.trigger,.meta)stepfunction,index)Test plan
go test ./module/...— 36 template tests pass (16 new)go test ./config/...— 60+ config tests pass (8 new)go test ./cmd/wfctl/...— 18 validation tests pass (5 new)go build ./...— clean🤖 Generated with Claude Code