diff --git a/CHANGELOG.md b/CHANGELOG.md index e48777666d..d3e668da22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ - Fix a missing a line break on log when using `--watch` mode (#1285, #1297 by @FilipSolich). - Fix `defer` on JSON Schema (#1288 by @calvinmclean and @andreynering). +- Fix bug in usage of special variables like `{{.USER_WORKING_DIR}}` in + combination with `includes` (#1046, #1205, #1250, #1293, #1312, #1274 by + @andarto, #1309 by @andreynering). ## v3.28.0 - 2023-07-24 diff --git a/internal/filepathext/filepathext.go b/internal/filepathext/filepathext.go index 16ed5d0a25..db64695c8e 100644 --- a/internal/filepathext/filepathext.go +++ b/internal/filepathext/filepathext.go @@ -3,17 +3,43 @@ package filepathext import ( "os" "path/filepath" + "strings" ) // SmartJoin joins two paths, but only if the second is not already an // absolute path. func SmartJoin(a, b string) string { - if filepath.IsAbs(b) { + if IsAbs(b) { return b } return filepath.Join(a, b) } +func IsAbs(path string) bool { + // NOTE(@andreynering): If the path contains any if the special + // variables that we know are absolute, return true. + if isSpecialDir(path) { + return true + } + + return filepath.IsAbs(path) +} + +var knownAbsDirs = []string{ + ".ROOT_DIR", + ".TASKFILE_DIR", + ".USER_WORKING_DIR", +} + +func isSpecialDir(dir string) bool { + for _, d := range knownAbsDirs { + if strings.Contains(dir, d) { + return true + } + } + return false +} + // TryAbsToRel tries to convert an absolute path to relative based on the // process working directory. If it can't, it returns the absolute path. func TryAbsToRel(abs string) string { diff --git a/setup.go b/setup.go index 060cc7821f..2d1b3e6edf 100644 --- a/setup.go +++ b/setup.go @@ -175,13 +175,17 @@ func (e *Executor) setupCompiler() error { Logger: e.Logger, } } else { - userWorkingDir, err := os.Getwd() - if err != nil { - return err + if e.UserWorkingDir == "" { + var err error + e.UserWorkingDir, err = os.Getwd() + if err != nil { + return err + } } + e.Compiler = &compilerv3.CompilerV3{ Dir: e.Dir, - UserWorkingDir: userWorkingDir, + UserWorkingDir: e.UserWorkingDir, TaskfileEnv: e.Taskfile.Env, TaskfileVars: e.Taskfile.Vars, Logger: e.Logger, diff --git a/task.go b/task.go index cb55955403..dd540a41dc 100644 --- a/task.go +++ b/task.go @@ -67,11 +67,12 @@ type Executor struct { Stdout io.Writer Stderr io.Writer - Logger *logger.Logger - Compiler compiler.Compiler - Output output.Output - OutputStyle taskfile.Output - TaskSorter sort.TaskSorter + Logger *logger.Logger + Compiler compiler.Compiler + Output output.Output + OutputStyle taskfile.Output + TaskSorter sort.TaskSorter + UserWorkingDir string taskvars *taskfile.Vars fuzzyModel *fuzzy.Model diff --git a/task_test.go b/task_test.go index 5c5a153a52..a589629c96 100644 --- a/task_test.go +++ b/task_test.go @@ -1940,6 +1940,26 @@ func TestUserWorkingDirectory(t *testing.T) { assert.Equal(t, fmt.Sprintf("%s\n", wd), buff.String()) } +func TestUserWorkingDirectoryWithIncluded(t *testing.T) { + wd, err := os.Getwd() + require.NoError(t, err) + + wd = filepathext.SmartJoin(wd, "testdata/user_working_dir_with_includes/somedir") + + var buff bytes.Buffer + e := task.Executor{ + UserWorkingDir: wd, + Dir: "testdata/user_working_dir_with_includes", + Stdout: &buff, + Stderr: &buff, + } + + require.NoError(t, err) + require.NoError(t, e.Setup()) + require.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "included:echo"})) + assert.Equal(t, fmt.Sprintf("%s\n", wd), buff.String()) +} + func TestPlatforms(t *testing.T) { var buff bytes.Buffer e := task.Executor{ diff --git a/taskfile/included_taskfile.go b/taskfile/included_taskfile.go index 6137344fbe..c409052e20 100644 --- a/taskfile/included_taskfile.go +++ b/taskfile/included_taskfile.go @@ -153,7 +153,7 @@ func (it *IncludedTaskfile) resolvePath(path string) (string, error) { return "", err } - if filepath.IsAbs(path) { + if filepathext.IsAbs(path) { return path, nil } diff --git a/testdata/user_working_dir_with_includes/Taskfile.yml b/testdata/user_working_dir_with_includes/Taskfile.yml new file mode 100644 index 0000000000..2e369b6efa --- /dev/null +++ b/testdata/user_working_dir_with_includes/Taskfile.yml @@ -0,0 +1,5 @@ +version: '3' + +includes: + included: + taskfile: ./included/Taskfile.yml diff --git a/testdata/user_working_dir_with_includes/included/Taskfile.yml b/testdata/user_working_dir_with_includes/included/Taskfile.yml new file mode 100644 index 0000000000..ac853b7611 --- /dev/null +++ b/testdata/user_working_dir_with_includes/included/Taskfile.yml @@ -0,0 +1,8 @@ +version: '3' + +tasks: + echo: + dir: '{{.USER_WORKING_DIR}}' + cmds: + - pwd + silent: true diff --git a/testdata/user_working_dir_with_includes/somedir/.keep b/testdata/user_working_dir_with_includes/somedir/.keep new file mode 100644 index 0000000000..e69de29bb2