Tests verify:
- Legacy mode: vars merged globally (A sees B's VAR, can access UNIQUE_B)
- Scoped mode: vars isolated (A sees own VAR, cannot access UNIQUE_B)
- Inheritance: includes can still access root vars (ROOT_VAR)
Test structure:
- testdata/scoped_includes/ with main Taskfile and two includes
- inc_a and inc_b both define VAR with different values
- Cross-include test shows A trying to access B's UNIQUE_B
When SCOPED_INCLUDES experiment is enabled:
- Resolve vars from DAG instead of merged vars
- Apply root Taskfile vars first (inheritance)
- Then apply task's source Taskfile vars from DAG
- Apply IncludeVars passed via includes: section
- Skip IncludedTaskfileVars (contains parent's vars, not source's)
This ensures tasks in included Taskfiles see:
1. Root vars (inheritance from parent)
2. Their own Taskfile's vars
3. Vars passed through includes: section
4. Call vars and task-level vars
When the SCOPED_INCLUDES experiment is enabled, variables from included
Taskfiles are no longer merged globally. They remain in their original
Taskfile within the DAG.
Exception: flatten includes still merge variables globally to allow
sharing common variables across multiple Taskfiles.
Add Root() method to TaskfileGraph to get the root vertex (entrypoint
Taskfile). This will be used for lazy variable resolution.
Note: Tasks already have Location.Taskfile which can be used to find
their source Taskfile in the graph, so GetVertexByNamespace is not
needed.
Store the TaskfileGraph in the Executor so it can be used for lazy
variable resolution when SCOPED_INCLUDES experiment is enabled.
The graph is now preserved after reading, before merging into the
final Taskfile. This allows traversing the DAG at runtime to resolve
variables from the correct scope.
Add new experiment flag TASK_X_SCOPED_INCLUDES for scoped variable
resolution in included Taskfiles. When enabled, variables from included
Taskfiles will be isolated rather than merged globally.
This is the first step towards implementing lazy DAG-based variable
resolution with strict isolation between includes.
When using `task FOO=bar` with a Taskfile containing
`FOO: '{{.FOO | default "foo"}}'`, the CLI value was being
overwritten by the Taskfile default.
Split the variable merging into two steps:
1. Merge CLI variables (FOO=bar) first so they override Taskfile vars
2. ReverseMerge special variables (CLI_ARGS, CLI_FORCE, etc.) so
they're available for templating in Taskfile vars
Fixes regression introduced in #2403.
Co-authored-by: Timothy Rule <timothy.rule@gmail.com>