diff --git a/pkg/cli/alpha/internal/generate.go b/pkg/cli/alpha/internal/generate.go index c31f88bb158..bb410c79cb8 100644 --- a/pkg/cli/alpha/internal/generate.go +++ b/pkg/cli/alpha/internal/generate.go @@ -521,6 +521,11 @@ func getAPIResourceFlags(res resource.Resource) []string { } else { args = append(args, "--namespaced=false") } + if res.API.GenerateApplyConfiguration { + args = append(args, "--generate-apply-configuration") + } else { + args = append(args, "--generate-apply-configuration=false") + } } if res.Controller { args = append(args, "--controller") diff --git a/pkg/model/resource/api.go b/pkg/model/resource/api.go index 002205161ca..c346bc24198 100644 --- a/pkg/model/resource/api.go +++ b/pkg/model/resource/api.go @@ -27,6 +27,9 @@ type API struct { // Namespaced is true if the API is namespaced. Namespaced bool `json:"namespaced,omitempty"` + + // GenerateApplyConfiguration indicates whether to generate applyconfiguration code for the resource. + GenerateApplyConfiguration bool `json:"generateApplyConfiguration,omitempty"` } // Validate checks that the API is valid. @@ -65,6 +68,9 @@ func (api *API) Update(other *API) error { // Update the namespace. api.Namespaced = api.Namespaced || other.Namespaced + // Update the generate apply configuration flag. + api.GenerateApplyConfiguration = api.GenerateApplyConfiguration || other.GenerateApplyConfiguration + return nil } diff --git a/pkg/model/resource/resource.go b/pkg/model/resource/resource.go index 4c429b3642e..197bee268c0 100644 --- a/pkg/model/resource/resource.go +++ b/pkg/model/resource/resource.go @@ -140,6 +140,11 @@ func (r Resource) IsRegularPlural() bool { return r.Plural == RegularPlural(r.Kind) } +// HasApplyConfiguration returns true if the resource has applyconfiguration generation enabled. +func (r Resource) HasApplyConfiguration() bool { + return r.API != nil && r.API.GenerateApplyConfiguration +} + // Copy returns a deep copy of the Resource that can be safely modified without affecting the original. func (r Resource) Copy() Resource { // As this function doesn't use a pointer receiver, r is already a shallow copy. diff --git a/pkg/plugins/golang/options.go b/pkg/plugins/golang/options.go index 438d245ea11..8c73d091726 100644 --- a/pkg/plugins/golang/options.go +++ b/pkg/plugins/golang/options.go @@ -68,6 +68,9 @@ type Options struct { // Namespaced is true if the resource should be namespaced. Namespaced bool + // GenerateApplyConfiguration indicates whether to generate applyconfiguration code for the resource. + GenerateApplyConfiguration bool + // Flags that define which parts should be scaffolded DoAPI bool DoController bool @@ -95,8 +98,9 @@ func (opts Options) UpdateResource(res *resource.Resource, c config.Config) { res.Path = resource.APIPackagePath(c.GetRepository(), res.Group, res.Version, c.IsMultiGroup()) res.API = &resource.API{ - CRDVersion: "v1", - Namespaced: opts.Namespaced, + CRDVersion: "v1", + Namespaced: opts.Namespaced, + GenerateApplyConfiguration: opts.GenerateApplyConfiguration, } } diff --git a/pkg/plugins/golang/v4/api.go b/pkg/plugins/golang/v4/api.go index 3d49fb10966..4aad0995e3a 100644 --- a/pkg/plugins/golang/v4/api.go +++ b/pkg/plugins/golang/v4/api.go @@ -104,6 +104,7 @@ func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { "if set, generate the resource without prompting the user") p.resourceFlag = fs.Lookup("resource") fs.BoolVar(&p.options.Namespaced, "namespaced", true, "resource is namespaced") + fs.BoolVar(&p.options.GenerateApplyConfiguration, "generate-apply-configuration", true, "if set, generate applyconfiguration code for the resource") fs.BoolVar(&p.options.DoController, "controller", true, "if set, generate the controller without prompting the user") diff --git a/pkg/plugins/golang/v4/scaffolds/api.go b/pkg/plugins/golang/v4/scaffolds/api.go index aa8c708417a..e4b088914f5 100644 --- a/pkg/plugins/golang/v4/scaffolds/api.go +++ b/pkg/plugins/golang/v4/scaffolds/api.go @@ -100,6 +100,7 @@ func (s *apiScaffolder) Scaffold() error { if err := scaffold.Execute( &api.Types{Force: s.force}, &api.Group{}, + &api.Doc{}, ); err != nil { return fmt.Errorf("error scaffolding APIs: %w", err) } diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/api/doc.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/api/doc.go new file mode 100644 index 00000000000..031976b0bfc --- /dev/null +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/api/doc.go @@ -0,0 +1,59 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package api + +import ( + log "log/slog" + "path/filepath" + + "sigs.k8s.io/kubebuilder/v4/pkg/machinery" +) + +var _ machinery.Template = &Doc{} + +// Doc scaffolds the doc file that defines the groupName +type Doc struct { + machinery.TemplateMixin + machinery.MultiGroupMixin + machinery.BoilerplateMixin + machinery.ResourceMixin +} + +// SetTemplateDefaults implements machinery.Template +func (f *Doc) SetTemplateDefaults() error { + if f.Path == "" { + if f.MultiGroup && f.Resource.Group != "" { + f.Path = filepath.Join("api", "%[group]", "%[version]", "doc.go") + } else { + f.Path = filepath.Join("api", "%[version]", "doc.go") + } + } + + f.Path = f.Resource.Replacer().Replace(f.Path) + log.Info(f.Path) + f.TemplateBody = docTemplate + + return nil +} + +//nolint:lll +const docTemplate = `{{ .Boilerplate }} + +// Package {{ .Resource.Version }} contains API Schema definitions for the {{ .Resource.Group }} {{ .Resource.Version }} API group. +// +groupName={{ .Resource.QualifiedGroup }} +package {{ .Resource.Version }} +` diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/api/group.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/api/group.go index 817722b461b..612ebe35a94 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/api/group.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/api/group.go @@ -55,7 +55,6 @@ const groupTemplate = `{{ .Boilerplate }} // Package {{ .Resource.Version }} contains API Schema definitions for the {{ .Resource.Group }} {{ .Resource.Version }} API group. // +kubebuilder:object:generate=true -// +groupName={{ .Resource.QualifiedGroup }} package {{ .Resource.Version }} import ( @@ -67,8 +66,11 @@ var ( // GroupVersion is group version used to register these objects. GroupVersion = schema.GroupVersion{Group: "{{ .Resource.QualifiedGroup }}", Version: "{{ .Resource.Version }}"} + // SchemeGroupVersion is necessary for applyconfiguration codegen. + SchemeGroupVersion = GroupVersion + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} // AddToScheme adds the types in this group-version to the given scheme. AddToScheme = SchemeBuilder.AddToScheme diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/api/types.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/api/types.go index 6996047e875..65f5a147360 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/api/types.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/api/types.go @@ -64,6 +64,11 @@ func (f *Types) SetTemplateDefaults() error { //nolint:lll const typesTemplate = `{{ .Boilerplate }} +{{ if .Resource.HasApplyConfiguration }} +// +kubebuilder:ac:generate=true +{{ else }} +// +kubebuilder:ac:generate=false +{{ end }} package {{ .Resource.Version }} import ( @@ -116,6 +121,8 @@ type {{ .Resource.Kind }}Status struct { // +kubebuilder:resource:scope=Cluster {{- else if not .Resource.IsRegularPlural }} // +kubebuilder:resource:path={{ .Resource.Plural }} +{{- else }} +// +kubebuilder:resource {{- end }} // {{ .Resource.Kind }} is the Schema for the {{ .Resource.Plural }} API diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go index 4ee5fbc7ff7..eb0b1bdf0fd 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go @@ -123,9 +123,9 @@ manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and Cust .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. {{ if .BoilerplatePath -}} - "$(CONTROLLER_GEN)" object:headerFile={{printf "%q" .BoilerplatePath}} paths="./..." + "$(CONTROLLER_GEN)" applyconfiguration:headerFile="hack/boilerplate.go.txt" object:headerFile={{printf "%q" .BoilerplatePath}} paths="./..." {{- else -}} - "$(CONTROLLER_GEN)" object paths="./..." + "$(CONTROLLER_GEN)" applyconfiguration object paths="./..." {{- end }} .PHONY: fmt