1
0
mirror of https://github.com/go-task/task.git synced 2025-01-20 04:59:37 +02:00

feat: support looping over map variables (#1436)

* feat: support looping over map variables

* feat: add .KEY variable
This commit is contained in:
Pete Davison 2023-12-21 09:43:56 -06:00 committed by GitHub
parent 658b6012a6
commit b592648d55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 8 deletions

View File

@ -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
@ -86,8 +85,8 @@ tasks:
cmd: echo {{.ITEM}}
```
Because this experiment adds support for array variables, the `for` keyword has
been updated to support looping over arrays directly:
Because this experiment adds support for "collection-type" variables, the `for`
keyword has been updated to support looping over arrays directly:
```yaml
version: 3
@ -102,6 +101,30 @@ tasks:
cmd: echo {{.ITEM}}
```
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
tasks:
foo:
vars:
MAP:
KEY_1:
SUBKEY: sub_value_1
KEY_2:
SUBKEY: sub_value_2
KEY_3:
SUBKEY: sub_value_3
cmds:
- for:
var: MAP
cmd: echo {{.KEY}} {{.ITEM.SUBKEY}}
```
String splitting is still supported and remember that for simple cases, you have
always been able to loop over an array without using variables at all:

View File

@ -9,6 +9,8 @@ tasks:
- task: string-array
- task: for-string
- task: for-int
- task: for-map
- task: for-multi-layer-map
dynamic:
vars:
@ -78,3 +80,27 @@ tasks:
var: LIST
cmd: echo {{add .ITEM 100}}
for-map:
vars:
MAP:
KEY_1: value_1
KEY_2: value_2
KEY_3: value_3
cmds:
- for:
var: MAP
cmd: echo {{.KEY}} {{.ITEM}}
for-multi-layer-map:
vars:
MAP:
KEY_1:
SUBKEY: sub_value_1
KEY_2:
SUBKEY: sub_value_2
KEY_3:
SUBKEY: sub_value_3
cmds:
- for:
var: MAP
cmd: echo {{.KEY}} {{.ITEM.SUBKEY}}

View File

@ -133,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 {
@ -170,9 +171,9 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
case []any:
list = value
case map[string]any:
return &taskfile.Task{}, errors.TaskfileInvalidError{
URI: origTask.Location.Taskfile,
Err: errors.New("sh is not supported with the 'Any Variables' experiment enabled.\nSee https://taskfile.dev/experiments/any-variables for more information."),
for k, v := range value {
keys = append(keys, k)
list = append(list, v)
}
default:
return nil, errors.TaskfileInvalidError{
@ -191,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),