feat: recursive config search (#2166)

* refactor: experiments flags

* refactor: args.Parse

* feat: recursive search for taskrc files

* feat: consolidate some code into new fsext package

* feat: add tests for search and default dir

* fix: linting issues
This commit is contained in:
Pete Davison
2025-04-19 12:20:33 +01:00
committed by GitHub
parent 1ae3bf0b25
commit c5afffb551
20 changed files with 616 additions and 233 deletions

8
taskrc/ast/taskrc.go Normal file
View File

@@ -0,0 +1,8 @@
package ast
import "github.com/Masterminds/semver/v3"
type TaskRC struct {
Version *semver.Version `yaml:"version"`
Experiments map[string]int `yaml:"experiments"`
}

24
taskrc/node.go Normal file
View File

@@ -0,0 +1,24 @@
package taskrc
import "github.com/go-task/task/v3/internal/fsext"
type Node struct {
entrypoint string
dir string
}
func NewNode(
entrypoint string,
dir string,
) (*Node, error) {
dir = fsext.DefaultDir(entrypoint, dir)
var err error
entrypoint, dir, err = fsext.Search(entrypoint, dir, defaultTaskRCs)
if err != nil {
return nil, err
}
return &Node{
entrypoint: entrypoint,
dir: dir,
}, nil
}

79
taskrc/reader.go Normal file
View File

@@ -0,0 +1,79 @@
package taskrc
import (
"os"
"gopkg.in/yaml.v3"
"github.com/go-task/task/v3/taskrc/ast"
)
type (
// DebugFunc is a function that can be called to log debug messages.
DebugFunc func(string)
// A ReaderOption is any type that can apply a configuration to a [Reader].
ReaderOption interface {
ApplyToReader(*Reader)
}
// A Reader will recursively read Taskfiles from a given [Node] and build a
// [ast.TaskRC] from them.
Reader struct {
debugFunc DebugFunc
}
)
// NewReader constructs a new Taskfile [Reader] using the given Node and
// options.
func NewReader(opts ...ReaderOption) *Reader {
r := &Reader{
debugFunc: nil,
}
r.Options(opts...)
return r
}
// Options loops through the given [ReaderOption] functions and applies them to
// the [Reader].
func (r *Reader) Options(opts ...ReaderOption) {
for _, opt := range opts {
opt.ApplyToReader(r)
}
}
// WithDebugFunc sets the debug function to be used by the [Reader]. If set,
// this function will be called with debug messages. This can be useful if the
// caller wants to log debug messages from the [Reader]. By default, no debug
// function is set and the logs are not written.
func WithDebugFunc(debugFunc DebugFunc) ReaderOption {
return &debugFuncOption{debugFunc: debugFunc}
}
type debugFuncOption struct {
debugFunc DebugFunc
}
func (o *debugFuncOption) ApplyToReader(r *Reader) {
r.debugFunc = o.debugFunc
}
// Read will read the Task config defined by the [Reader]'s [Node].
func (r *Reader) Read(node *Node) (*ast.TaskRC, error) {
var config ast.TaskRC
if node == nil {
return nil, os.ErrInvalid
}
// Read the file
b, err := os.ReadFile(node.entrypoint)
if err != nil {
return nil, err
}
// Parse the content
if err := yaml.Unmarshal(b, &config); err != nil {
return nil, err
}
return &config, nil
}

6
taskrc/taskrc.go Normal file
View File

@@ -0,0 +1,6 @@
package taskrc
var defaultTaskRCs = []string{
".taskrc.yml",
".taskrc.yaml",
}