1
0
mirror of https://github.com/go-task/task.git synced 2025-01-06 03:53:54 +02:00

Evaluate included taskfiles in order of declaration

Closes #393
This commit is contained in:
Andrey Nering 2021-01-01 18:27:50 -03:00
parent 22fd74846d
commit 9674d75ff6
7 changed files with 104 additions and 28 deletions

View File

@ -176,7 +176,7 @@ func (e *Executor) Setup() error {
if v < 2.1 && e.Taskfile.Output != "" {
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
}
if v < 2.2 && len(e.Taskfile.Includes) > 0 {
if v < 2.2 && e.Taskfile.Includes.Len() > 0 {
return fmt.Errorf(`task: Including Taskfiles is only available starting on Taskfile version v2.2`)
}
if v >= 3.0 && e.Taskfile.Expansions > 2 {
@ -229,10 +229,14 @@ func (e *Executor) Setup() error {
}
if v < 3 {
for _, taskfile := range e.Taskfile.Includes {
err := e.Taskfile.Includes.Range(func(_ string, taskfile taskfile.IncludedTaskfile) error {
if taskfile.AdvancedImport {
return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`)
}
return nil
})
if err != nil {
return err
}
}

View File

@ -1,6 +1,10 @@
package taskfile
import "errors"
import (
"errors"
"gopkg.in/yaml.v3"
)
var (
// ErrCantUnmarshalIncludedTaskfile is returned for invalid var YAML.
@ -15,7 +19,72 @@ type IncludedTaskfile struct {
}
// IncludedTaskfiles represents information about included tasksfiles
type IncludedTaskfiles = map[string]IncludedTaskfile
type IncludedTaskfiles struct {
Keys []string
Mapping map[string]IncludedTaskfile
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (tfs *IncludedTaskfiles) UnmarshalYAML(node *yaml.Node) error {
if node.Kind != yaml.MappingNode {
return errors.New("task: includes is not a map")
}
// NOTE(@andreynering): on this style of custom unmarsheling,
// even number contains the keys, while odd numbers contains
// the values.
for i := 0; i < len(node.Content); i += 2 {
keyNode := node.Content[i]
valueNode := node.Content[i+1]
var v IncludedTaskfile
if err := valueNode.Decode(&v); err != nil {
return err
}
tfs.Set(keyNode.Value, v)
}
return nil
}
// Len returns the length of the map
func (tfs *IncludedTaskfiles) Len() int {
if tfs == nil {
return 0
}
return len(tfs.Keys)
}
// Merge merges the given IncludedTaskfiles into the caller one
func (tfs *IncludedTaskfiles) Merge(other *IncludedTaskfiles) {
other.Range(func(key string, value IncludedTaskfile) error {
tfs.Set(key, value)
return nil
})
}
// Set sets a value to a given key
func (tfs *IncludedTaskfiles) Set(key string, includedTaskfile IncludedTaskfile) {
if tfs.Mapping == nil {
tfs.Mapping = make(map[string]IncludedTaskfile, 1)
}
if !stringSliceContains(tfs.Keys, key) {
tfs.Keys = append(tfs.Keys, key)
}
tfs.Mapping[key] = includedTaskfile
}
// Range allows you to loop into the included taskfiles in its right order
func (tfs *IncludedTaskfiles) Range(yield func(key string, includedTaskfile IncludedTaskfile) error) error {
if tfs == nil {
return nil
}
for _, k := range tfs.Keys {
if err := yield(k, tfs.Mapping[k]); err != nil {
return err
}
}
return nil
}
// UnmarshalYAML implements yaml.Unmarshaler interface
func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {

View File

@ -22,11 +22,9 @@ func Merge(t1, t2 *Taskfile, namespaces ...string) error {
}
if t1.Includes == nil {
t1.Includes = make(IncludedTaskfiles)
}
for k, v := range t2.Includes {
t1.Includes[k] = v
t1.Includes = &IncludedTaskfiles{}
}
t1.Includes.Merge(t2.Includes)
if t1.Vars == nil {
t1.Vars = &Vars{}

View File

@ -58,7 +58,7 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
}
}
for namespace, includedTask := range t.Includes {
err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error {
if v >= 3.0 {
tr := templater.Templater{Vars: &taskfile.Vars{}, RemoveNoValue: true}
includedTask = taskfile.IncludedTaskfile{
@ -67,7 +67,7 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
AdvancedImport: includedTask.AdvancedImport,
}
if err := tr.Err(); err != nil {
return nil, err
return err
}
}
@ -79,21 +79,21 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
info, err := os.Stat(path)
if err != nil {
return nil, err
return err
}
if info.IsDir() {
path = filepath.Join(path, "Taskfile.yml")
}
includedTaskfile, err := readTaskfile(path)
if err != nil {
return nil, err
return err
}
if len(includedTaskfile.Includes) > 0 {
return nil, ErrIncludedTaskfilesCantHaveIncludes
if includedTaskfile.Includes.Len() > 0 {
return ErrIncludedTaskfilesCantHaveIncludes
}
if v >= 3.0 && len(includedTaskfile.Dotenv) > 0 {
return nil, ErrIncludedTaskfilesCantHaveDotenvs
return ErrIncludedTaskfilesCantHaveDotenvs
}
if includedTask.AdvancedImport {
@ -105,8 +105,12 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
}
if err = taskfile.Merge(t, includedTaskfile, namespace); err != nil {
return nil, err
return err
}
return nil
})
if err != nil {
return nil, err
}
if v < 3.0 {

10
taskfile/slice.go Normal file
View File

@ -0,0 +1,10 @@
package taskfile
func stringSliceContains(s []string, str string) bool {
for _, v := range s {
if v == str {
return true
}
}
return false
}

View File

@ -11,7 +11,7 @@ type Taskfile struct {
Expansions int
Output string
Method string
Includes IncludedTaskfiles
Includes *IncludedTaskfiles
Vars *Vars
Env *Vars
Tasks Tasks
@ -26,7 +26,7 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
Expansions int
Output string
Method string
Includes IncludedTaskfiles
Includes *IncludedTaskfiles
Vars *Vars
Env *Vars
Tasks Tasks

View File

@ -53,21 +53,12 @@ func (vs *Vars) Set(key string, value Var) {
if vs.Mapping == nil {
vs.Mapping = make(map[string]Var, 1)
}
if !strSliceContains(vs.Keys, key) {
if !stringSliceContains(vs.Keys, key) {
vs.Keys = append(vs.Keys, key)
}
vs.Mapping[key] = value
}
func strSliceContains(s []string, str string) bool {
for _, v := range s {
if v == str {
return true
}
}
return false
}
// Range allows you to loop into the vars in its right order
func (vs *Vars) Range(yield func(key string, value Var) error) error {
if vs == nil {