diff --git a/CHANGELOG.md b/CHANGELOG.md index 679f07ef..8498408a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +- Add support for yaml extension ([#584](https://github.com/go-task/task/issues/584)) + ## v3.9.2 - 2021-12-02 - Upgrade [mvdan/sh](https://github.com/mvdan/sh) which contains a fix a for diff --git a/cmd/task/task.go b/cmd/task/task.go index 2f7a11c0..ae2d4f90 100644 --- a/cmd/task/task.go +++ b/cmd/task/task.go @@ -77,7 +77,7 @@ func main() { pflag.BoolVar(&versionFlag, "version", false, "show Task version") pflag.BoolVarP(&helpFlag, "help", "h", false, "shows Task usage") - pflag.BoolVarP(&init, "init", "i", false, "creates a new Taskfile.yml in the current folder") + pflag.BoolVarP(&init, "init", "i", false, "creates a new Taskfile.yaml in the current folder") pflag.BoolVarP(&list, "list", "l", false, "lists tasks with description of current Taskfile") pflag.BoolVar(&status, "status", false, "exits with non-zero exit code if any of the given tasks is not up-to-date") pflag.BoolVarP(&force, "force", "f", false, "forces execution even when the task is up-to-date") @@ -122,8 +122,6 @@ func main() { if entrypoint != "" { dir = filepath.Dir(entrypoint) entrypoint = filepath.Base(entrypoint) - } else { - entrypoint = "Taskfile.yml" } e := task.Executor{ diff --git a/completion/zsh/_task b/completion/zsh/_task index 48777e4b..2bd4ac40 100755 --- a/completion/zsh/_task +++ b/completion/zsh/_task @@ -4,7 +4,7 @@ function __list() { local -a scripts - if [ -f Taskfile.yml ]; then + if [ -f Taskfile.yml ] || [ -f Taskfile.yaml ]; then scripts=($(task -l | sed '1d' | sed 's/^\* //' | awk '{ print $1 }' | sed 's/:$//' | sed 's/:/\\:/g')) _describe 'script' scripts fi diff --git a/init.go b/init.go index 1c1d043f..2bddb210 100644 --- a/init.go +++ b/init.go @@ -23,7 +23,7 @@ tasks: // InitTaskfile Taskfile creates a new Taskfile func InitTaskfile(w io.Writer, dir string) error { - f := filepath.Join(dir, "Taskfile.yml") + f := filepath.Join(dir, "Taskfile.yaml") if _, err := os.Stat(f); err == nil { return ErrTaskfileAlreadyExists @@ -32,6 +32,6 @@ func InitTaskfile(w io.Writer, dir string) error { if err := os.WriteFile(f, []byte(defaultTaskfile), 0644); err != nil { return err } - fmt.Fprintf(w, "Taskfile.yml created in the current directory\n") + fmt.Fprintf(w, "Taskfile.yaml created in the current directory\n") return nil } diff --git a/task.go b/task.go index c1c4e286..7021b77a 100644 --- a/task.go +++ b/task.go @@ -105,10 +105,6 @@ func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error { // Setup setups Executor's internal state func (e *Executor) Setup() error { - if e.Entrypoint == "" { - e.Entrypoint = "Taskfile.yml" - } - var err error e.Taskfile, err = read.Taskfile(e.Dir, e.Entrypoint) if err != nil { diff --git a/task_test.go b/task_test.go index db83a851..f8e396f7 100644 --- a/task_test.go +++ b/task_test.go @@ -24,10 +24,11 @@ func init() { // fileContentTest provides a basic reusable test-case for running a Taskfile // and inspect generated files. type fileContentTest struct { - Dir string - Target string - TrimSpace bool - Files map[string]string + Dir string + Entrypoint string + Target string + TrimSpace bool + Files map[string]string } func (fct fileContentTest) name(file string) string { @@ -40,9 +41,10 @@ func (fct fileContentTest) Run(t *testing.T) { } e := &task.Executor{ - Dir: fct.Dir, - Stdout: io.Discard, - Stderr: io.Discard, + Dir: fct.Dir, + Entrypoint: fct.Entrypoint, + Stdout: io.Discard, + Stderr: io.Discard, } assert.NoError(t, e.Setup(), "e.Setup()") assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: fct.Target}), "e.Run(target)") @@ -550,11 +552,11 @@ func TestStatusVariables(t *testing.T) { func TestInit(t *testing.T) { const dir = "testdata/init" - var file = filepath.Join(dir, "Taskfile.yml") + var file = filepath.Join(dir, "Taskfile.yaml") _ = os.Remove(file) if _, err := os.Stat(file); err == nil { - t.Errorf("Taskfile.yml should not exist") + t.Errorf("Taskfile.yaml should not exist") } if err := task.InitTaskfile(io.Discard, dir); err != nil { @@ -562,8 +564,9 @@ func TestInit(t *testing.T) { } if _, err := os.Stat(file); err != nil { - t.Errorf("Taskfile.yml should exist") + t.Errorf("Taskfile.yaml should exist") } + _ = os.Remove(file) } func TestCyclicDep(t *testing.T) { @@ -790,6 +793,21 @@ func TestIncludesOptionalExplicitFalse(t *testing.T) { assert.Equal(t, "stat testdata/includes_optional_explicit_false/TaskfileOptional.yml: no such file or directory", err.Error()) } +func TestIncludesFromCustomTaskfile(t *testing.T) { + tt := fileContentTest{ + Dir: "testdata/includes_yaml", + Entrypoint: "Custom.ext", + Target: "default", + TrimSpace: true, + Files: map[string]string{ + "main.txt": "main", + "included_with_yaml_extension.txt": "included_with_yaml_extension", + "included_with_custom_file.txt": "included_with_custom_file", + }, + } + tt.Run(t) +} + func TestSummary(t *testing.T) { const dir = "testdata/summary" diff --git a/taskfile/read/taskfile.go b/taskfile/read/taskfile.go index 5ca194a3..ec7a3ab9 100644 --- a/taskfile/read/taskfile.go +++ b/taskfile/read/taskfile.go @@ -19,14 +19,26 @@ var ( ErrIncludedTaskfilesCantHaveIncludes = errors.New("task: Included Taskfiles can't have includes. Please, move the include to the main Taskfile") // ErrIncludedTaskfilesCantHaveDotenvs is returned when a included Taskfile contains dotenvs ErrIncludedTaskfilesCantHaveDotenvs = errors.New("task: Included Taskfiles can't have dotenv declarations. Please, move the dotenv declaration to the main Taskfile") + + defaultTaskfiles = []string{"Taskfile.yml", "Taskfile.yaml"} ) // Taskfile reads a Taskfile for a given directory +// Uses current dir when dir is left empty. Uses Taskfile.yml +// or Taskfile.yaml when entrypoint is left empty func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) { - path := filepath.Join(dir, entrypoint) - if _, err := os.Stat(path); err != nil { - return nil, fmt.Errorf(`task: No Taskfile found on "%s". Use "task --init" to create a new one`, path) + if dir == "" { + d, err := os.Getwd() + if err != nil { + return nil, err + } + dir = d } + path, err := exists(filepath.Join(dir, entrypoint)) + if err != nil { + return nil, err + } + t, err := readTaskfile(path) if err != nil { return nil, err @@ -59,16 +71,14 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) { path = filepath.Join(dir, path) } - info, err := os.Stat(path) + path, err = exists(path) if err != nil { if includedTask.Optional { return nil } return err } - if info.IsDir() { - path = filepath.Join(path, "Taskfile.yml") - } + includedTaskfile, err := readTaskfile(path) if err != nil { return err @@ -141,3 +151,22 @@ func readTaskfile(file string) (*taskfile.Taskfile, error) { var t taskfile.Taskfile return &t, yaml.NewDecoder(f).Decode(&t) } + +func exists(path string) (string, error) { + fi, err := os.Stat(path) + if err != nil { + return "", err + } + if fi.Mode().IsRegular() { + return path, nil + } + + for _, n := range defaultTaskfiles { + fpath := filepath.Join(path, n) + if _, err := os.Stat(fpath); err == nil { + return fpath, nil + } + } + + return "", fmt.Errorf(`task: No Taskfile found in "%s". Use "task --init" to create a new one`, path) +} diff --git a/testdata/includes_yaml/.gitignore b/testdata/includes_yaml/.gitignore new file mode 100644 index 00000000..2211df63 --- /dev/null +++ b/testdata/includes_yaml/.gitignore @@ -0,0 +1 @@ +*.txt diff --git a/testdata/includes_yaml/Custom.ext b/testdata/includes_yaml/Custom.ext new file mode 100644 index 00000000..5264ca1e --- /dev/null +++ b/testdata/includes_yaml/Custom.ext @@ -0,0 +1,16 @@ +version: '3' + +includes: + included: ./included + custom: ./included/custom.yaml + +tasks: + default: + cmds: + - task: gen + - task: included:gen + - task: custom:gen + + gen: + cmds: + - echo main > main.txt diff --git a/testdata/includes_yaml/included/Taskfile.yaml b/testdata/includes_yaml/included/Taskfile.yaml new file mode 100644 index 00000000..6e3f4962 --- /dev/null +++ b/testdata/includes_yaml/included/Taskfile.yaml @@ -0,0 +1,6 @@ +version: '3' + +tasks: + gen: + cmds: + - echo included_with_yaml_extension > included_with_yaml_extension.txt diff --git a/testdata/includes_yaml/included/custom.yaml b/testdata/includes_yaml/included/custom.yaml new file mode 100644 index 00000000..f72e199f --- /dev/null +++ b/testdata/includes_yaml/included/custom.yaml @@ -0,0 +1,6 @@ +version: '3' + +tasks: + gen: + cmds: + - echo included_with_custom_file > included_with_custom_file.txt