Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions errors/errors_taskfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,15 @@ import (
// TaskfileNotFoundError is returned when no appropriate Taskfile is found when
// searching the filesystem.
type TaskfileNotFoundError struct {
URI string
Walk bool
AskInit bool
URI string
Walk bool
}

func (err TaskfileNotFoundError) Error() string {
var walkText string
if err.Walk {
walkText = " (or any of the parent directories)."
}
if err.AskInit {
walkText += " Run `task --init` to create a new Taskfile."
}
return fmt.Sprintf(`task: No Taskfile found at %q%s`, err.URI, walkText)
}

Expand Down
18 changes: 18 additions & 0 deletions internal/fsext/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ func ResolveDir(entrypoint, resolvedEntrypoint, dir string) (string, error) {
return filepath.Dir(resolvedEntrypoint), nil
}

// GetSearchPath returns the absolute path to search for the entrypoint. If the
// entrypoint is set, it returns the absolute path to the entrypoint. If the dir
// is set, it returns the absolute path to the dir. If both are empty, it returns
// the current working directory.
func GetSearchPath(entrypoint, dir string) (string, error) {
if entrypoint != "" {
return filepath.Abs(entrypoint)
}
if dir != "" {
return filepath.Abs(dir)
}
wd, err := os.Getwd()
if err != nil {
return "", err
}
return wd, nil
}

// Search looks for files with the given possible filenames using the given
// entrypoint and directory. If the entrypoint is set, it checks if the
// entrypoint matches a file or if it matches a directory containing one of the
Expand Down
72 changes: 72 additions & 0 deletions internal/fsext/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,78 @@ func TestDefaultDir(t *testing.T) {
}
}

func TestGetSearchPath(t *testing.T) {
t.Parallel()

wd, err := os.Getwd()
require.NoError(t, err)

tests := []struct {
name string
entrypoint string
dir string
expectedPath string
}{
{
name: "return absolute entrypoint if only absolute entrypoint is set",
entrypoint: "/dir/to/Taskfile.yml",
dir: "",
expectedPath: "/dir/to/Taskfile.yml",
},
{
name: "return absolute path of entrypoint if only relative entrypoint is set",
entrypoint: "./dir/to/Taskfile.yml",
dir: "",
expectedPath: filepath.Join(wd, "dir", "to", "Taskfile.yml"),
},
{
name: "return absolute dir if only absolute dir is set",
entrypoint: "",
dir: "/dir/to",
expectedPath: "/dir/to",
},
{
name: "return absolute path of dir if only relative dir is set",
entrypoint: "",
dir: "./dir/to",
expectedPath: filepath.Join(wd, "dir", "to"),
},
{
name: "return absolute entrypoint if both absolute entrypoint and dir are set",
entrypoint: "/dir/to/another/Taskfile.yml",
dir: "/dir/to",
expectedPath: "/dir/to/another/Taskfile.yml",
},
{
name: "return absolute path of entrypoint if both relative entrypoint and dir are set",
entrypoint: "./dir/to/another/Taskfile.yml",
dir: "./dir/to",
expectedPath: filepath.Join(wd, "dir", "to", "another", "Taskfile.yml"),
},
{
name: "return absolute path of entrypoint if relative entrypoint and absolute dir are set",
entrypoint: "./dir/to/another/Taskfile.yml",
dir: "/dir/to",
expectedPath: filepath.Join(wd, "dir", "to", "another", "Taskfile.yml"),
},
{
name: "return working directory if both are empty",
entrypoint: "",
dir: "",
expectedPath: wd,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

path, err := GetSearchPath(tt.entrypoint, tt.dir)
require.NoError(t, err)
require.Equal(t, tt.expectedPath, path)
})
}
}

func TestSearch(t *testing.T) {
t.Parallel()

Expand Down
14 changes: 5 additions & 9 deletions setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/go-task/task/v3/internal/env"
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/filepathext"
"github.com/go-task/task/v3/internal/fsext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/output"
"github.com/go-task/task/v3/internal/version"
Expand Down Expand Up @@ -56,18 +55,15 @@ func (e *Executor) Setup() error {

func (e *Executor) getRootNode() (taskfile.Node, error) {
node, err := taskfile.NewRootNode(e.Entrypoint, e.Dir, e.Insecure, e.Timeout)
if os.IsNotExist(err) {
return nil, errors.TaskfileNotFoundError{
URI: fsext.DefaultDir(e.Entrypoint, e.Dir),
Walk: true,
AskInit: true,
}
}
if err != nil {
// if the error is a TaskfileNotFoundError and no entrypoint or dir is set, we can suggest to run `task --init`
if errors.As(err, &errors.TaskfileNotFoundError{}) && e.Entrypoint == "" && e.Dir == "" {
return nil, fmt.Errorf("%w. Run `task --init` to create a new Taskfile", err)
}
return nil, err
}
e.Dir = node.Dir()
return node, err
return node, nil
}

func (e *Executor) readTaskfile(node taskfile.Node) error {
Expand Down
13 changes: 10 additions & 3 deletions taskfile/node_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@ type FileNode struct {
func NewFileNode(entrypoint, dir string, opts ...NodeOption) (*FileNode, error) {
// Find the entrypoint file
resolvedEntrypoint, err := fsext.Search(entrypoint, dir, DefaultTaskfiles)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, errors.TaskfileNotFoundError{URI: entrypoint, Walk: false}
if errors.Is(err, os.ErrNotExist) {
path, err := fsext.GetSearchPath(entrypoint, dir)
if err != nil {
return nil, err
}
return nil, errors.TaskfileNotFoundError{
URI: path,
Walk: entrypoint == "",
}
}
if err != nil {
return nil, err
}

Expand Down