From c047bdf58fe743bfbc5ced3f2e4f0c28b1c41daf Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Thu, 17 Jul 2025 00:06:41 -0700 Subject: [PATCH] Sort item criteria to match listmap key order --- .../output_tests/tags/item/multiple_keys/doc.go | 7 +++++++ .../item/multiple_keys/zz_generated.validations.go | 14 ++++++++++++++ .../cmd/validation-gen/validators/item.go | 7 +++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/doc.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/doc.go index bbfadf4e610..6748332039d 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/doc.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/doc.go @@ -33,6 +33,13 @@ type Struct struct { // +k8s:listMapKey=boolKey // +k8s:item(stringKey: "target", intKey: 42, boolKey: true)=+k8s:validateFalse="item Items[stringKey=target,intKey=42,boolKey=true]" Items []Item `json:"items"` + + // +k8s:listType=map + // +k8s:listMapKey=stringKey + // +k8s:listMapKey=intKey + // +k8s:listMapKey=boolKey + // +k8s:item(boolKey: true, stringKey: "target", intKey: 42)=+k8s:validateFalse="item OutOfOrder[boolKey=42,stringKey=target,intKey=42]" + OutOfOrder []Item `json:"outOfOrder"` } type Item struct { diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/zz_generated.validations.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/zz_generated.validations.go index 0315ad7a7b5..64479184fb0 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/zz_generated.validations.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/multiple_keys/zz_generated.validations.go @@ -68,5 +68,19 @@ func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field return }(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *Struct) []Item { return oldObj.Items }))...) + // field Struct.OutOfOrder + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []Item) (errs field.ErrorList) { + // don't revalidate unchanged data + if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + errs = append(errs, validate.SliceItem(ctx, op, fldPath, obj, oldObj, func(item *Item) bool { return item.StringKey == "target" && item.IntKey == 42 && item.BoolKey == true }, validate.DirectEqual, func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Item) field.ErrorList { + return validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "item OutOfOrder[boolKey=42,stringKey=target,intKey=42]") + })...) + return + }(fldPath.Child("outOfOrder"), obj.OutOfOrder, safe.Field(oldObj, func(oldObj *Struct) []Item { return oldObj.OutOfOrder }))...) + return errs } diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/validators/item.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/validators/item.go index f34b83100b4..e0bbd58d167 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/validators/item.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/validators/item.go @@ -221,12 +221,13 @@ func (iv itemValidator) GetValidations(context Context) (Validations, error) { result := Validations{} for _, item := range itemMeta.items { - if len(item.criteria) != len(listMeta.keyNames) { - return Validations{}, fmt.Errorf("number of arguments does not match number of listMapKey fields") + if narg, nkey := len(item.criteria), len(listMeta.keyNames); narg != nkey { + return Validations{}, fmt.Errorf("number of arguments (%d) does not match number of listMapKey fields (%d)", narg, nkey) } // Validate that all listMapKeys are provided and types match foundKeys := make(map[string]bool) + sorted := make([]keyValuePair, 0, len(listMeta.keyNames)) for _, keyName := range listMeta.keyNames { for _, pair := range item.criteria { if pair.key == keyName { @@ -238,6 +239,7 @@ func (iv itemValidator) GetValidations(context Context) (Validations, error) { return Validations{}, fmt.Errorf("key %q: %w", pair.key, err) } foundKeys[keyName] = true + sorted = append(sorted, pair) break } } @@ -251,6 +253,7 @@ func (iv itemValidator) GetValidations(context Context) (Validations, error) { } return Validations{}, fmt.Errorf("missing required listMapKey fields: %v", missing) } + item.criteria = sorted // Extract validations from the stored tag itemKey := selectorString(item.criteria)