diff --git a/compiler.go b/compiler.go index c0679c2cbf..022ee263fe 100644 --- a/compiler.go +++ b/compiler.go @@ -115,7 +115,13 @@ func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (* } } // Resolve any outstanding 'Ref' values in global vars (esp. globals from imported Taskfiles). - c.TaskfileVars = templater.ReplaceVars(c.TaskfileVars, &templater.Cache{Vars: result}) + // Only process variables with Ref set to avoid clobbering already-resolved sh: variables. + cache := &templater.Cache{Vars: result} + for k, v := range c.TaskfileVars.All() { + if v.Ref != "" { + c.TaskfileVars.Set(k, ast.Var{Value: templater.ResolveRef(v.Ref, cache)}) + } + } if t != nil { for k, v := range t.IncludeVars.All() { diff --git a/executor_test.go b/executor_test.go index 05080b3474..370e3befd5 100644 --- a/executor_test.go +++ b/executor_test.go @@ -946,6 +946,32 @@ func TestReference(t *testing.T) { } } +func TestShVarWithIncludes(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + call string + }{ + { + name: "sh var not clobbered by includes", + call: "default", + }, + } + + for _, test := range tests { + NewExecutorTest(t, + WithName(test.name), + WithExecutorOptions( + task.WithDir("testdata/var_sh_with_includes"), + task.WithSilent(true), + task.WithForce(true), + ), + WithTask(cmp.Or(test.call, "default")), + ) + } +} + func TestVarInheritance(t *testing.T) { enableExperimentForTest(t, &experiments.EnvPrecedence, 1) tests := []struct { diff --git a/testdata/var_sh_with_includes/Included.yml b/testdata/var_sh_with_includes/Included.yml new file mode 100644 index 0000000000..9c0f4e437a --- /dev/null +++ b/testdata/var_sh_with_includes/Included.yml @@ -0,0 +1,6 @@ +version: '3' + +tasks: + noop: + cmds: + - "true" diff --git a/testdata/var_sh_with_includes/Taskfile.yml b/testdata/var_sh_with_includes/Taskfile.yml new file mode 100644 index 0000000000..7e3bf197dc --- /dev/null +++ b/testdata/var_sh_with_includes/Taskfile.yml @@ -0,0 +1,18 @@ +version: '3' + +includes: + other: + taskfile: ./Included.yml + internal: true + +vars: + DYNAMIC_VAR: + sh: echo "hello" + DERIVED_VAR: "{{.DYNAMIC_VAR}} world" + +tasks: + default: + cmds: + - echo "DYNAMIC_VAR={{.DYNAMIC_VAR}}" + - echo "DERIVED_VAR={{.DERIVED_VAR}}" + silent: true diff --git a/testdata/var_sh_with_includes/testdata/TestShVarWithIncludes-sh_var_not_clobbered_by_includes.golden b/testdata/var_sh_with_includes/testdata/TestShVarWithIncludes-sh_var_not_clobbered_by_includes.golden new file mode 100644 index 0000000000..066c073193 --- /dev/null +++ b/testdata/var_sh_with_includes/testdata/TestShVarWithIncludes-sh_var_not_clobbered_by_includes.golden @@ -0,0 +1,2 @@ +DYNAMIC_VAR=hello +DERIVED_VAR=hello world