diff --git a/docs/book/src/cronjob-tutorial/testdata/project/.custom-gcl.yml b/docs/book/src/cronjob-tutorial/testdata/project/.custom-gcl.yml new file mode 100644 index 00000000000..78e822caa76 --- /dev/null +++ b/docs/book/src/cronjob-tutorial/testdata/project/.custom-gcl.yml @@ -0,0 +1,7 @@ +version: v2.5.0 +name: golangci-lint-kube-api +destination: ./bin + +plugins: + - module: sigs.k8s.io/kube-api-linter + version: latest diff --git a/docs/book/src/cronjob-tutorial/testdata/project/.github/workflows/lint.yml b/docs/book/src/cronjob-tutorial/testdata/project/.github/workflows/lint.yml index 4838c54c0df..6b1a90764ec 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/.github/workflows/lint.yml +++ b/docs/book/src/cronjob-tutorial/testdata/project/.github/workflows/lint.yml @@ -17,7 +17,13 @@ jobs: with: go-version-file: go.mod + - name: Check linter configuration + run: make lint-config + - name: Run linter uses: golangci/golangci-lint-action@v8 with: version: v2.5.0 + + - name: Run lint target + run: make lint diff --git a/docs/book/src/cronjob-tutorial/testdata/project/.golangci.yml b/docs/book/src/cronjob-tutorial/testdata/project/.golangci.yml index e5b21b0f11c..4b55b0cb6b2 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/.golangci.yml +++ b/docs/book/src/cronjob-tutorial/testdata/project/.golangci.yml @@ -21,11 +21,23 @@ linters: - unconvert - unparam - unused + - kubeapilinter settings: revive: rules: - name: comment-spacings - name: import-shadowing + custom: + kubeapilinter: + type: module + description: "Kube API Linter plugin" + original-url: "sigs.k8s.io/kube-api-linter" + settings: + linters: {} + lintersConfig: + optionalfields: + pointers: + preference: WhenRequired exclusions: generated: lax rules: @@ -36,6 +48,9 @@ linters: - dupl - lll path: internal/* + - path-except: "^api/" + linters: + - kubeapilinter paths: - third_party$ - builtin$ diff --git a/docs/book/src/cronjob-tutorial/testdata/project/Makefile b/docs/book/src/cronjob-tutorial/testdata/project/Makefile index 4f42c1d5b24..deb25aa0dbf 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/Makefile +++ b/docs/book/src/cronjob-tutorial/testdata/project/Makefile @@ -188,7 +188,8 @@ KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT_BASE = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-kube-api ## Tool Versions KUSTOMIZE_VERSION ?= v5.7.1 @@ -230,8 +231,17 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT_BASE): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT_BASE),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT): $(GOLANGCI_LINT_BASE) .custom-gcl.yml + @echo "Running golangci-lint custom..." + @$(GOLANGCI_LINT_BASE) custom || { \ + echo "golangci-lint failed. Cleaning up..."; \ + rm -f $(GOLANGCI_LINT_BASE); \ + exit 1; \ + } # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary diff --git a/docs/book/src/cronjob-tutorial/testdata/project/api/v1/cronjob_types.go b/docs/book/src/cronjob-tutorial/testdata/project/api/v1/cronjob_types.go index 9db5ea28c02..edf2e16ea6c 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/api/v1/cronjob_types.go +++ b/docs/book/src/cronjob-tutorial/testdata/project/api/v1/cronjob_types.go @@ -192,7 +192,7 @@ type CronJob struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of CronJob // +required @@ -200,7 +200,7 @@ type CronJob struct { // status defines the observed state of CronJob // +optional - Status CronJobStatus `json:"status,omitempty,omitzero"` + Status CronJobStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -208,7 +208,7 @@ type CronJob struct { // CronJobList contains a list of CronJob type CronJobList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []CronJob `json:"items"` } diff --git a/docs/book/src/getting-started/testdata/project/.custom-gcl.yml b/docs/book/src/getting-started/testdata/project/.custom-gcl.yml new file mode 100644 index 00000000000..78e822caa76 --- /dev/null +++ b/docs/book/src/getting-started/testdata/project/.custom-gcl.yml @@ -0,0 +1,7 @@ +version: v2.5.0 +name: golangci-lint-kube-api +destination: ./bin + +plugins: + - module: sigs.k8s.io/kube-api-linter + version: latest diff --git a/docs/book/src/getting-started/testdata/project/.github/workflows/lint.yml b/docs/book/src/getting-started/testdata/project/.github/workflows/lint.yml index 4838c54c0df..6b1a90764ec 100644 --- a/docs/book/src/getting-started/testdata/project/.github/workflows/lint.yml +++ b/docs/book/src/getting-started/testdata/project/.github/workflows/lint.yml @@ -17,7 +17,13 @@ jobs: with: go-version-file: go.mod + - name: Check linter configuration + run: make lint-config + - name: Run linter uses: golangci/golangci-lint-action@v8 with: version: v2.5.0 + + - name: Run lint target + run: make lint diff --git a/docs/book/src/getting-started/testdata/project/.golangci.yml b/docs/book/src/getting-started/testdata/project/.golangci.yml index e5b21b0f11c..4b55b0cb6b2 100644 --- a/docs/book/src/getting-started/testdata/project/.golangci.yml +++ b/docs/book/src/getting-started/testdata/project/.golangci.yml @@ -21,11 +21,23 @@ linters: - unconvert - unparam - unused + - kubeapilinter settings: revive: rules: - name: comment-spacings - name: import-shadowing + custom: + kubeapilinter: + type: module + description: "Kube API Linter plugin" + original-url: "sigs.k8s.io/kube-api-linter" + settings: + linters: {} + lintersConfig: + optionalfields: + pointers: + preference: WhenRequired exclusions: generated: lax rules: @@ -36,6 +48,9 @@ linters: - dupl - lll path: internal/* + - path-except: "^api/" + linters: + - kubeapilinter paths: - third_party$ - builtin$ diff --git a/docs/book/src/getting-started/testdata/project/Makefile b/docs/book/src/getting-started/testdata/project/Makefile index 02348985717..9fd1fe0a988 100644 --- a/docs/book/src/getting-started/testdata/project/Makefile +++ b/docs/book/src/getting-started/testdata/project/Makefile @@ -184,7 +184,8 @@ KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT_BASE = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-kube-api ## Tool Versions KUSTOMIZE_VERSION ?= v5.7.1 @@ -226,8 +227,17 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT_BASE): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT_BASE),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT): $(GOLANGCI_LINT_BASE) .custom-gcl.yml + @echo "Running golangci-lint custom..." + @$(GOLANGCI_LINT_BASE) custom || { \ + echo "golangci-lint failed. Cleaning up..."; \ + rm -f $(GOLANGCI_LINT_BASE); \ + exit 1; \ + } # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary diff --git a/docs/book/src/getting-started/testdata/project/api/v1alpha1/memcached_types.go b/docs/book/src/getting-started/testdata/project/api/v1alpha1/memcached_types.go index 4e8569dc9ab..fc9e4712206 100644 --- a/docs/book/src/getting-started/testdata/project/api/v1alpha1/memcached_types.go +++ b/docs/book/src/getting-started/testdata/project/api/v1alpha1/memcached_types.go @@ -75,7 +75,7 @@ type Memcached struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Memcached // +required @@ -83,7 +83,7 @@ type Memcached struct { // status defines the observed state of Memcached // +optional - Status MemcachedStatus `json:"status,omitempty,omitzero"` + Status MemcachedStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -91,7 +91,7 @@ type Memcached struct { // MemcachedList contains a list of Memcached type MemcachedList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Memcached `json:"items"` } diff --git a/docs/book/src/multiversion-tutorial/testdata/project/.custom-gcl.yml b/docs/book/src/multiversion-tutorial/testdata/project/.custom-gcl.yml new file mode 100644 index 00000000000..78e822caa76 --- /dev/null +++ b/docs/book/src/multiversion-tutorial/testdata/project/.custom-gcl.yml @@ -0,0 +1,7 @@ +version: v2.5.0 +name: golangci-lint-kube-api +destination: ./bin + +plugins: + - module: sigs.k8s.io/kube-api-linter + version: latest diff --git a/docs/book/src/multiversion-tutorial/testdata/project/.github/workflows/lint.yml b/docs/book/src/multiversion-tutorial/testdata/project/.github/workflows/lint.yml index 4838c54c0df..6b1a90764ec 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/.github/workflows/lint.yml +++ b/docs/book/src/multiversion-tutorial/testdata/project/.github/workflows/lint.yml @@ -17,7 +17,13 @@ jobs: with: go-version-file: go.mod + - name: Check linter configuration + run: make lint-config + - name: Run linter uses: golangci/golangci-lint-action@v8 with: version: v2.5.0 + + - name: Run lint target + run: make lint diff --git a/docs/book/src/multiversion-tutorial/testdata/project/.golangci.yml b/docs/book/src/multiversion-tutorial/testdata/project/.golangci.yml index e5b21b0f11c..4b55b0cb6b2 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/.golangci.yml +++ b/docs/book/src/multiversion-tutorial/testdata/project/.golangci.yml @@ -21,11 +21,23 @@ linters: - unconvert - unparam - unused + - kubeapilinter settings: revive: rules: - name: comment-spacings - name: import-shadowing + custom: + kubeapilinter: + type: module + description: "Kube API Linter plugin" + original-url: "sigs.k8s.io/kube-api-linter" + settings: + linters: {} + lintersConfig: + optionalfields: + pointers: + preference: WhenRequired exclusions: generated: lax rules: @@ -36,6 +48,9 @@ linters: - dupl - lll path: internal/* + - path-except: "^api/" + linters: + - kubeapilinter paths: - third_party$ - builtin$ diff --git a/docs/book/src/multiversion-tutorial/testdata/project/Makefile b/docs/book/src/multiversion-tutorial/testdata/project/Makefile index 4f42c1d5b24..deb25aa0dbf 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/Makefile +++ b/docs/book/src/multiversion-tutorial/testdata/project/Makefile @@ -188,7 +188,8 @@ KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT_BASE = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-kube-api ## Tool Versions KUSTOMIZE_VERSION ?= v5.7.1 @@ -230,8 +231,17 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT_BASE): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT_BASE),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT): $(GOLANGCI_LINT_BASE) .custom-gcl.yml + @echo "Running golangci-lint custom..." + @$(GOLANGCI_LINT_BASE) custom || { \ + echo "golangci-lint failed. Cleaning up..."; \ + rm -f $(GOLANGCI_LINT_BASE); \ + exit 1; \ + } # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary diff --git a/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go b/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go index e92d070bb71..9e3412ff0eb 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go @@ -156,7 +156,7 @@ type CronJob struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of CronJob // +required @@ -164,7 +164,7 @@ type CronJob struct { // status defines the observed state of CronJob // +optional - Status CronJobStatus `json:"status,omitempty,omitzero"` + Status CronJobStatus `json:"status,omitzero"` } /* @@ -175,7 +175,7 @@ type CronJob struct { // CronJobList contains a list of CronJob type CronJobList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []CronJob `json:"items"` } diff --git a/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go b/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go index ba9ef8f2eac..78c58ae3b8f 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go +++ b/docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_types.go @@ -186,7 +186,7 @@ type CronJob struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of CronJob // +required @@ -194,7 +194,7 @@ type CronJob struct { // status defines the observed state of CronJob // +optional - Status CronJobStatus `json:"status,omitempty,omitzero"` + Status CronJobStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -202,7 +202,7 @@ type CronJob struct { // CronJobList contains a list of CronJob type CronJobList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []CronJob `json:"items"` } diff --git a/pkg/plugins/golang/deploy-image/v1alpha1/scaffolds/internal/templates/api/types.go b/pkg/plugins/golang/deploy-image/v1alpha1/scaffolds/internal/templates/api/types.go index 56769378d5f..0d83d1e8da5 100644 --- a/pkg/plugins/golang/deploy-image/v1alpha1/scaffolds/internal/templates/api/types.go +++ b/pkg/plugins/golang/deploy-image/v1alpha1/scaffolds/internal/templates/api/types.go @@ -126,7 +126,7 @@ type {{ .Resource.Kind }} struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta ` + "`" + `json:"metadata,omitempty,omitzero"` + "`" + ` + metav1.ObjectMeta ` + "`" + `json:"metadata,omitzero"` + "`" + ` // spec defines the desired state of {{ .Resource.Kind }} // +required @@ -134,7 +134,7 @@ type {{ .Resource.Kind }} struct { // status defines the observed state of {{ .Resource.Kind }} // +optional - Status {{ .Resource.Kind }}Status ` + "`" + `json:"status,omitempty,omitzero"` + "`" + ` + Status {{ .Resource.Kind }}Status ` + "`" + `json:"status,omitzero"` + "`" + ` } // +kubebuilder:object:root=true @@ -142,7 +142,7 @@ type {{ .Resource.Kind }} struct { // {{ .Resource.Kind }}List contains a list of {{ .Resource.Kind }} type {{ .Resource.Kind }}List struct { metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` - metav1.ListMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` + metav1.ListMeta ` + "`" + `json:"metadata,omitzero"` + "`" + ` Items []{{ .Resource.Kind }} ` + "`" + `json:"items"` + "`" + ` } diff --git a/pkg/plugins/golang/v4/scaffolds/init.go b/pkg/plugins/golang/v4/scaffolds/init.go index 6f78d0a5cfa..a4583d104f0 100644 --- a/pkg/plugins/golang/v4/scaffolds/init.go +++ b/pkg/plugins/golang/v4/scaffolds/init.go @@ -176,6 +176,7 @@ func (s *initScaffolder) Scaffold() error { &templates.DockerIgnore{}, &templates.Readme{CommandName: s.commandName}, &templates.Golangci{}, + &templates.CustomGcl{GolangciLintVersion: GolangciLintVersion}, &e2e.Test{}, &e2e.WebhookTestUpdater{WireWebhook: false}, &e2e.SuiteTest{}, 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 429b68192d6..6996047e875 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/api/types.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/api/types.go @@ -124,7 +124,7 @@ type {{ .Resource.Kind }} struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta ` + "`" + `json:"metadata,omitempty,omitzero"` + "`" + ` + metav1.ObjectMeta ` + "`" + `json:"metadata,omitzero"` + "`" + ` // spec defines the desired state of {{ .Resource.Kind }} // +required @@ -132,7 +132,7 @@ type {{ .Resource.Kind }} struct { // status defines the observed state of {{ .Resource.Kind }} // +optional - Status {{ .Resource.Kind }}Status ` + "`" + `json:"status,omitempty,omitzero"` + "`" + ` + Status {{ .Resource.Kind }}Status ` + "`" + `json:"status,omitzero"` + "`" + ` } // +kubebuilder:object:root=true @@ -140,7 +140,7 @@ type {{ .Resource.Kind }} struct { // {{ .Resource.Kind }}List contains a list of {{ .Resource.Kind }} type {{ .Resource.Kind }}List struct { metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` - metav1.ListMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` + metav1.ListMeta ` + "`" + `json:"metadata,omitzero"` + "`" + ` Items []{{ .Resource.Kind }} ` + "`" + `json:"items"` + "`" + ` } diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/custom-gcl.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/custom-gcl.go new file mode 100644 index 00000000000..0efda5231e6 --- /dev/null +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/custom-gcl.go @@ -0,0 +1,54 @@ +/* +Copyright 2025 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 templates + +import ( + "sigs.k8s.io/kubebuilder/v4/pkg/machinery" +) + +var _ machinery.Template = &CustomGcl{} + +// CustomGcl scaffolds a file ..custom-gcl.yaml which define KAL configuration to install +type CustomGcl struct { + machinery.TemplateMixin + machinery.ProjectNameMixin + + // GolangciLintVersion is the golangci-lint version used to build the custom binary + GolangciLintVersion string +} + +// SetTemplateDefaults implements machinery.Template +func (f *CustomGcl) SetTemplateDefaults() error { + if f.Path == "" { + f.Path = ".custom-gcl.yml" + } + + f.TemplateBody = customGCLTemplate + + f.IfExistsAction = machinery.SkipFile + + return nil +} + +const customGCLTemplate = `version: {{ .GolangciLintVersion }} +name: golangci-lint-kube-api +destination: ./bin + +plugins: + - module: sigs.k8s.io/kube-api-linter + version: latest +` diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/github/lint.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/github/lint.go index 730eba48ab4..b0605ce646d 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/github/lint.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/github/lint.go @@ -65,8 +65,14 @@ jobs: with: go-version-file: go.mod + - name: Check linter configuration + run: make lint-config + - name: Run linter uses: golangci/golangci-lint-action@v8 with: version: {{ .GolangciLintVersion }} + + - name: Run lint target + run: make lint ` diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/golangci.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/golangci.go index d2a1d1fc012..29fa106d2b0 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/golangci.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/golangci.go @@ -64,11 +64,23 @@ linters: - unconvert - unparam - unused + - kubeapilinter settings: revive: rules: - name: comment-spacings - name: import-shadowing + custom: + kubeapilinter: + type: module + description: "Kube API Linter plugin" + original-url: "sigs.k8s.io/kube-api-linter" + settings: + linters: {} + lintersConfig: + optionalfields: + pointers: + preference: WhenRequired exclusions: generated: lax rules: @@ -79,6 +91,9 @@ linters: - dupl - lll path: internal/* + - path-except: "^api/" + linters: + - kubeapilinter paths: - third_party$ - builtin$ diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go index 4ee5fbc7ff7..c411d9efd91 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go @@ -263,7 +263,8 @@ KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT_BASE = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-kube-api ## Tool Versions KUSTOMIZE_VERSION ?= {{ .KustomizeVersion }} @@ -305,8 +306,17 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT_BASE): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT_BASE),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT): $(GOLANGCI_LINT_BASE) .custom-gcl.yml + @echo "Running golangci-lint custom..." + @$(GOLANGCI_LINT_BASE) custom || { \ + echo "golangci-lint failed. Cleaning up..."; \ + rm -f $(GOLANGCI_LINT_BASE); \ + exit 1; \ + } # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary diff --git a/testdata/project-v4-multigroup/.custom-gcl.yml b/testdata/project-v4-multigroup/.custom-gcl.yml new file mode 100644 index 00000000000..78e822caa76 --- /dev/null +++ b/testdata/project-v4-multigroup/.custom-gcl.yml @@ -0,0 +1,7 @@ +version: v2.5.0 +name: golangci-lint-kube-api +destination: ./bin + +plugins: + - module: sigs.k8s.io/kube-api-linter + version: latest diff --git a/testdata/project-v4-multigroup/.github/workflows/lint.yml b/testdata/project-v4-multigroup/.github/workflows/lint.yml index 4838c54c0df..6b1a90764ec 100644 --- a/testdata/project-v4-multigroup/.github/workflows/lint.yml +++ b/testdata/project-v4-multigroup/.github/workflows/lint.yml @@ -17,7 +17,13 @@ jobs: with: go-version-file: go.mod + - name: Check linter configuration + run: make lint-config + - name: Run linter uses: golangci/golangci-lint-action@v8 with: version: v2.5.0 + + - name: Run lint target + run: make lint diff --git a/testdata/project-v4-multigroup/.golangci.yml b/testdata/project-v4-multigroup/.golangci.yml index e5b21b0f11c..4b55b0cb6b2 100644 --- a/testdata/project-v4-multigroup/.golangci.yml +++ b/testdata/project-v4-multigroup/.golangci.yml @@ -21,11 +21,23 @@ linters: - unconvert - unparam - unused + - kubeapilinter settings: revive: rules: - name: comment-spacings - name: import-shadowing + custom: + kubeapilinter: + type: module + description: "Kube API Linter plugin" + original-url: "sigs.k8s.io/kube-api-linter" + settings: + linters: {} + lintersConfig: + optionalfields: + pointers: + preference: WhenRequired exclusions: generated: lax rules: @@ -36,6 +48,9 @@ linters: - dupl - lll path: internal/* + - path-except: "^api/" + linters: + - kubeapilinter paths: - third_party$ - builtin$ diff --git a/testdata/project-v4-multigroup/Makefile b/testdata/project-v4-multigroup/Makefile index 6a428164264..91e3f14f939 100644 --- a/testdata/project-v4-multigroup/Makefile +++ b/testdata/project-v4-multigroup/Makefile @@ -184,7 +184,8 @@ KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT_BASE = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-kube-api ## Tool Versions KUSTOMIZE_VERSION ?= v5.7.1 @@ -226,8 +227,17 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT_BASE): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT_BASE),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT): $(GOLANGCI_LINT_BASE) .custom-gcl.yml + @echo "Running golangci-lint custom..." + @$(GOLANGCI_LINT_BASE) custom || { \ + echo "golangci-lint failed. Cleaning up..."; \ + rm -f $(GOLANGCI_LINT_BASE); \ + exit 1; \ + } # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary diff --git a/testdata/project-v4-multigroup/api/crew/v1/captain_types.go b/testdata/project-v4-multigroup/api/crew/v1/captain_types.go index c7377c347c9..bef6aec7b05 100644 --- a/testdata/project-v4-multigroup/api/crew/v1/captain_types.go +++ b/testdata/project-v4-multigroup/api/crew/v1/captain_types.go @@ -67,7 +67,7 @@ type Captain struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Captain // +required @@ -75,7 +75,7 @@ type Captain struct { // status defines the observed state of Captain // +optional - Status CaptainStatus `json:"status,omitempty,omitzero"` + Status CaptainStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Captain struct { // CaptainList contains a list of Captain type CaptainList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Captain `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/example.com/v1/wordpress_types.go b/testdata/project-v4-multigroup/api/example.com/v1/wordpress_types.go index 615d540c95e..a785838d26e 100644 --- a/testdata/project-v4-multigroup/api/example.com/v1/wordpress_types.go +++ b/testdata/project-v4-multigroup/api/example.com/v1/wordpress_types.go @@ -68,7 +68,7 @@ type Wordpress struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Wordpress // +required @@ -76,7 +76,7 @@ type Wordpress struct { // status defines the observed state of Wordpress // +optional - Status WordpressStatus `json:"status,omitempty,omitzero"` + Status WordpressStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -84,7 +84,7 @@ type Wordpress struct { // WordpressList contains a list of Wordpress type WordpressList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Wordpress `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/example.com/v1alpha1/busybox_types.go b/testdata/project-v4-multigroup/api/example.com/v1alpha1/busybox_types.go index 58f1f644d41..5fb42df3ec1 100644 --- a/testdata/project-v4-multigroup/api/example.com/v1alpha1/busybox_types.go +++ b/testdata/project-v4-multigroup/api/example.com/v1alpha1/busybox_types.go @@ -66,7 +66,7 @@ type Busybox struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Busybox // +required @@ -74,7 +74,7 @@ type Busybox struct { // status defines the observed state of Busybox // +optional - Status BusyboxStatus `json:"status,omitempty,omitzero"` + Status BusyboxStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -82,7 +82,7 @@ type Busybox struct { // BusyboxList contains a list of Busybox type BusyboxList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Busybox `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/example.com/v1alpha1/memcached_types.go b/testdata/project-v4-multigroup/api/example.com/v1alpha1/memcached_types.go index e9a2b649dbb..de6e96e899e 100644 --- a/testdata/project-v4-multigroup/api/example.com/v1alpha1/memcached_types.go +++ b/testdata/project-v4-multigroup/api/example.com/v1alpha1/memcached_types.go @@ -70,7 +70,7 @@ type Memcached struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Memcached // +required @@ -78,7 +78,7 @@ type Memcached struct { // status defines the observed state of Memcached // +optional - Status MemcachedStatus `json:"status,omitempty,omitzero"` + Status MemcachedStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -86,7 +86,7 @@ type Memcached struct { // MemcachedList contains a list of Memcached type MemcachedList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Memcached `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/example.com/v2/wordpress_types.go b/testdata/project-v4-multigroup/api/example.com/v2/wordpress_types.go index e930845b25c..7935e36cc13 100644 --- a/testdata/project-v4-multigroup/api/example.com/v2/wordpress_types.go +++ b/testdata/project-v4-multigroup/api/example.com/v2/wordpress_types.go @@ -67,7 +67,7 @@ type Wordpress struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Wordpress // +required @@ -75,7 +75,7 @@ type Wordpress struct { // status defines the observed state of Wordpress // +optional - Status WordpressStatus `json:"status,omitempty,omitzero"` + Status WordpressStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Wordpress struct { // WordpressList contains a list of Wordpress type WordpressList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Wordpress `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/fiz/v1/bar_types.go b/testdata/project-v4-multigroup/api/fiz/v1/bar_types.go index b0fd2941da6..b91c01c94b0 100644 --- a/testdata/project-v4-multigroup/api/fiz/v1/bar_types.go +++ b/testdata/project-v4-multigroup/api/fiz/v1/bar_types.go @@ -67,7 +67,7 @@ type Bar struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Bar // +required @@ -75,7 +75,7 @@ type Bar struct { // status defines the observed state of Bar // +optional - Status BarStatus `json:"status,omitempty,omitzero"` + Status BarStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Bar struct { // BarList contains a list of Bar type BarList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Bar `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/foo.policy/v1/healthcheckpolicy_types.go b/testdata/project-v4-multigroup/api/foo.policy/v1/healthcheckpolicy_types.go index a5bc0b59651..1b71fe4afaa 100644 --- a/testdata/project-v4-multigroup/api/foo.policy/v1/healthcheckpolicy_types.go +++ b/testdata/project-v4-multigroup/api/foo.policy/v1/healthcheckpolicy_types.go @@ -67,7 +67,7 @@ type HealthCheckPolicy struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of HealthCheckPolicy // +required @@ -75,7 +75,7 @@ type HealthCheckPolicy struct { // status defines the observed state of HealthCheckPolicy // +optional - Status HealthCheckPolicyStatus `json:"status,omitempty,omitzero"` + Status HealthCheckPolicyStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type HealthCheckPolicy struct { // HealthCheckPolicyList contains a list of HealthCheckPolicy type HealthCheckPolicyList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []HealthCheckPolicy `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/foo/v1/bar_types.go b/testdata/project-v4-multigroup/api/foo/v1/bar_types.go index b0fd2941da6..b91c01c94b0 100644 --- a/testdata/project-v4-multigroup/api/foo/v1/bar_types.go +++ b/testdata/project-v4-multigroup/api/foo/v1/bar_types.go @@ -67,7 +67,7 @@ type Bar struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Bar // +required @@ -75,7 +75,7 @@ type Bar struct { // status defines the observed state of Bar // +optional - Status BarStatus `json:"status,omitempty,omitzero"` + Status BarStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Bar struct { // BarList contains a list of Bar type BarList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Bar `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/sea-creatures/v1beta1/kraken_types.go b/testdata/project-v4-multigroup/api/sea-creatures/v1beta1/kraken_types.go index dbbba68c8b4..897f1a8240f 100644 --- a/testdata/project-v4-multigroup/api/sea-creatures/v1beta1/kraken_types.go +++ b/testdata/project-v4-multigroup/api/sea-creatures/v1beta1/kraken_types.go @@ -67,7 +67,7 @@ type Kraken struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Kraken // +required @@ -75,7 +75,7 @@ type Kraken struct { // status defines the observed state of Kraken // +optional - Status KrakenStatus `json:"status,omitempty,omitzero"` + Status KrakenStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Kraken struct { // KrakenList contains a list of Kraken type KrakenList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Kraken `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/sea-creatures/v1beta2/leviathan_types.go b/testdata/project-v4-multigroup/api/sea-creatures/v1beta2/leviathan_types.go index b79a5c4e81e..3b9192ee578 100644 --- a/testdata/project-v4-multigroup/api/sea-creatures/v1beta2/leviathan_types.go +++ b/testdata/project-v4-multigroup/api/sea-creatures/v1beta2/leviathan_types.go @@ -67,7 +67,7 @@ type Leviathan struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Leviathan // +required @@ -75,7 +75,7 @@ type Leviathan struct { // status defines the observed state of Leviathan // +optional - Status LeviathanStatus `json:"status,omitempty,omitzero"` + Status LeviathanStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Leviathan struct { // LeviathanList contains a list of Leviathan type LeviathanList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Leviathan `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/ship/v1/destroyer_types.go b/testdata/project-v4-multigroup/api/ship/v1/destroyer_types.go index 849a07b38ce..fba07ea19b7 100644 --- a/testdata/project-v4-multigroup/api/ship/v1/destroyer_types.go +++ b/testdata/project-v4-multigroup/api/ship/v1/destroyer_types.go @@ -68,7 +68,7 @@ type Destroyer struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Destroyer // +required @@ -76,7 +76,7 @@ type Destroyer struct { // status defines the observed state of Destroyer // +optional - Status DestroyerStatus `json:"status,omitempty,omitzero"` + Status DestroyerStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -84,7 +84,7 @@ type Destroyer struct { // DestroyerList contains a list of Destroyer type DestroyerList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Destroyer `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/ship/v1beta1/frigate_types.go b/testdata/project-v4-multigroup/api/ship/v1beta1/frigate_types.go index d01cf4a41cb..4656fb6d5ba 100644 --- a/testdata/project-v4-multigroup/api/ship/v1beta1/frigate_types.go +++ b/testdata/project-v4-multigroup/api/ship/v1beta1/frigate_types.go @@ -67,7 +67,7 @@ type Frigate struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Frigate // +required @@ -75,7 +75,7 @@ type Frigate struct { // status defines the observed state of Frigate // +optional - Status FrigateStatus `json:"status,omitempty,omitzero"` + Status FrigateStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Frigate struct { // FrigateList contains a list of Frigate type FrigateList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Frigate `json:"items"` } diff --git a/testdata/project-v4-multigroup/api/ship/v2alpha1/cruiser_types.go b/testdata/project-v4-multigroup/api/ship/v2alpha1/cruiser_types.go index 46c906dd4c5..8f3d45fb9aa 100644 --- a/testdata/project-v4-multigroup/api/ship/v2alpha1/cruiser_types.go +++ b/testdata/project-v4-multigroup/api/ship/v2alpha1/cruiser_types.go @@ -68,7 +68,7 @@ type Cruiser struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Cruiser // +required @@ -76,7 +76,7 @@ type Cruiser struct { // status defines the observed state of Cruiser // +optional - Status CruiserStatus `json:"status,omitempty,omitzero"` + Status CruiserStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -84,7 +84,7 @@ type Cruiser struct { // CruiserList contains a list of Cruiser type CruiserList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Cruiser `json:"items"` } diff --git a/testdata/project-v4-with-plugins/.custom-gcl.yml b/testdata/project-v4-with-plugins/.custom-gcl.yml new file mode 100644 index 00000000000..78e822caa76 --- /dev/null +++ b/testdata/project-v4-with-plugins/.custom-gcl.yml @@ -0,0 +1,7 @@ +version: v2.5.0 +name: golangci-lint-kube-api +destination: ./bin + +plugins: + - module: sigs.k8s.io/kube-api-linter + version: latest diff --git a/testdata/project-v4-with-plugins/.github/workflows/lint.yml b/testdata/project-v4-with-plugins/.github/workflows/lint.yml index 4838c54c0df..6b1a90764ec 100644 --- a/testdata/project-v4-with-plugins/.github/workflows/lint.yml +++ b/testdata/project-v4-with-plugins/.github/workflows/lint.yml @@ -17,7 +17,13 @@ jobs: with: go-version-file: go.mod + - name: Check linter configuration + run: make lint-config + - name: Run linter uses: golangci/golangci-lint-action@v8 with: version: v2.5.0 + + - name: Run lint target + run: make lint diff --git a/testdata/project-v4-with-plugins/.golangci.yml b/testdata/project-v4-with-plugins/.golangci.yml index e5b21b0f11c..4b55b0cb6b2 100644 --- a/testdata/project-v4-with-plugins/.golangci.yml +++ b/testdata/project-v4-with-plugins/.golangci.yml @@ -21,11 +21,23 @@ linters: - unconvert - unparam - unused + - kubeapilinter settings: revive: rules: - name: comment-spacings - name: import-shadowing + custom: + kubeapilinter: + type: module + description: "Kube API Linter plugin" + original-url: "sigs.k8s.io/kube-api-linter" + settings: + linters: {} + lintersConfig: + optionalfields: + pointers: + preference: WhenRequired exclusions: generated: lax rules: @@ -36,6 +48,9 @@ linters: - dupl - lll path: internal/* + - path-except: "^api/" + linters: + - kubeapilinter paths: - third_party$ - builtin$ diff --git a/testdata/project-v4-with-plugins/Makefile b/testdata/project-v4-with-plugins/Makefile index 649bb75d7ed..b7e8c9c52eb 100644 --- a/testdata/project-v4-with-plugins/Makefile +++ b/testdata/project-v4-with-plugins/Makefile @@ -184,7 +184,8 @@ KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT_BASE = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-kube-api ## Tool Versions KUSTOMIZE_VERSION ?= v5.7.1 @@ -226,8 +227,17 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT_BASE): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT_BASE),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT): $(GOLANGCI_LINT_BASE) .custom-gcl.yml + @echo "Running golangci-lint custom..." + @$(GOLANGCI_LINT_BASE) custom || { \ + echo "golangci-lint failed. Cleaning up..."; \ + rm -f $(GOLANGCI_LINT_BASE); \ + exit 1; \ + } # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary diff --git a/testdata/project-v4-with-plugins/api/v1/wordpress_types.go b/testdata/project-v4-with-plugins/api/v1/wordpress_types.go index 615d540c95e..a785838d26e 100644 --- a/testdata/project-v4-with-plugins/api/v1/wordpress_types.go +++ b/testdata/project-v4-with-plugins/api/v1/wordpress_types.go @@ -68,7 +68,7 @@ type Wordpress struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Wordpress // +required @@ -76,7 +76,7 @@ type Wordpress struct { // status defines the observed state of Wordpress // +optional - Status WordpressStatus `json:"status,omitempty,omitzero"` + Status WordpressStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -84,7 +84,7 @@ type Wordpress struct { // WordpressList contains a list of Wordpress type WordpressList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Wordpress `json:"items"` } diff --git a/testdata/project-v4-with-plugins/api/v1alpha1/busybox_types.go b/testdata/project-v4-with-plugins/api/v1alpha1/busybox_types.go index 58f1f644d41..5fb42df3ec1 100644 --- a/testdata/project-v4-with-plugins/api/v1alpha1/busybox_types.go +++ b/testdata/project-v4-with-plugins/api/v1alpha1/busybox_types.go @@ -66,7 +66,7 @@ type Busybox struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Busybox // +required @@ -74,7 +74,7 @@ type Busybox struct { // status defines the observed state of Busybox // +optional - Status BusyboxStatus `json:"status,omitempty,omitzero"` + Status BusyboxStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -82,7 +82,7 @@ type Busybox struct { // BusyboxList contains a list of Busybox type BusyboxList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Busybox `json:"items"` } diff --git a/testdata/project-v4-with-plugins/api/v1alpha1/memcached_types.go b/testdata/project-v4-with-plugins/api/v1alpha1/memcached_types.go index e9a2b649dbb..de6e96e899e 100644 --- a/testdata/project-v4-with-plugins/api/v1alpha1/memcached_types.go +++ b/testdata/project-v4-with-plugins/api/v1alpha1/memcached_types.go @@ -70,7 +70,7 @@ type Memcached struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Memcached // +required @@ -78,7 +78,7 @@ type Memcached struct { // status defines the observed state of Memcached // +optional - Status MemcachedStatus `json:"status,omitempty,omitzero"` + Status MemcachedStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -86,7 +86,7 @@ type Memcached struct { // MemcachedList contains a list of Memcached type MemcachedList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Memcached `json:"items"` } diff --git a/testdata/project-v4-with-plugins/api/v2/wordpress_types.go b/testdata/project-v4-with-plugins/api/v2/wordpress_types.go index e930845b25c..7935e36cc13 100644 --- a/testdata/project-v4-with-plugins/api/v2/wordpress_types.go +++ b/testdata/project-v4-with-plugins/api/v2/wordpress_types.go @@ -67,7 +67,7 @@ type Wordpress struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Wordpress // +required @@ -75,7 +75,7 @@ type Wordpress struct { // status defines the observed state of Wordpress // +optional - Status WordpressStatus `json:"status,omitempty,omitzero"` + Status WordpressStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Wordpress struct { // WordpressList contains a list of Wordpress type WordpressList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Wordpress `json:"items"` } diff --git a/testdata/project-v4/.custom-gcl.yml b/testdata/project-v4/.custom-gcl.yml new file mode 100644 index 00000000000..78e822caa76 --- /dev/null +++ b/testdata/project-v4/.custom-gcl.yml @@ -0,0 +1,7 @@ +version: v2.5.0 +name: golangci-lint-kube-api +destination: ./bin + +plugins: + - module: sigs.k8s.io/kube-api-linter + version: latest diff --git a/testdata/project-v4/.github/workflows/lint.yml b/testdata/project-v4/.github/workflows/lint.yml index 4838c54c0df..6b1a90764ec 100644 --- a/testdata/project-v4/.github/workflows/lint.yml +++ b/testdata/project-v4/.github/workflows/lint.yml @@ -17,7 +17,13 @@ jobs: with: go-version-file: go.mod + - name: Check linter configuration + run: make lint-config + - name: Run linter uses: golangci/golangci-lint-action@v8 with: version: v2.5.0 + + - name: Run lint target + run: make lint diff --git a/testdata/project-v4/.golangci.yml b/testdata/project-v4/.golangci.yml index e5b21b0f11c..4b55b0cb6b2 100644 --- a/testdata/project-v4/.golangci.yml +++ b/testdata/project-v4/.golangci.yml @@ -21,11 +21,23 @@ linters: - unconvert - unparam - unused + - kubeapilinter settings: revive: rules: - name: comment-spacings - name: import-shadowing + custom: + kubeapilinter: + type: module + description: "Kube API Linter plugin" + original-url: "sigs.k8s.io/kube-api-linter" + settings: + linters: {} + lintersConfig: + optionalfields: + pointers: + preference: WhenRequired exclusions: generated: lax rules: @@ -36,6 +48,9 @@ linters: - dupl - lll path: internal/* + - path-except: "^api/" + linters: + - kubeapilinter paths: - third_party$ - builtin$ diff --git a/testdata/project-v4/Makefile b/testdata/project-v4/Makefile index fc3e0f9dd0a..429d4d96f8a 100644 --- a/testdata/project-v4/Makefile +++ b/testdata/project-v4/Makefile @@ -184,7 +184,8 @@ KIND ?= kind KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT_BASE = $(LOCALBIN)/golangci-lint +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-kube-api ## Tool Versions KUSTOMIZE_VERSION ?= v5.7.1 @@ -226,8 +227,17 @@ $(ENVTEST): $(LOCALBIN) .PHONY: golangci-lint golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT_BASE): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT_BASE),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +$(GOLANGCI_LINT): $(GOLANGCI_LINT_BASE) .custom-gcl.yml + @echo "Running golangci-lint custom..." + @$(GOLANGCI_LINT_BASE) custom || { \ + echo "golangci-lint failed. Cleaning up..."; \ + rm -f $(GOLANGCI_LINT_BASE); \ + exit 1; \ + } # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary diff --git a/testdata/project-v4/api/v1/admiral_types.go b/testdata/project-v4/api/v1/admiral_types.go index ae9ffa93b2a..b6efcfbfc5e 100644 --- a/testdata/project-v4/api/v1/admiral_types.go +++ b/testdata/project-v4/api/v1/admiral_types.go @@ -68,7 +68,7 @@ type Admiral struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Admiral // +required @@ -76,7 +76,7 @@ type Admiral struct { // status defines the observed state of Admiral // +optional - Status AdmiralStatus `json:"status,omitempty,omitzero"` + Status AdmiralStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -84,7 +84,7 @@ type Admiral struct { // AdmiralList contains a list of Admiral type AdmiralList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Admiral `json:"items"` } diff --git a/testdata/project-v4/api/v1/captain_types.go b/testdata/project-v4/api/v1/captain_types.go index c7377c347c9..bef6aec7b05 100644 --- a/testdata/project-v4/api/v1/captain_types.go +++ b/testdata/project-v4/api/v1/captain_types.go @@ -67,7 +67,7 @@ type Captain struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Captain // +required @@ -75,7 +75,7 @@ type Captain struct { // status defines the observed state of Captain // +optional - Status CaptainStatus `json:"status,omitempty,omitzero"` + Status CaptainStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Captain struct { // CaptainList contains a list of Captain type CaptainList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Captain `json:"items"` } diff --git a/testdata/project-v4/api/v1/firstmate_types.go b/testdata/project-v4/api/v1/firstmate_types.go index d365e068b67..a5bb4abd5c5 100644 --- a/testdata/project-v4/api/v1/firstmate_types.go +++ b/testdata/project-v4/api/v1/firstmate_types.go @@ -68,7 +68,7 @@ type FirstMate struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of FirstMate // +required @@ -76,7 +76,7 @@ type FirstMate struct { // status defines the observed state of FirstMate // +optional - Status FirstMateStatus `json:"status,omitempty,omitzero"` + Status FirstMateStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -84,7 +84,7 @@ type FirstMate struct { // FirstMateList contains a list of FirstMate type FirstMateList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []FirstMate `json:"items"` } diff --git a/testdata/project-v4/api/v1/sailor_types.go b/testdata/project-v4/api/v1/sailor_types.go index b84cb0b2260..c275c31e6d7 100644 --- a/testdata/project-v4/api/v1/sailor_types.go +++ b/testdata/project-v4/api/v1/sailor_types.go @@ -67,7 +67,7 @@ type Sailor struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of Sailor // +required @@ -75,7 +75,7 @@ type Sailor struct { // status defines the observed state of Sailor // +optional - Status SailorStatus `json:"status,omitempty,omitzero"` + Status SailorStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type Sailor struct { // SailorList contains a list of Sailor type SailorList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []Sailor `json:"items"` } diff --git a/testdata/project-v4/api/v2/firstmate_types.go b/testdata/project-v4/api/v2/firstmate_types.go index cb043103946..bda6b5e17ad 100644 --- a/testdata/project-v4/api/v2/firstmate_types.go +++ b/testdata/project-v4/api/v2/firstmate_types.go @@ -67,7 +67,7 @@ type FirstMate struct { // metadata is a standard object metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + metav1.ObjectMeta `json:"metadata,omitzero"` // spec defines the desired state of FirstMate // +required @@ -75,7 +75,7 @@ type FirstMate struct { // status defines the observed state of FirstMate // +optional - Status FirstMateStatus `json:"status,omitempty,omitzero"` + Status FirstMateStatus `json:"status,omitzero"` } // +kubebuilder:object:root=true @@ -83,7 +83,7 @@ type FirstMate struct { // FirstMateList contains a list of FirstMate type FirstMateList struct { metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata,omitzero"` Items []FirstMate `json:"items"` }