diff --git a/CHANGELOG.md b/CHANGELOG.md index d81487a9..6ebab2b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ([#252](https://github.com/go-task/task/issues/252)). - Implement short task syntax ([#194](https://github.com/go-task/task/issues/194), [#240](https://github.com/go-task/task/pull/240)). +- Added option to make included Taskfile run commands on its own directory + ([#260](https://github.com/go-task/task/issues/260), [#144](https://github.com/go-task/task/issues/144)) # v3.0.0 - Preview 2 diff --git a/internal/taskfile/included_taskfile.go b/internal/taskfile/included_taskfile.go new file mode 100644 index 00000000..346744f9 --- /dev/null +++ b/internal/taskfile/included_taskfile.go @@ -0,0 +1,40 @@ +package taskfile + +import "errors" + +var ( + // ErrCantUnmarshalIncludedTaskfile is returned for invalid var YAML. + ErrCantUnmarshalIncludedTaskfile = errors.New("task: can't unmarshal included value") +) + +// IncludedTaskfile represents information about included tasksfile +type IncludedTaskfile struct { + Taskfile string + Dir string + AdvancedImport bool +} + +// IncludedTaskfiles represents information about included tasksfiles +type IncludedTaskfiles = map[string]IncludedTaskfile + +// UnmarshalYAML implements yaml.Unmarshaler interface +func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) error { + var str string + if err := unmarshal(&str); err == nil { + it.Taskfile = str + return nil + } + + var includedTaskfile struct { + Taskfile string + Dir string + } + if err := unmarshal(&includedTaskfile); err == nil { + it.Dir = includedTaskfile.Dir + it.Taskfile = includedTaskfile.Taskfile + it.AdvancedImport = true + return nil + } + + return ErrCantUnmarshalIncludedTaskfile +} diff --git a/internal/taskfile/merge.go b/internal/taskfile/merge.go index b9f415ba..d350e4b9 100644 --- a/internal/taskfile/merge.go +++ b/internal/taskfile/merge.go @@ -22,7 +22,7 @@ func Merge(t1, t2 *Taskfile, namespaces ...string) error { } if t1.Includes == nil { - t1.Includes = make(map[string]string) + t1.Includes = make(IncludedTaskfiles) } for k, v := range t2.Includes { t1.Includes[k] = v diff --git a/internal/taskfile/read/taskfile.go b/internal/taskfile/read/taskfile.go index a08360d3..7b1db509 100644 --- a/internal/taskfile/read/taskfile.go +++ b/internal/taskfile/read/taskfile.go @@ -28,8 +28,13 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) { return nil, err } - for namespace, path := range t.Includes { - path = filepath.Join(dir, path) + for namespace, includedTask := range t.Includes { + if filepath.IsAbs(includedTask.Taskfile) { + path = includedTask.Taskfile + } else { + path = filepath.Join(dir, includedTask.Taskfile) + } + info, err := os.Stat(path) if err != nil { return nil, err @@ -44,6 +49,15 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) { if len(includedTaskfile.Includes) > 0 { return nil, ErrIncludedTaskfilesCantHaveIncludes } + + if includedTask.AdvancedImport { + for _, task := range includedTaskfile.Tasks { + if !filepath.IsAbs(task.Dir) { + task.Dir = filepath.Join(includedTask.Dir, task.Dir) + } + } + } + if err = taskfile.Merge(t, includedTaskfile, namespace); err != nil { return nil, err } diff --git a/internal/taskfile/taskfile.go b/internal/taskfile/taskfile.go index 52b707c8..bcb7653c 100644 --- a/internal/taskfile/taskfile.go +++ b/internal/taskfile/taskfile.go @@ -6,7 +6,7 @@ type Taskfile struct { Expansions int Output string Method string - Includes map[string]string + Includes IncludedTaskfiles Vars Vars Env Vars Tasks Tasks @@ -20,7 +20,7 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error { Expansions int Output string Method string - Includes map[string]string + Includes IncludedTaskfiles Vars Vars Env Vars Tasks Tasks diff --git a/task.go b/task.go index 8c1b14b7..5c4f07d6 100644 --- a/task.go +++ b/task.go @@ -207,6 +207,14 @@ func (e *Executor) Setup() error { } } + if v < 3 { + for _, taskfile := range e.Taskfile.Includes { + if taskfile.AdvancedImport { + return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`) + } + } + } + e.taskCallCount = make(map[string]*int32, len(e.Taskfile.Tasks)) e.mkdirMutexMap = make(map[string]*sync.Mutex, len(e.Taskfile.Tasks)) for k := range e.Taskfile.Tasks { diff --git a/task_test.go b/task_test.go index 5877088d..c752e95b 100644 --- a/task_test.go +++ b/task_test.go @@ -540,14 +540,32 @@ func TestIncludes(t *testing.T) { Target: "default", TrimSpace: true, Files: map[string]string{ - "main.txt": "main", - "included_directory.txt": "included_directory", - "included_taskfile.txt": "included_taskfile", + "main.txt": "main", + "included_directory.txt": "included_directory", + "included_directory_without_dir.txt": "included_directory_without_dir", + "included_taskfile_without_dir.txt": "included_taskfile_without_dir", + "./module2/included_directory_with_dir.txt": "included_directory_with_dir", + "./module2/included_taskfile_with_dir.txt": "included_taskfile_with_dir", }, } tt.Run(t) } +func TestIncorrectVersionIncludes(t *testing.T) { + const dir = "testdata/incorrect_includes" + expectedError := "task: Import with additional parameters is only available starting on Taskfile version v3" + + var buff bytes.Buffer + e := task.Executor{ + Dir: dir, + Stdout: &buff, + Stderr: &buff, + Silent: true, + } + + assert.EqualError(t, e.Setup(), expectedError) +} + func TestIncludesEmptyMain(t *testing.T) { tt := fileContentTest{ Dir: "testdata/includes_empty", diff --git a/testdata/includes/Taskfile.yml b/testdata/includes/Taskfile.yml index 6b7f29ef..e94099e1 100644 --- a/testdata/includes/Taskfile.yml +++ b/testdata/includes/Taskfile.yml @@ -1,8 +1,18 @@ -version: '2' +version: '3' includes: included: ./included included_taskfile: ./Taskfile2.yml + included_without_dir: + taskfile: ./module1 + included_taskfile_without_dir: + taskfile: ./module1/Taskfile.yml + included_with_dir: + taskfile: ./module2 + dir: ./module2 + included_taskfile_with_dir: + taskfile: ./module2/Taskfile.yml + dir: ./module2 tasks: default: @@ -10,6 +20,10 @@ tasks: - task: gen - task: included:gen - task: included_taskfile:gen + - task: included_without_dir:gen_file + - task: included_taskfile_without_dir:gen_dir + - task: included_with_dir:gen_file + - task: included_taskfile_with_dir:gen_dir gen: cmds: diff --git a/testdata/includes/Taskfile2.yml b/testdata/includes/Taskfile2.yml index dbb4a34c..858fb38b 100644 --- a/testdata/includes/Taskfile2.yml +++ b/testdata/includes/Taskfile2.yml @@ -1,4 +1,4 @@ -version: '2' +version: '3' tasks: gen: diff --git a/testdata/includes/included/Taskfile.yml b/testdata/includes/included/Taskfile.yml index e8fe2ad2..93b82347 100644 --- a/testdata/includes/included/Taskfile.yml +++ b/testdata/includes/included/Taskfile.yml @@ -1,4 +1,4 @@ -version: '2' +version: '3' tasks: gen: diff --git a/testdata/includes/module1/Taskfile.yml b/testdata/includes/module1/Taskfile.yml new file mode 100644 index 00000000..3659073e --- /dev/null +++ b/testdata/includes/module1/Taskfile.yml @@ -0,0 +1,10 @@ +version: '3' + +tasks: + gen_dir: + cmds: + - echo included_directory_without_dir > included_directory_without_dir.txt + + gen_file: + cmds: + - echo included_taskfile_without_dir > included_taskfile_without_dir.txt diff --git a/testdata/includes/module2/Taskfile.yml b/testdata/includes/module2/Taskfile.yml new file mode 100644 index 00000000..09bbdb60 --- /dev/null +++ b/testdata/includes/module2/Taskfile.yml @@ -0,0 +1,10 @@ +version: '3' + +tasks: + gen_dir: + cmds: + - echo included_directory_with_dir > included_directory_with_dir.txt + + gen_file: + cmds: + - echo included_taskfile_with_dir > included_taskfile_with_dir.txt diff --git a/testdata/incorrect_includes/Taskfile.yml b/testdata/incorrect_includes/Taskfile.yml new file mode 100644 index 00000000..63f4745b --- /dev/null +++ b/testdata/incorrect_includes/Taskfile.yml @@ -0,0 +1,10 @@ +version: '2.6' + +includes: + included: + taskfile: ./included + +tasks: + default: + cmds: + - task: gen diff --git a/testdata/incorrect_includes/included/Taskfile.yml b/testdata/incorrect_includes/included/Taskfile.yml new file mode 100644 index 00000000..a50cc0ba --- /dev/null +++ b/testdata/incorrect_includes/included/Taskfile.yml @@ -0,0 +1,6 @@ +version: '2.6' + +tasks: + gen: + cmds: + - echo incorrect includes test