From bf6637013af23be4b027d5963430f120b158a4bf Mon Sep 17 00:00:00 2001 From: Stefan Bueringer Date: Fri, 3 Feb 2023 17:41:13 +0100 Subject: [PATCH] Add support for example marker --- pkg/crd/markers/validation.go | 25 +++++++++++++++++++ pkg/crd/markers/zz_generated.markerhelp.go | 16 ++++++++++++ pkg/crd/testdata/cronjob_types.go | 3 +++ .../testdata/gen/bar.example.com_foos.yaml | 1 + pkg/crd/testdata/gen/foo_types.go | 1 + .../gen/zoo/bar.example.com_zooes.yaml | 1 + pkg/crd/testdata/gen/zoo/zoo_types.go | 1 + .../testdata.kubebuilder.io_cronjobs.yaml | 10 ++++++++ pkg/crd/zz_generated.markerhelp.go | 8 ++++++ pkg/rbac/zz_generated.markerhelp.go | 8 ++++++ pkg/webhook/zz_generated.markerhelp.go | 11 +++++++- 11 files changed, 84 insertions(+), 1 deletion(-) diff --git a/pkg/crd/markers/validation.go b/pkg/crd/markers/validation.go index 5d1496189..67522c9d7 100644 --- a/pkg/crd/markers/validation.go +++ b/pkg/crd/markers/validation.go @@ -86,6 +86,9 @@ var FieldOnlyMarkers = []*definitionWithHelp{ must(markers.MakeAnyTypeDefinition("kubebuilder:default", markers.DescribesField, Default{})). WithHelp(Default{}.Help()), + must(markers.MakeAnyTypeDefinition("kubebuilder:example", markers.DescribesField, Example{})). + WithHelp(Example{}.Help()), + must(markers.MakeDefinition("kubebuilder:validation:EmbeddedResource", markers.DescribesField, XEmbeddedResource{})). WithHelp(XEmbeddedResource{}.Help()), @@ -222,6 +225,19 @@ type Default struct { Value interface{} } +// +controllertools:marker:generateHelp:category="CRD validation" +// Example sets the example value for this field. +// +// An example value will be accepted as any value valid for the +// field. Formatting for common types include: boolean: `true`, string: +// `Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy: +// "delete"}`). Examples should be defined in pruned form, and only best-effort +// validation will be performed. Full validation of an example requires +// submission of the containing CRD to an apiserver. +type Example struct { + Value interface{} +} + // +controllertools:marker:generateHelp:category="CRD processing" // PreserveUnknownFields stops the apiserver from pruning fields which are not specified. // @@ -465,6 +481,15 @@ func (m Default) ApplyToSchema(schema *apiext.JSONSchemaProps) error { return nil } +func (m Example) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + marshalledExample, err := json.Marshal(m.Value) + if err != nil { + return err + } + schema.Example = &apiext.JSON{Raw: marshalledExample} + return nil +} + func (m XPreserveUnknownFields) ApplyToSchema(schema *apiext.JSONSchemaProps) error { defTrue := true schema.XPreserveUnknownFields = &defTrue diff --git a/pkg/crd/markers/zz_generated.markerhelp.go b/pkg/crd/markers/zz_generated.markerhelp.go index 4a920039f..1884bc35f 100644 --- a/pkg/crd/markers/zz_generated.markerhelp.go +++ b/pkg/crd/markers/zz_generated.markerhelp.go @@ -68,6 +68,22 @@ func (Enum) Help() *markers.DefinitionHelp { } } +func (Example) Help() *markers.DefinitionHelp { + return &markers.DefinitionHelp{ + Category: "CRD validation", + DetailedHelp: markers.DetailedHelp{ + Summary: "sets the example value for this field. ", + Details: "An example value will be accepted as any value valid for the field. Formatting for common types include: boolean: `true`, string: `Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy: \"delete\"}`). Examples should be defined in pruned form, and only best-effort validation will be performed. Full validation of an example requires submission of the containing CRD to an apiserver.", + }, + FieldHelp: map[string]markers.DetailedHelp{ + "Value": { + Summary: "", + Details: "", + }, + }, + } +} + func (ExclusiveMaximum) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", diff --git a/pkg/crd/testdata/cronjob_types.go b/pkg/crd/testdata/cronjob_types.go index 279b81157..3b9a9ef76 100644 --- a/pkg/crd/testdata/cronjob_types.go +++ b/pkg/crd/testdata/cronjob_types.go @@ -107,14 +107,17 @@ type CronJobSpec struct { // This tests that primitive defaulting can be performed. // +kubebuilder:default=forty-two + // +kubebuilder:example=forty-two DefaultedString string `json:"defaultedString"` // This tests that slice defaulting can be performed. // +kubebuilder:default={a,b} + // +kubebuilder:example={a,b} DefaultedSlice []string `json:"defaultedSlice"` // This tests that object defaulting can be performed. // +kubebuilder:default={{nested: {foo: "baz", bar: true}},{nested: {bar: false}}} + // +kubebuilder:example={{nested: {foo: "baz", bar: true}},{nested: {bar: false}}} DefaultedObject []RootObject `json:"defaultedObject"` // This tests that pattern validator is properly applied. diff --git a/pkg/crd/testdata/gen/bar.example.com_foos.yaml b/pkg/crd/testdata/gen/bar.example.com_foos.yaml index 87ab52507..e20c13965 100644 --- a/pkg/crd/testdata/gen/bar.example.com_foos.yaml +++ b/pkg/crd/testdata/gen/bar.example.com_foos.yaml @@ -38,6 +38,7 @@ spec: default: fooDefaultString description: This tests that defaulted fields are stripped for v1beta1, but not for v1 + example: fooExampleString type: string required: - defaultedString diff --git a/pkg/crd/testdata/gen/foo_types.go b/pkg/crd/testdata/gen/foo_types.go index 5d86117e7..089904770 100644 --- a/pkg/crd/testdata/gen/foo_types.go +++ b/pkg/crd/testdata/gen/foo_types.go @@ -28,6 +28,7 @@ type FooSpec struct { // This tests that defaulted fields are stripped for v1beta1, // but not for v1 // +kubebuilder:default=fooDefaultString + // +kubebuilder:example=fooExampleString DefaultedString string `json:"defaultedString"` } type FooStatus struct{} diff --git a/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.yaml b/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.yaml index 5663360a7..7721bd6a0 100644 --- a/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.yaml +++ b/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.yaml @@ -38,6 +38,7 @@ spec: default: zooDefaultString description: This tests that defaulted fields are stripped for v1beta1, but not for v1 + example: zooExampleString type: string required: - defaultedString diff --git a/pkg/crd/testdata/gen/zoo/zoo_types.go b/pkg/crd/testdata/gen/zoo/zoo_types.go index cf9fafd66..1172b3d8a 100644 --- a/pkg/crd/testdata/gen/zoo/zoo_types.go +++ b/pkg/crd/testdata/gen/zoo/zoo_types.go @@ -28,6 +28,7 @@ type ZooSpec struct { // This tests that defaulted fields are stripped for v1beta1, // but not for v1 // +kubebuilder:default=zooDefaultString + // +kubebuilder:example=zooExampleString DefaultedString string `json:"defaultedString"` } type ZooStatus struct{} diff --git a/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml b/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml index ead8723de..b3c7ab1dd 100644 --- a/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml +++ b/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml @@ -105,6 +105,12 @@ spec: - nested: bar: false description: This tests that object defaulting can be performed. + example: + - nested: + bar: true + foo: baz + - nested: + bar: false items: properties: nested: @@ -126,12 +132,16 @@ spec: - a - b description: This tests that slice defaulting can be performed. + example: + - a + - b items: type: string type: array defaultedString: default: forty-two description: This tests that primitive defaulting can be performed. + example: forty-two type: string embeddedResource: type: object diff --git a/pkg/crd/zz_generated.markerhelp.go b/pkg/crd/zz_generated.markerhelp.go index fee8de4b9..15f2a85c3 100644 --- a/pkg/crd/zz_generated.markerhelp.go +++ b/pkg/crd/zz_generated.markerhelp.go @@ -53,6 +53,14 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "specifies if any embedded ObjectMeta in the CRD should be generated", Details: "", }, + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, }, } } diff --git a/pkg/rbac/zz_generated.markerhelp.go b/pkg/rbac/zz_generated.markerhelp.go index 0e2083a23..5b6d9c487 100644 --- a/pkg/rbac/zz_generated.markerhelp.go +++ b/pkg/rbac/zz_generated.markerhelp.go @@ -37,6 +37,14 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "sets the name of the generated ClusterRole.", Details: "", }, + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, }, } } diff --git a/pkg/webhook/zz_generated.markerhelp.go b/pkg/webhook/zz_generated.markerhelp.go index 411c58e17..8e1ef419d 100644 --- a/pkg/webhook/zz_generated.markerhelp.go +++ b/pkg/webhook/zz_generated.markerhelp.go @@ -96,6 +96,15 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "generates (partial) {Mutating,Validating}WebhookConfiguration objects.", Details: "", }, - FieldHelp: map[string]markers.DetailedHelp{}, + FieldHelp: map[string]markers.DetailedHelp{ + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, + }, } }