1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-05 15:37:19 +00:00

feat: support arrays in jp items() function (#6180)

This commit is contained in:
Charles-Edouard Brétéché 2023-02-01 06:43:58 +01:00 committed by GitHub
parent 04e73e0e2f
commit 7540daa906
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 26 deletions

View file

@ -450,14 +450,14 @@ func GetFunctions() []*FunctionEntry {
Entry: &gojmespath.FunctionEntry{ Entry: &gojmespath.FunctionEntry{
Name: items, Name: items,
Arguments: []ArgSpec{ Arguments: []ArgSpec{
{Types: []JpType{JpObject}}, {Types: []JpType{JpObject, JpArray}},
{Types: []JpType{JpString}}, {Types: []JpType{JpString}},
{Types: []JpType{JpString}}, {Types: []JpType{JpString}},
}, },
Handler: jpItems, Handler: jpItems,
}, },
ReturnType: []JpType{JpArray}, ReturnType: []JpType{JpArray},
Note: "converts a map to an array of objects where each key:value is an item in the array", Note: "converts a map or array to an array of objects where each key:value is an item in the array",
}, },
{ {
Entry: &gojmespath.FunctionEntry{ Entry: &gojmespath.FunctionEntry{
@ -984,10 +984,6 @@ func jpParseYAML(arguments []interface{}) (interface{}, error) {
} }
func jpItems(arguments []interface{}) (interface{}, error) { func jpItems(arguments []interface{}) (interface{}, error) {
input, ok := arguments[0].(map[string]interface{})
if !ok {
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 0, "Object")
}
keyName, ok := arguments[1].(string) keyName, ok := arguments[1].(string)
if !ok { if !ok {
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 1, "String") return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 1, "String")
@ -996,26 +992,34 @@ func jpItems(arguments []interface{}) (interface{}, error) {
if !ok { if !ok {
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 2, "String") return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 2, "String")
} }
switch input := arguments[0].(type) {
arrayOfObj := make([]map[string]interface{}, 0) case map[string]interface{}:
var keys []string
keys := []string{} // Sort the keys so that the output is deterministic
for key := range input {
// Sort the keys so that the output is deterministic keys = append(keys, key)
for key := range input { }
keys = append(keys, key) sort.Strings(keys)
var arrayOfObj []map[string]interface{}
for _, key := range keys {
arrayOfObj = append(arrayOfObj, map[string]interface{}{
keyName: key,
valName: input[key],
})
}
return arrayOfObj, nil
case []interface{}:
var arrayOfObj []map[string]interface{}
for index, value := range input {
arrayOfObj = append(arrayOfObj, map[string]interface{}{
keyName: float64(index),
valName: value,
})
}
return arrayOfObj, nil
default:
return nil, fmt.Errorf(invalidArgumentTypeError, arguments, 0, "Object")
} }
sort.Strings(keys)
for _, key := range keys {
m := make(map[string]interface{})
m[keyName] = key
m[valName] = input[key]
arrayOfObj = append(arrayOfObj, m)
}
return arrayOfObj, nil
} }
func jpObjectFromLists(arguments []interface{}) (interface{}, error) { func jpObjectFromLists(arguments []interface{}) (interface{}, error) {
@ -1068,7 +1072,6 @@ func validateArg(f string, arguments []interface{}, index int, expectedType refl
if arg.Type().Kind() != expectedType { if arg.Type().Kind() != expectedType {
return reflect.Value{}, fmt.Errorf(invalidArgumentTypeError, f, index+1, expectedType.String()) return reflect.Value{}, fmt.Errorf(invalidArgumentTypeError, f, index+1, expectedType.String())
} }
return arg, nil return arg, nil
} }

View file

@ -1349,6 +1349,12 @@ func Test_Items(t *testing.T) {
valName: `"myValue"`, valName: `"myValue"`,
expectedResult: `[{ "myKey": "key1", "myValue": "value1" }, { "myKey": "key2", "myValue": "value2" }]`, expectedResult: `[{ "myKey": "key1", "myValue": "value1" }, { "myKey": "key2", "myValue": "value2" }]`,
}, },
{
object: `["A", "B", "C"]`,
keyName: `"myKey"`,
valName: `"myValue"`,
expectedResult: `[{ "myKey": 0, "myValue": "A" }, { "myKey": 1, "myValue": "B" }, { "myKey": 2, "myValue": "C" }]`,
},
} }
for i, tc := range testCases { for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) { t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {