diff --git a/taskfile/read/taskfile.go b/taskfile/read/taskfile.go index b97d21ab..6bd8a005 100644 --- a/taskfile/read/taskfile.go +++ b/taskfile/read/taskfile.go @@ -77,29 +77,18 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) { path = filepath.Join(readerNode.Dir, path) } - // check for cyclic include references by walking up - // node tree of parents and comparing paths - var curNode = readerNode - for curNode.Parent != nil { - curNode = curNode.Parent - curPath := filepath.Join(curNode.Dir, curNode.Entrypoint) - if curPath == path { - return fmt.Errorf("include cycle detected between %s <--> %s", - curPath, - filepath.Join(readerNode.Dir, readerNode.Entrypoint), - ) - } - } - - // if we made it here then there is no cyclic include - readOpts := &ReaderNode{ + includeReaderNode := &ReaderNode{ Dir: filepath.Dir(path), Entrypoint: filepath.Base(path), Parent: readerNode, Optional: includedTask.Optional, } - includedTaskfile, err := Taskfile(readOpts) + if err := checkCircularIncludes(includeReaderNode); err != nil { + return err + } + + includedTaskfile, err := Taskfile(includeReaderNode) if err != nil { if includedTask.Optional { return nil @@ -190,3 +179,25 @@ func exists(path string) (string, error) { return "", fmt.Errorf(`task: No Taskfile found in "%s". Use "task --init" to create a new one`, path) } + +func checkCircularIncludes(node *ReaderNode) error { + if node == nil { + return errors.New("failed to check for include cycle: node was nil") + } + if node.Parent == nil { + return errors.New("failed to check for include cycle: node.Parent was nil") + } + var curNode = node + var basePath = filepath.Join(node.Dir, node.Entrypoint) + for curNode.Parent != nil { + curNode = curNode.Parent + curPath := filepath.Join(curNode.Dir, curNode.Entrypoint) + if curPath == basePath { + return fmt.Errorf("include cycle detected between %s <--> %s", + curPath, + filepath.Join(node.Parent.Dir, node.Parent.Entrypoint), + ) + } + } + return nil +} diff --git a/testdata/includes_multi_level/Taskfile.yml b/testdata/includes_multi_level/Taskfile.yml index 56748cd7..a2a6aea5 100644 --- a/testdata/includes_multi_level/Taskfile.yml +++ b/testdata/includes_multi_level/Taskfile.yml @@ -6,7 +6,4 @@ includes: tasks: default: cmds: - - echo "called_dep" > called_dep.txt - level1: - cmds: - - echo "hello level 1" \ No newline at end of file + - task: one:two:default \ No newline at end of file diff --git a/testdata/includes_multi_level/one/Taskfile.yml b/testdata/includes_multi_level/one/Taskfile.yml index a948df55..34d26381 100644 --- a/testdata/includes_multi_level/one/Taskfile.yml +++ b/testdata/includes_multi_level/one/Taskfile.yml @@ -4,6 +4,6 @@ includes: 'two': ./two/Taskfile.yml tasks: - level2: + level1: cmds: - - echo "hello level 2" \ No newline at end of file + - echo "hello level 1" \ No newline at end of file diff --git a/testdata/includes_multi_level/one/two/Taskfile.yml b/testdata/includes_multi_level/one/two/Taskfile.yml index 738fa5ae..d12ab6be 100644 --- a/testdata/includes_multi_level/one/two/Taskfile.yml +++ b/testdata/includes_multi_level/one/two/Taskfile.yml @@ -1,6 +1,6 @@ version: '3' tasks: - level3: + default: cmds: - - echo "hello level 3" \ No newline at end of file + - echo "called_dep" > called_dep.txt \ No newline at end of file