-
-
Notifications
You must be signed in to change notification settings - Fork 774
Description
Nested include vars overridden by ancestor include vars
Description
This issue may be related to the Variables Megathread discussion (#2034) and the scoping proposal in #2035, but I want to report a specific behavior that appears to contradict the fix in PR #1256 ("fix: propagate include vars in multi-level includes").
I believe the behavior described here is an edge case not covered by #1256 or a regression of that PR, but apologies if this is the expected behavior or a duplicate issue.
Summary
In nested includes (A → B → C), vars explicitly passed in the child include (B → C) are overridden by vars from the ancestor include (A → B). The immediate parent's explicit vars declaration is ignored. This seems inconsistent with PR #1256's intent to properly propagate include vars in multi-level includes.
Minimal Reproduction
minimal_test/
├── Taskfile.yml # includes TasksLevel1 with EGVAR='INHERITED-root-value'
├── TasksLevel1.yml # includes TasksLevel2 with EGVAR='PASSED-via-includes-in-level1'
└── TasksLevel2.yml # expects 'PASSED-via-includes-in-level1', gets 'INHERITED-root-value'
Taskfile.yml
version: '3'
includes:
level1:
taskfile: './TasksLevel1.yml'
vars:
EGVAR: 'INHERITED-root-value'TasksLevel1.yml
version: '3'
includes:
level2:
taskfile: './TasksLevel2.yml'
vars:
EGVAR: 'PASSED-via-includes-in-level1' # IGNORED when invoked via root
tasks:
show:
cmds:
- echo "EGVAR={{.EGVAR}}"
call-level2-workaround:
cmds:
- task: level2:show
vars:
EGVAR: 'PASSED-via-task-in-level1'TasksLevel2.yml
version: '3'
vars:
DERIVED_EGVAR: '{{.EGVAR}}-derived' # Computed at parse time
tasks:
show:
cmds:
- echo "EGVAR={{.EGVAR}}"
- echo "DERIVED_EGVAR={{.DERIVED_EGVAR}}"Observed Behavior
# Nested includes: ancestor var overrides immediate parent's explicit var
$ task level1:level2:show
EGVAR=INHERITED-root-value
DERIVED_EGVAR=INHERITED-root-value-derived
# Direct invocation: immediate include var works correctly
$ task -t TasksLevel1.yml level2:show
EGVAR=PASSED-via-includes-in-level1
DERIVED_EGVAR=PASSED-via-includes-in-level1-derivedExpected Behavior
TasksLevel2.yml should receive EGVAR='PASSED-via-includes-in-level1' because that is what TasksLevel1.yml explicitly passes in its includes.
Task-Call-Time Vars Do Not Resolve This
Passing vars at task-call time (rather than include time) does not fully resolve this issue:
$ task level1:call-level2-workaround
EGVAR=PASSED-via-task-in-level1 # Task-call var works
DERIVED_EGVAR=INHERITED-root-value-derived # Global var still wrongTask-call vars override EGVAR for task execution, but cannot affect DERIVED_EGVAR, which was already evaluated at include time using the (incorrect) ancestor value.
Why This Seems Like a Bug
-
Explicit declarations ignored:
vars: { EGVAR: '...' }in an include statement is an explicit override. Silent replacement by an ancestor's value violates least-surprise. -
Entry-point-dependent behavior: The same taskfile behaves differently depending on whether it is the root or included from a parent.
-
Contradicts fix: propagate include vars in multi-level includes #1256: PR fix: propagate include vars in multi-level includes #1256 fixed multi-level include var propagation. Vars now propagate, but with incorrect precedence—ancestor wins over immediate parent.
Related Issues
| Issue | Problem | This Bug |
|---|---|---|
| #996 | Vars nil/lost | Vars propagate, wrong precedence |
| #1800 | Child vars override parent | Opposite: ancestor overrides child |
| #2595 | Race condition | Deterministic |
- fix: propagate include vars in multi-level includes #1256 - PR that fixed multi-level include var propagation
- Variables Megathread #2034 - Variables Megathread
- Proposal: Variable scope and inheritance #2035 - Variable Scope and Inheritance Proposal
Version
3.46.3
Operating system
macOS 14.8.3
Experiments Enabled
No response
Example Taskfile
See above