diff --git a/docs/docs/experiments/any_variables.md b/docs/docs/experiments/any_variables.md index d216bf4a8e..eb9c18193f 100644 --- a/docs/docs/experiments/any_variables.md +++ b/docs/docs/experiments/any_variables.md @@ -63,8 +63,7 @@ tasks: ``` There are many more templating functions which can be used with the new types of -variables. For a full list, see the -[slim-sprig][slim-sprig] documentation. +variables. For a full list, see the [slim-sprig][slim-sprig] documentation. ## Looping over variables @@ -102,8 +101,10 @@ tasks: cmd: echo {{.ITEM}} ``` -This also works for maps. However, remember that maps are unordered, so the -order in which the items are looped over is random: +This also works for maps. When looping over a map we also make an additional +`{{.KEY}}` variable availabe that holds the string value of the map key. +Remember that maps are unordered, so the order in which the items are looped +over is random: ```yaml version: 3 @@ -121,7 +122,7 @@ tasks: cmds: - for: var: MAP - cmd: echo {{.ITEM.SUBKEY}} + cmd: echo {{.KEY}} {{.ITEM.SUBKEY}} ``` String splitting is still supported and remember that for simple cases, you have diff --git a/testdata/vars/any/Taskfile.yml b/testdata/vars/any/Taskfile.yml index e4580f636d..285996348e 100644 --- a/testdata/vars/any/Taskfile.yml +++ b/testdata/vars/any/Taskfile.yml @@ -89,7 +89,7 @@ tasks: cmds: - for: var: MAP - cmd: echo {{.ITEM}} + cmd: echo {{.KEY}} {{.ITEM}} for-multi-layer-map: vars: @@ -103,4 +103,4 @@ tasks: cmds: - for: var: MAP - cmd: echo {{.ITEM.SUBKEY}} + cmd: echo {{.KEY}} {{.ITEM.SUBKEY}} diff --git a/variables.go b/variables.go index 1cbda2e70b..9e7a4b0d4a 100644 --- a/variables.go +++ b/variables.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/joho/godotenv" - "golang.org/x/exp/maps" "github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/internal/execext" @@ -134,6 +133,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf continue } if cmd.For != nil { + var keys []string var list []any // Get the list from the explicit for list if cmd.For.List != nil && len(cmd.For.List) > 0 { @@ -171,7 +171,10 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf case []any: list = value case map[string]any: - list = maps.Values(value) + for k, v := range value { + keys = append(keys, k) + list = append(list, v) + } default: return nil, errors.TaskfileInvalidError{ URI: origTask.Location.Taskfile, @@ -189,10 +192,13 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf as = "ITEM" } // Create a new command for each item in the list - for _, loopValue := range list { + for i, loopValue := range list { extra := map[string]any{ as: loopValue, } + if len(keys) > 0 { + extra["KEY"] = keys[i] + } new.Cmds = append(new.Cmds, &taskfile.Cmd{ Cmd: r.ReplaceWithExtra(cmd.Cmd, extra), Task: r.ReplaceWithExtra(cmd.Task, extra),