diff --git a/CHANGELOG.md b/CHANGELOG.md index d1c6d636..d1e7b0c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +- Fix a bug where dynamic variables (those declared with `sh:`) were not + running in the task directory when the task has a custom dir or it was + in an included taskfile + ([#384](https://github.com/go-task/task/issues/384)). - The watch feature (via the `--watch` flag) got a few different bug fixes and should be more stable now ([#423](https://github.com/go-task/task/pull/423), [#365](https://github.com/go-task/task/issues/365)). diff --git a/internal/compiler/compiler.go b/internal/compiler/compiler.go index 1e0fabfa..16c13886 100644 --- a/internal/compiler/compiler.go +++ b/internal/compiler/compiler.go @@ -8,6 +8,6 @@ import ( // E.g. variable merger, template processing, etc. type Compiler interface { GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) - HandleDynamicVar(v taskfile.Var) (string, error) + HandleDynamicVar(v taskfile.Var, dir string) (string, error) ResetCache() } diff --git a/internal/compiler/v2/compiler_v2.go b/internal/compiler/v2/compiler_v2.go index 5c1d6e46..d9319547 100644 --- a/internal/compiler/v2/compiler_v2.go +++ b/internal/compiler/v2/compiler_v2.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "path/filepath" "strings" "sync" @@ -37,8 +38,20 @@ type CompilerV2 struct { // 4. Taskvars file variables // 5. Environment variables func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) { - vr := varResolver{c: c, vars: compiler.GetEnviron()} + // NOTE(@andreynering): We're manually joining these paths here because + // this is the raw task, not the compiled one. + dir := t.Dir + if !filepath.IsAbs(dir) { + dir = filepath.Join(c.Dir, dir) + } + + vr := varResolver{ + c: c, + dir: dir, + vars: compiler.GetEnviron(), + } vr.vars.Set("TASK", taskfile.Var{Static: t.Task}) + for _, vars := range []*taskfile.Vars{c.Taskvars, c.TaskfileVars, call.Vars, t.Vars} { for i := 0; i < c.Expansions; i++ { vr.merge(vars) @@ -49,6 +62,7 @@ func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi type varResolver struct { c *CompilerV2 + dir string vars *taskfile.Vars err error } @@ -63,7 +77,7 @@ func (vr *varResolver) merge(vars *taskfile.Vars) { Static: tr.Replace(v.Static), Sh: tr.Replace(v.Sh), } - static, err := vr.c.HandleDynamicVar(v) + static, err := vr.c.HandleDynamicVar(v, vr.dir) if err != nil { vr.err = err return err @@ -74,7 +88,7 @@ func (vr *varResolver) merge(vars *taskfile.Vars) { vr.err = tr.Err() } -func (c *CompilerV2) HandleDynamicVar(v taskfile.Var) (string, error) { +func (c *CompilerV2) HandleDynamicVar(v taskfile.Var, dir string) (string, error) { if v.Static != "" || v.Sh == "" { return v.Static, nil } @@ -92,7 +106,7 @@ func (c *CompilerV2) HandleDynamicVar(v taskfile.Var) (string, error) { var stdout bytes.Buffer opts := &execext.RunCommandOptions{ Command: v.Sh, - Dir: c.Dir, + Dir: dir, Stdout: &stdout, Stderr: c.Logger.Stderr, } diff --git a/internal/compiler/v3/compiler_v3.go b/internal/compiler/v3/compiler_v3.go index 0cc9ba78..1c0e2d5b 100644 --- a/internal/compiler/v3/compiler_v3.go +++ b/internal/compiler/v3/compiler_v3.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "path/filepath" "strings" "sync" @@ -31,6 +32,13 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi result := compiler.GetEnviron() result.Set("TASK", taskfile.Var{Static: t.Task}) + // NOTE(@andreynering): We're manually joining these paths here because + // this is the raw task, not the compiled one. + dir := t.Dir + if !filepath.IsAbs(dir) { + dir = filepath.Join(c.Dir, dir) + } + rangeFunc := func(k string, v taskfile.Var) error { tr := templater.Templater{Vars: result, RemoveNoValue: true} v = taskfile.Var{ @@ -40,7 +48,7 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi if err := tr.Err(); err != nil { return err } - static, err := c.HandleDynamicVar(v) + static, err := c.HandleDynamicVar(v, dir) if err != nil { return err } @@ -61,7 +69,7 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi return result, nil } -func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) { +func (c *CompilerV3) HandleDynamicVar(v taskfile.Var, dir string) (string, error) { if v.Static != "" || v.Sh == "" { return v.Static, nil } @@ -79,7 +87,7 @@ func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) { var stdout bytes.Buffer opts := &execext.RunCommandOptions{ Command: v.Sh, - Dir: c.Dir, + Dir: dir, Stdout: &stdout, Stderr: c.Logger.Stderr, } diff --git a/task_test.go b/task_test.go index f86d2741..9613f814 100644 --- a/task_test.go +++ b/task_test.go @@ -303,16 +303,15 @@ func TestPrecondition(t *testing.T) { } func TestGenerates(t *testing.T) { + const dir = "testdata/generates" + const ( srcTask = "sub/src.txt" relTask = "rel.txt" - absTask = "abs.txt" + absTask = "sub/abs.txt" fileWithSpaces = "my text file.txt" ) - // This test does not work with a relative dir. - dir, err := filepath.Abs("testdata/generates") - assert.NoError(t, err) var srcFile = filepath.Join(dir, srcTask) for _, task := range []string{srcTask, relTask, absTask, fileWithSpaces} { @@ -800,6 +799,18 @@ func TestWhenDirAttributeItCreatesMissingAndRunsInThatDir(t *testing.T) { _ = os.RemoveAll(toBeCreated) } +func TestDynamicVariablesShouldRunOnTheTaskDir(t *testing.T) { + tt := fileContentTest{ + Dir: "testdata/dir/dynamic_var", + Target: "default", + TrimSpace: false, + Files: map[string]string{ + "subdirectory/dir.txt": "subdirectory\n", + }, + } + tt.Run(t) +} + func TestDisplaysErrorOnUnsupportedVersion(t *testing.T) { e := task.Executor{ Dir: "testdata/version/v1", diff --git a/testdata/dir/dynamic_var/.gitignore b/testdata/dir/dynamic_var/.gitignore new file mode 100644 index 00000000..5e4f4543 --- /dev/null +++ b/testdata/dir/dynamic_var/.gitignore @@ -0,0 +1 @@ +subdirectory/dir.txt diff --git a/testdata/dir/dynamic_var/Taskfile.yml b/testdata/dir/dynamic_var/Taskfile.yml new file mode 100644 index 00000000..9a2d8cd6 --- /dev/null +++ b/testdata/dir/dynamic_var/Taskfile.yml @@ -0,0 +1,11 @@ +version: '3' + +tasks: + default: + cmds: + - echo '{{.FOLDER}}' > dir.txt + dir: subdirectory + vars: + FOLDER: + sh: basename $(pwd) + silent: true diff --git a/testdata/dir/dynamic_var/subdirectory/dir.txt b/testdata/dir/dynamic_var/subdirectory/dir.txt new file mode 100644 index 00000000..bcba6aa2 --- /dev/null +++ b/testdata/dir/dynamic_var/subdirectory/dir.txt @@ -0,0 +1 @@ +subdirectory diff --git a/testdata/generates/Taskfile.yml b/testdata/generates/Taskfile.yml index 4dc6e9ec..e2f4a87b 100644 --- a/testdata/generates/Taskfile.yml +++ b/testdata/generates/Taskfile.yml @@ -4,7 +4,7 @@ vars: BUILD_DIR: $pwd tasks: - abs.txt: + sub/abs.txt: desc: generates dest file based on absolute paths deps: - sub/src.txt diff --git a/variables.go b/variables.go index 649bac4a..a6929cfd 100644 --- a/variables.go +++ b/variables.go @@ -60,7 +60,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) { new.Env.Merge(r.ReplaceVars(e.Taskfile.Env)) new.Env.Merge(r.ReplaceVars(origTask.Env)) err = new.Env.Range(func(k string, v taskfile.Var) error { - static, err := e.Compiler.HandleDynamicVar(v) + static, err := e.Compiler.HandleDynamicVar(v, new.Dir) if err != nil { return err }