mirror of
https://github.com/go-task/task.git
synced 2025-06-04 23:38:05 +02:00
fix: matrix loops should be deterministic (#1784)
This commit is contained in:
parent
a3bdb6c40a
commit
e4b4d04abd
@ -5,12 +5,13 @@ import (
|
|||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
"github.com/go-task/task/v3/internal/deepcopy"
|
"github.com/go-task/task/v3/internal/deepcopy"
|
||||||
|
"github.com/go-task/task/v3/internal/omap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type For struct {
|
type For struct {
|
||||||
From string
|
From string
|
||||||
List []any
|
List []any
|
||||||
Matrix map[string][]any
|
Matrix omap.OrderedMap[string, []any]
|
||||||
Var string
|
Var string
|
||||||
Split string
|
Split string
|
||||||
As string
|
As string
|
||||||
@ -37,7 +38,7 @@ func (f *For) UnmarshalYAML(node *yaml.Node) error {
|
|||||||
|
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
var forStruct struct {
|
var forStruct struct {
|
||||||
Matrix map[string][]any
|
Matrix omap.OrderedMap[string, []any]
|
||||||
Var string
|
Var string
|
||||||
Split string
|
Split string
|
||||||
As string
|
As string
|
||||||
@ -45,10 +46,10 @@ func (f *For) UnmarshalYAML(node *yaml.Node) error {
|
|||||||
if err := node.Decode(&forStruct); err != nil {
|
if err := node.Decode(&forStruct); err != nil {
|
||||||
return errors.NewTaskfileDecodeError(err, node)
|
return errors.NewTaskfileDecodeError(err, node)
|
||||||
}
|
}
|
||||||
if forStruct.Var == "" && forStruct.Matrix == nil {
|
if forStruct.Var == "" && forStruct.Matrix.Len() == 0 {
|
||||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage("invalid keys in for")
|
return errors.NewTaskfileDecodeError(nil, node).WithMessage("invalid keys in for")
|
||||||
}
|
}
|
||||||
if forStruct.Var != "" && forStruct.Matrix != nil {
|
if forStruct.Var != "" && forStruct.Matrix.Len() != 0 {
|
||||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage("cannot use both var and matrix in for")
|
return errors.NewTaskfileDecodeError(nil, node).WithMessage("cannot use both var and matrix in for")
|
||||||
}
|
}
|
||||||
f.Matrix = forStruct.Matrix
|
f.Matrix = forStruct.Matrix
|
||||||
@ -68,7 +69,7 @@ func (f *For) DeepCopy() *For {
|
|||||||
return &For{
|
return &For{
|
||||||
From: f.From,
|
From: f.From,
|
||||||
List: deepcopy.Slice(f.List),
|
List: deepcopy.Slice(f.List),
|
||||||
Matrix: deepcopy.Map(f.Matrix),
|
Matrix: f.Matrix.DeepCopy(),
|
||||||
Var: f.Var,
|
Var: f.Var,
|
||||||
Split: f.Split,
|
Split: f.Split,
|
||||||
As: f.As,
|
As: f.As,
|
||||||
|
22
variables.go
22
variables.go
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"github.com/go-task/task/v3/internal/fingerprint"
|
"github.com/go-task/task/v3/internal/fingerprint"
|
||||||
|
"github.com/go-task/task/v3/internal/omap"
|
||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
"github.com/go-task/task/v3/taskfile/ast"
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
)
|
)
|
||||||
@ -272,7 +273,7 @@ func itemsFromFor(
|
|||||||
var keys []string // The list of keys to loop over (only if looping over a map)
|
var keys []string // The list of keys to loop over (only if looping over a map)
|
||||||
var values []any // The list of values to loop over
|
var values []any // The list of values to loop over
|
||||||
// Get the list from a matrix
|
// Get the list from a matrix
|
||||||
if f.Matrix != nil {
|
if f.Matrix.Len() != 0 {
|
||||||
return asAnySlice(product(f.Matrix)), nil, nil
|
return asAnySlice(product(f.Matrix)), nil, nil
|
||||||
}
|
}
|
||||||
// Get the list from the explicit for list
|
// Get the list from the explicit for list
|
||||||
@ -328,24 +329,16 @@ func itemsFromFor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// product generates the cartesian product of the input map of slices.
|
// product generates the cartesian product of the input map of slices.
|
||||||
func product(inputMap map[string][]any) []map[string]any {
|
func product(inputMap omap.OrderedMap[string, []any]) []map[string]any {
|
||||||
if len(inputMap) == 0 {
|
if inputMap.Len() == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the keys and corresponding slices
|
|
||||||
keys := make([]string, 0, len(inputMap))
|
|
||||||
slices := make([][]any, 0, len(inputMap))
|
|
||||||
for key, slice := range inputMap {
|
|
||||||
keys = append(keys, key)
|
|
||||||
slices = append(slices, slice)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start with an empty product result
|
// Start with an empty product result
|
||||||
result := []map[string]any{{}}
|
result := []map[string]any{{}}
|
||||||
|
|
||||||
// Iterate over each slice in the slices
|
// Iterate over each slice in the slices
|
||||||
for i, slice := range slices {
|
_ = inputMap.Range(func(key string, slice []any) error {
|
||||||
var newResult []map[string]any
|
var newResult []map[string]any
|
||||||
|
|
||||||
// For each combination in the current result
|
// For each combination in the current result
|
||||||
@ -358,14 +351,15 @@ func product(inputMap map[string][]any) []map[string]any {
|
|||||||
newComb[k] = v
|
newComb[k] = v
|
||||||
}
|
}
|
||||||
// Add the current item with the corresponding key
|
// Add the current item with the corresponding key
|
||||||
newComb[keys[i]] = item
|
newComb[key] = item
|
||||||
newResult = append(newResult, newComb)
|
newResult = append(newResult, newComb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update result with the new combinations
|
// Update result with the new combinations
|
||||||
result = newResult
|
result = newResult
|
||||||
}
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user