diff --git a/variables.go b/variables.go index c10bfcd576..fa90276411 100644 --- a/variables.go +++ b/variables.go @@ -161,10 +161,11 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err } } } + dotenvEnvs = resolveDotenvVars(dotenvEnvs, cache) new.Env = ast.NewVars() new.Env.Merge(templater.ReplaceVars(e.Taskfile.Env, cache), nil) - new.Env.Merge(templater.ReplaceVars(dotenvEnvs, cache), nil) + new.Env.Merge(dotenvEnvs, nil) new.Env.Merge(templater.ReplaceVars(origTask.Env, cache), nil) if evaluateShVars { for k, v := range new.Env.All() { @@ -464,3 +465,23 @@ func product(matrix *ast.Matrix) []map[string]any { return result } + +func resolveDotenvVars(dotenvEnvs *ast.Vars, cache *templater.Cache) *ast.Vars { + if dotenvEnvs == nil || dotenvEnvs.Len() == 0 { + return dotenvEnvs + } + + resolved := dotenvEnvs + for range dotenvEnvs.Len() { + next := templater.ReplaceVarsWithExtra(resolved, cache, resolved.ToCacheMap()) + if next == nil { + return resolved + } + if fmt.Sprint(next.All()) == fmt.Sprint(resolved.All()) { + return next + } + resolved = next + } + + return resolved +} diff --git a/variables_dotenv_test.go b/variables_dotenv_test.go new file mode 100644 index 0000000000..865a35474c --- /dev/null +++ b/variables_dotenv_test.go @@ -0,0 +1,37 @@ +package task + +import ( + "testing" + + "github.com/go-task/task/v3/internal/templater" + "github.com/go-task/task/v3/taskfile/ast" + "github.com/stretchr/testify/require" +) + +func TestResolveDotenvVarsNestedTemplates(t *testing.T) { + t.Parallel() + + base := ast.NewVars() + base.Set("BASE_DIR", ast.Var{Value: "/home/user"}) + + cache := &templater.Cache{Vars: base} + + dotenv := ast.NewVars() + dotenv.Set("MID_DIR", ast.Var{Value: "{{.BASE_DIR}}/nested"}) + dotenv.Set("FINAL_DIR", ast.Var{Value: "{{.MID_DIR}}/deeper"}) + dotenv.Set("FULL_PATH", ast.Var{Value: "{{.FINAL_DIR}}/file.txt"}) + + resolved := resolveDotenvVars(dotenv, cache) + + mid, ok := resolved.Get("MID_DIR") + require.True(t, ok) + require.Equal(t, "/home/user/nested", mid.Value) + + finalDir, ok := resolved.Get("FINAL_DIR") + require.True(t, ok) + require.Equal(t, "/home/user/nested/deeper", finalDir.Value) + + fullPath, ok := resolved.Get("FULL_PATH") + require.True(t, ok) + require.Equal(t, "/home/user/nested/deeper/file.txt", fullPath.Value) +}