Skip to content

Commit 930ec8c

Browse files
authored
🐛 Fix XValidations flattening (#998)
* Fix XValidations flattening * Add integration test for xvalidation on field and struct * Reverse order of XValidations when flattening
1 parent 99df651 commit 930ec8c

File tree

4 files changed

+38
-0
lines changed

4 files changed

+38
-0
lines changed

pkg/crd/flatten.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ func flattenAllOfInto(dst *apiext.JSONSchemaProps, src apiext.JSONSchemaProps, e
147147
dstField.Set(srcField)
148148
case "XMapType":
149149
dstField.Set(srcField)
150+
case "XValidations":
151+
dstField.Set(reflect.AppendSlice(srcField, dstField))
150152
// NB(directxman12): no need to explicitly handle nullable -- false is considered to be the zero value
151153
// TODO(directxman12): src isn't necessarily the field value -- it's just the most recent allOf entry
152154
default:

pkg/crd/flatten_all_of_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,25 @@ var _ = Describe("AllOf Flattening", func() {
241241
},
242242
}))
243243
})
244+
245+
It("should merge XValidation fields", func() {
246+
By("flattening a schema with multiple validation fields")
247+
original := &apiext.JSONSchemaProps{
248+
AllOf: []apiext.JSONSchemaProps{
249+
{XValidations: apiext.ValidationRules{{Rule: "rule2"}, {Rule: "rule3"}}},
250+
{XValidations: apiext.ValidationRules{{Rule: "rule1"}}},
251+
},
252+
}
253+
flattened := crd.FlattenEmbedded(original, errRec)
254+
Expect(errRec.FirstError()).NotTo(HaveOccurred())
255+
256+
By("ensuring that the result lists all validation rules")
257+
Expect(flattened).To(Equal(&apiext.JSONSchemaProps{
258+
XValidations: []apiext.ValidationRule{
259+
{Rule: "rule1"}, {Rule: "rule2"}, {Rule: "rule3"},
260+
},
261+
}))
262+
})
244263
})
245264

246265
It("should skip Title, Description, Example, and ExternalDocs, assuming they've been merged pre-AllOf flattening", func() {

pkg/crd/testdata/cronjob_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ type CronJobSpec struct {
303303
// +kubebuilder:validation:XValidation:rule="self.size() % 2 == 0",messageExpression="'Length has to be even but is ' + len(self.stringWithEvenLengthAndMessageExpression) + ' instead'"
304304
StringWithEvenLengthAndMessageExpression string `json:"stringWithEvenLengthAndMessageExpression,omitempty"`
305305

306+
// Test of the expression-based validation on both field and type.
307+
// +kubebuilder:validation:XValidation:rule="self.startsWith('good-')",message="must have good prefix"
308+
StringWithEvenLengthAndGoodPrefix StringEvenType `json:"stringWithEvenLengthAndGoodPrefix,omitempty"`
309+
306310
// Test that we can add a forbidden field using XValidation Reason and FieldPath.
307311
// The validation is applied to the spec struct itself and not the field.
308312
ForbiddenInt int `json:"forbiddenInt,omitempty"`
@@ -585,6 +589,10 @@ const (
585589
ReplaceConcurrent ConcurrencyPolicy = "Replace"
586590
)
587591

592+
// StringEvenType is a type that includes an expression-based validation.
593+
// +kubebuilder:validation:XValidation:rule="self.size() % 2 == 0",message="must have even length"
594+
type StringEvenType string
595+
588596
// CronJobStatus defines the observed state of CronJob
589597
type CronJobStatus struct {
590598
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster

pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6840,6 +6840,15 @@ spec:
68406840
- messageExpression: '''Length has to be even but is '' + len(self.stringWithEvenLengthAndMessageExpression)
68416841
+ '' instead'''
68426842
rule: self.size() % 2 == 0
6843+
stringWithEvenLengthAndGoodPrefix:
6844+
description: Test of the expression-based validation on both field
6845+
and type.
6846+
type: string
6847+
x-kubernetes-validations:
6848+
- message: must have good prefix
6849+
rule: self.startsWith('good-')
6850+
- message: must have even length
6851+
rule: self.size() % 2 == 0
68436852
structWithSeveralFields:
68446853
description: A struct that can only be entirely replaced
68456854
properties:

0 commit comments

Comments
 (0)