diff --git a/internal/compiler/compiler.go b/internal/compiler/compiler.go index 5c52d60e..ee7c4adb 100644 --- a/internal/compiler/compiler.go +++ b/internal/compiler/compiler.go @@ -3,10 +3,13 @@ package compiler import ( "bytes" "context" + "encoding/json" "fmt" "strings" "sync" + "gopkg.in/yaml.v3" + "github.com/go-task/task/v3/internal/execext" "github.com/go-task/task/v3/internal/filepathext" "github.com/go-task/task/v3/internal/logger" @@ -64,6 +67,8 @@ func (c *Compiler) getVariables(t *ast.Task, call *ast.Call, evaluateShVars bool newVar.Value = value } newVar.Sh = tr.Replace(v.Sh) + newVar.Json = tr.Replace(v.Json) + newVar.Yaml = tr.Replace(v.Yaml) newVar.Dir = v.Dir // If the variable should not be evaluated, but is nil, set it to an empty string // This stops empty interface errors when using the templater to replace values later @@ -80,6 +85,18 @@ func (c *Compiler) getVariables(t *ast.Task, call *ast.Call, evaluateShVars bool if err := tr.Err(); err != nil { return err } + // Evaluate JSON + if newVar.Json != "" { + if err := json.Unmarshal([]byte(newVar.Json), &newVar.Value); err != nil { + return err + } + } + // Evaluate YAML + if newVar.Yaml != "" { + if err := yaml.Unmarshal([]byte(newVar.Yaml), &newVar.Value); err != nil { + return err + } + } // If the variable is not dynamic, we can set it and return if newVar.Value != nil || newVar.Sh == "" { result.Set(k, ast.Var{Value: newVar.Value}) diff --git a/taskfile/ast/var.go b/taskfile/ast/var.go index ea1aeaa0..69613fb0 100644 --- a/taskfile/ast/var.go +++ b/taskfile/ast/var.go @@ -76,6 +76,8 @@ type Var struct { Value any Live any Sh string + Json string + Yaml string Dir string } @@ -105,19 +107,23 @@ func (v *Var) UnmarshalYAML(node *yaml.Node) error { case yaml.MappingNode: key := node.Content[0].Value switch key { - case "sh", "map": + case "sh", "map", "json", "yaml": var m struct { - Sh string - Map any + Sh string + Map any + Json string + Yaml string } if err := node.Decode(&m); err != nil { return err } v.Sh = m.Sh v.Value = m.Map + v.Json = m.Json + v.Yaml = m.Yaml return nil default: - return fmt.Errorf(`yaml: line %d: %q is not a valid variable type. Try "sh", "map" or using a scalar value`, node.Line, key) + return fmt.Errorf(`yaml: line %d: %q is not a valid variable type. Try "sh", "map", "json", "yaml" or using a scalar value`, node.Line, key) } default: var value any diff --git a/testdata/vars/any2/Taskfile.yml b/testdata/vars/any2/Taskfile.yml index 547a627d..2d6769ea 100644 --- a/testdata/vars/any2/Taskfile.yml +++ b/testdata/vars/any2/Taskfile.yml @@ -19,3 +19,35 @@ tasks: {{- else}} and {{$child.name -}} {{- end -}} {{- end -}}" + + json: + vars: + JSON_STRING: + sh: cat example.json + JSON: + json: "{{.JSON_STRING}}" + cmds: + - >- + echo "{{.JSON.name}} has {{len .JSON.children}} children called + {{- $children := .JSON.children -}} + {{- range $i, $child := $children -}} + {{- if lt $i (sub (len $children) 1)}} {{$child.name -}}, + {{- else}} and {{$child.name -}} + {{- end -}} + {{- end -}}" + + yaml: + vars: + YAML_STRING: + sh: cat example.yaml + YAML: + yaml: "{{.YAML_STRING}}" + cmds: + - >- + echo "{{.YAML.name}} has {{len .YAML.children}} children called + {{- $children := .YAML.children -}} + {{- range $i, $child := $children -}} + {{- if lt $i (sub (len $children) 1)}} {{$child.name -}}, + {{- else}} and {{$child.name -}} + {{- end -}} + {{- end -}}" diff --git a/testdata/vars/any2/example.json b/testdata/vars/any2/example.json new file mode 100644 index 00000000..0d671527 --- /dev/null +++ b/testdata/vars/any2/example.json @@ -0,0 +1,18 @@ +{ + "name": "Alice", + "age": 30, + "children": [ + { + "name": "Bob", + "age": 5 + }, + { + "name": "Charlie", + "age": 3 + }, + { + "name": "Diane", + "age": 1 + } + ] +} diff --git a/testdata/vars/any2/example.yaml b/testdata/vars/any2/example.yaml new file mode 100644 index 00000000..368fca61 --- /dev/null +++ b/testdata/vars/any2/example.yaml @@ -0,0 +1,9 @@ +name: Alice +age: 30 +children: + - name: Bob + age: 5 + - name: Charlie + age: 3 + - name: Diane + age: 1