mirror of
https://github.com/go-task/task.git
synced 2025-08-08 22:36:57 +02:00
feat: support looping over map variables (#1436)
* feat: support looping over map variables * feat: add .KEY variable
This commit is contained in:
@@ -63,8 +63,7 @@ tasks:
|
|||||||
```
|
```
|
||||||
|
|
||||||
There are many more templating functions which can be used with the new types of
|
There are many more templating functions which can be used with the new types of
|
||||||
variables. For a full list, see the
|
variables. For a full list, see the [slim-sprig][slim-sprig] documentation.
|
||||||
[slim-sprig][slim-sprig] documentation.
|
|
||||||
|
|
||||||
## Looping over variables
|
## Looping over variables
|
||||||
|
|
||||||
@@ -86,8 +85,8 @@ tasks:
|
|||||||
cmd: echo {{.ITEM}}
|
cmd: echo {{.ITEM}}
|
||||||
```
|
```
|
||||||
|
|
||||||
Because this experiment adds support for array variables, the `for` keyword has
|
Because this experiment adds support for "collection-type" variables, the `for`
|
||||||
been updated to support looping over arrays directly:
|
keyword has been updated to support looping over arrays directly:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: 3
|
version: 3
|
||||||
@@ -102,6 +101,30 @@ tasks:
|
|||||||
cmd: echo {{.ITEM}}
|
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
|
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:
|
always been able to loop over an array without using variables at all:
|
||||||
|
|
||||||
|
26
testdata/vars/any/Taskfile.yml
vendored
26
testdata/vars/any/Taskfile.yml
vendored
@@ -9,6 +9,8 @@ tasks:
|
|||||||
- task: string-array
|
- task: string-array
|
||||||
- task: for-string
|
- task: for-string
|
||||||
- task: for-int
|
- task: for-int
|
||||||
|
- task: for-map
|
||||||
|
- task: for-multi-layer-map
|
||||||
|
|
||||||
dynamic:
|
dynamic:
|
||||||
vars:
|
vars:
|
||||||
@@ -78,3 +80,27 @@ tasks:
|
|||||||
var: LIST
|
var: LIST
|
||||||
cmd: echo {{add .ITEM 100}}
|
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}}
|
||||||
|
12
variables.go
12
variables.go
@@ -133,6 +133,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cmd.For != nil {
|
if cmd.For != nil {
|
||||||
|
var keys []string
|
||||||
var list []any
|
var list []any
|
||||||
// Get the list from the explicit for list
|
// Get the list from the explicit for list
|
||||||
if cmd.For.List != nil && len(cmd.For.List) > 0 {
|
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:
|
case []any:
|
||||||
list = value
|
list = value
|
||||||
case map[string]any:
|
case map[string]any:
|
||||||
return &taskfile.Task{}, errors.TaskfileInvalidError{
|
for k, v := range value {
|
||||||
URI: origTask.Location.Taskfile,
|
keys = append(keys, k)
|
||||||
Err: errors.New("sh is not supported with the 'Any Variables' experiment enabled.\nSee https://taskfile.dev/experiments/any-variables for more information."),
|
list = append(list, v)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, errors.TaskfileInvalidError{
|
return nil, errors.TaskfileInvalidError{
|
||||||
@@ -191,10 +192,13 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
|||||||
as = "ITEM"
|
as = "ITEM"
|
||||||
}
|
}
|
||||||
// Create a new command for each item in the list
|
// Create a new command for each item in the list
|
||||||
for _, loopValue := range list {
|
for i, loopValue := range list {
|
||||||
extra := map[string]any{
|
extra := map[string]any{
|
||||||
as: loopValue,
|
as: loopValue,
|
||||||
}
|
}
|
||||||
|
if len(keys) > 0 {
|
||||||
|
extra["KEY"] = keys[i]
|
||||||
|
}
|
||||||
new.Cmds = append(new.Cmds, &taskfile.Cmd{
|
new.Cmds = append(new.Cmds, &taskfile.Cmd{
|
||||||
Cmd: r.ReplaceWithExtra(cmd.Cmd, extra),
|
Cmd: r.ReplaceWithExtra(cmd.Cmd, extra),
|
||||||
Task: r.ReplaceWithExtra(cmd.Task, extra),
|
Task: r.ReplaceWithExtra(cmd.Task, extra),
|
||||||
|
Reference in New Issue
Block a user