From 2ccf80713d41b412fe94e894dc0b90900dec1cd4 Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Sat, 23 Dec 2023 04:59:10 +0000 Subject: [PATCH] feat: add sh and map (value) support --- internal/experiments/experiments.go | 2 +- taskfile/ast/var.go | 52 ++++++++++++++++++++++++----- testdata/vars/any2/Taskfile.yml | 21 ++++++++++++ 3 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 testdata/vars/any2/Taskfile.yml diff --git a/internal/experiments/experiments.go b/internal/experiments/experiments.go index d88fcb6b..2ef2d581 100644 --- a/internal/experiments/experiments.go +++ b/internal/experiments/experiments.go @@ -32,7 +32,7 @@ func init() { readDotEnv() GentleForce = New("GENTLE_FORCE") RemoteTaskfiles = New("REMOTE_TASKFILES") - AnyVariables = New("ANY_VARIABLES") + AnyVariables = New("ANY_VARIABLES", "1", "2") } func New(xName string, enabledValues ...string) Experiment { diff --git a/taskfile/ast/var.go b/taskfile/ast/var.go index 69a494ef..ea1aeaa0 100644 --- a/taskfile/ast/var.go +++ b/taskfile/ast/var.go @@ -81,19 +81,53 @@ type Var struct { func (v *Var) UnmarshalYAML(node *yaml.Node) error { if experiments.AnyVariables.Enabled { - var value any - if err := node.Decode(&value); err != nil { - return err + + // This implementation is not backwards-compatible and replaces the 'sh' key with map variables + if experiments.AnyVariables.Value == "1" { + var value any + if err := node.Decode(&value); err != nil { + return err + } + // If the value is a string and it starts with $, then it's a shell command + if str, ok := value.(string); ok { + if str, ok = strings.CutPrefix(str, "$"); ok { + v.Sh = str + return nil + } + } + v.Value = value + return nil } - // If the value is a string and it starts with $, then it's a shell command - if str, ok := value.(string); ok { - if str, ok = strings.CutPrefix(str, "$"); ok { - v.Sh = str + + // This implementation IS backwards-compatible and keeps the 'sh' key and allows map variables to be added under the `map` key + if experiments.AnyVariables.Value == "2" { + switch node.Kind { + case yaml.MappingNode: + key := node.Content[0].Value + switch key { + case "sh", "map": + var m struct { + Sh string + Map any + } + if err := node.Decode(&m); err != nil { + return err + } + v.Sh = m.Sh + v.Value = m.Map + 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) + } + default: + var value any + if err := node.Decode(&value); err != nil { + return err + } + v.Value = value return nil } } - v.Value = value - return nil } switch node.Kind { diff --git a/testdata/vars/any2/Taskfile.yml b/testdata/vars/any2/Taskfile.yml new file mode 100644 index 00000000..547a627d --- /dev/null +++ b/testdata/vars/any2/Taskfile.yml @@ -0,0 +1,21 @@ +version: '3' + +tasks: + default: + - task: map + - task: json + - task: yaml + + map: + vars: + MAP: + map: {"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]} + cmds: + - >- + echo "{{.MAP.name}} has {{len .MAP.children}} children called + {{- $children := .MAP.children -}} + {{- range $i, $child := $children -}} + {{- if lt $i (sub (len $children) 1)}} {{$child.name -}}, + {{- else}} and {{$child.name -}} + {{- end -}} + {{- end -}}"