diff --git a/.github/workflows/pr-golangci-lint.yaml b/.github/workflows/pr-golangci-lint.yaml index 69a59e35bf8e..3fbbfd935791 100644 --- a/.github/workflows/pr-golangci-lint.yaml +++ b/.github/workflows/pr-golangci-lint.yaml @@ -33,3 +33,5 @@ jobs: version: v1.63.4 args: --out-format=colored-line-number working-directory: ${{matrix.working-directory}} + - name: Lint API + run: GOLANGCI_LINT_EXTRA_ARGS=--out-format=colored-line-number make lint-api diff --git a/.golangci-kal.yml b/.golangci-kal.yml new file mode 100644 index 000000000000..75e1479e692b --- /dev/null +++ b/.golangci-kal.yml @@ -0,0 +1,62 @@ +run: + timeout: 10m + go: "1.23" + allow-parallel-runners: true + +linters: + disable-all: true + enable: + - kal # linter for Kube API conventions + +linters-settings: + custom: + kal: + type: "module" + description: KAL is the Kube-API-Linter and lints Kube like APIs based on API conventions and best practices. + settings: + linters: + enable: + # Per discussion in July 2024, we are keeping phase fields for now. + # See https://github.com/kubernetes-sigs/cluster-api/pull/10897#discussion_r1685929508 + # and https://github.com/kubernetes-sigs/cluster-api/pull/10897#discussion_r1685919394. + # - "nophase" # Phase fields are discouraged by the Kube API conventions, use conditions instead. + + # Linters below this line are disabled, pending conversation on how and when to enable them. + # - "conditions" # Ensure conditions have the correct json tags and markers. + # - "commentstart" # Ensure comments start with the serialized version of the field name. + # - "integers" # Ensure only int32 and int64 are used for integers. + # - "jsontags" # Ensure every field has a json tag. + # - "maxlength" # Ensure all strings and arrays have maximum lengths/maximum items. + # - "nobools" # Bools do not evolve over time, should use enums instead. + # - "optionalorrequired" # Every field should be marked as `+optional` or `+required`. + # - "requiredfields" # Required fields should not be pointers, and should not have `omitempty`. + # - "statussubresource" # All root objects that have a `status` field should have a status subresource. + disable: + - "*" # We will manually enable new linters after understanding the impact. Disable all by default. + lintersConfig: + conditions: + isFirstField: Warn # Require conditions to be the first field in the status struct. + usePatchStrategy: Forbid # Conditions should not use the patch strategy on CRDs. + useProtobuf: Forbid # We don't use protobuf, so protobuf tags are not required. + # jsonTags: + # jsonTagRegex: "^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$" # The default regex is appropriate for our use case. + # optionalOrRequired: + # preferredOptionalMarker: optional | kubebuilder:validation:Optional # The preferred optional marker to use, fixes will suggest to use this marker. Defaults to `optional`. + # preferredRequiredMarker: required | kubebuilder:validation:Required # The preferred required marker to use, fixes will suggest to use this marker. Defaults to `required`. + # requiredFields: + # pointerPolicy: Warn | SuggestFix # Defaults to `SuggestFix`. We want our required fields to not be pointers. + +issues: + exclude-files: + - "zz_generated.*\\.go$" + - "vendored_openapi\\.go$" + # We don't want to invest time to fix new linter findings in old API types. + - "internal/apis/.*" + - ".*_test.go" # Exclude test files. + max-same-issues: 0 + max-issues-per-linter: 0 + exclude-rules: + # KAL should only run on API folders. + - path-except: "api/*" + linters: + - kal diff --git a/.golangci.yml b/.golangci.yml index e3247c7a90f1..8fefa8d0a259 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -226,6 +226,7 @@ linters-settings: - name: constant-logical-expr goconst: ignore-tests: true + issues: exclude-files: - "zz_generated.*\\.go$" diff --git a/Makefile b/Makefile index aaf1a241ea05..8cd8ef49b7b7 100644 --- a/Makefile +++ b/Makefile @@ -164,6 +164,10 @@ GOLANGCI_LINT_VER := $(shell cat .github/workflows/pr-golangci-lint.yaml | grep GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER)) GOLANGCI_LINT_PKG := github.com/golangci/golangci-lint/cmd/golangci-lint +GOLANGCI_LINT_KAL_BIN := golangci-lint-kal +GOLANGCI_LINT_KAL_VER := $(shell cat ./hack/tools/.custom-gcl.yaml | grep name: | sed 's/name: golangci-lint-kal-//') +GOLANGCI_LINT_KAL := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_KAL_BIN)-$(GOLANGCI_LINT_KAL_VER)) + GOVULNCHECK_BIN := govulncheck GOVULNCHECK_VER := v1.1.4 GOVULNCHECK := $(abspath $(TOOLS_BIN_DIR)/$(GOVULNCHECK_BIN)-$(GOVULNCHECK_VER)) @@ -653,11 +657,12 @@ generate-test-infra-prowjobs: $(PROWJOB_GEN) ## Generates the prowjob configurat ##@ lint and verify: .PHONY: lint -lint: $(GOLANGCI_LINT) ## Lint the codebase +lint: $(GOLANGCI_LINT) $(GOLANGCI_LINT_KAL) ## Lint the codebase $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS) cd $(TEST_DIR); $(GOLANGCI_LINT) run --path-prefix $(TEST_DIR) --config $(ROOT_DIR)/.golangci.yml -v $(GOLANGCI_LINT_EXTRA_ARGS) cd $(TOOLS_DIR); $(GOLANGCI_LINT) run --path-prefix $(TOOLS_DIR) --config $(ROOT_DIR)/.golangci.yml -v $(GOLANGCI_LINT_EXTRA_ARGS) ./scripts/lint-dockerfiles.sh $(HADOLINT_VER) $(HADOLINT_FAILURE_THRESHOLD) + $(GOLANGCI_LINT_KAL) run -v --config $(ROOT_DIR)/.golangci-kal.yml $(GOLANGCI_LINT_EXTRA_ARGS) .PHONY: lint-dockerfiles lint-dockerfiles: @@ -667,6 +672,14 @@ lint-dockerfiles: lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint +.PHONY: lint-api +lint-api: $(GOLANGCI_LINT_KAL) + $(GOLANGCI_LINT_KAL) run -v --config $(ROOT_DIR)/.golangci-kal.yml $(GOLANGCI_LINT_EXTRA_ARGS) + +.PHONY: lint-api-fix +lint-api-fix: $(GOLANGCI_LINT_KAL) + GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint-api + .PHONY: tiltfile-fix tiltfile-fix: ## Format the Tiltfile TRACE=$(TRACE) ./hack/verify-starlark.sh fix @@ -1492,6 +1505,9 @@ $(GINKGO): # Build ginkgo from tools folder. $(GOLANGCI_LINT): # Build golangci-lint from tools folder. GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GOLANGCI_LINT_PKG) $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER) +$(GOLANGCI_LINT_KAL): $(GOLANGCI_LINT) # Build golangci-lint-kal from custom configuration. + cd $(TOOLS_DIR); $(GOLANGCI_LINT) custom + $(GOVULNCHECK): # Build govulncheck. GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GOVULNCHECK_PKG) $(GOVULNCHECK_BIN) $(GOVULNCHECK_VER) diff --git a/hack/tools/.custom-gcl.yaml b/hack/tools/.custom-gcl.yaml new file mode 100644 index 000000000000..74b654e21cca --- /dev/null +++ b/hack/tools/.custom-gcl.yaml @@ -0,0 +1,6 @@ +version: v1.63.4 +name: golangci-lint-kal-v1.63.4 +destination: ./bin +plugins: +- module: 'github.com/JoelSpeed/kal' + version: v0.0.0-20250208110507-b94e5ede1177