From 0eb588e8bd3a9c37f392326b23414e521b35c6ff Mon Sep 17 00:00:00 2001 From: Jan Novak Date: Thu, 8 Oct 2026 20:32:53 +0200 Subject: [PATCH] chore: add Makefile with check gate, golangci-lint config, dockerignore - make check runs lint + vet + test-short; lint is pinned to the go.mod toolchain so it works when the host Go is newer than golangci-lint's - gofumpt main.go and patch.go; drop unused gatewayGroup/gatewayKind vars Co-Authored-By: Claude Opus 5.5 --- .dockerignore | 11 ++++ .golangci.yml | 1 + CLAUDE.md | 22 ++++++-- Makefile | 56 +++++++++++++++++++ .../2026-10-08-2028-house-conventions.md | 35 +++++++++++- internal/gateway/patch.go | 8 +-- main.go | 2 +- 7 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 .dockerignore create mode 100644 .golangci.yml create mode 100644 Makefile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9af8280 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore everything by default and re-include only needed files +** + +# Re-include Go source files (but not *_test.go) +!**/*.go +**/*_test.go + +# Re-include Go module files +!go.mod +!go.sum diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..26b4afd --- /dev/null +++ b/.golangci.yml @@ -0,0 +1 @@ +version: "2" diff --git a/CLAUDE.md b/CLAUDE.md index 3eb53d0..27dfc0c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,13 +13,14 @@ Certificate's secret. ## Commands ```bash -go build ./... # build -go vet ./... # vet -go test ./... # all tests +make help # list targets +make check # lint + vet + test-short (the pre-commit gate) +make build # bin/manager +make test # full suite, -race -cover +make fmt # gofumpt -w . +make run # run against the current kubeconfig context +make docker-build IMG=gateway-cert-operator:dev go test -race -v -run TestName ./path/to/package # single test -golangci-lint run # lint -go run . # run against the current kubeconfig context -docker build -t gateway-cert-operator . kubectl kustomize deploy/ # render the manifests ``` @@ -150,6 +151,12 @@ Get the timestamp with `date "+%Y-%m-%d %H:%M %Z"`. Never write a literal placeh like `HH:MM` — always run `date` first to get the real current time. Skip trivial edits (typos, formatting, comment tweaks); only log changes a future reader would care about. +### Quality gate + +`make check` is the one-shot pre-commit gate — it runs `golangci-lint`, `go vet` and +`go test -short`, in that order. Do not declare a task complete if `make check` +reports any failures. + ### Reviews Before opening an MR for a feature, run the `operator-reviewer` and @@ -237,6 +244,9 @@ Gitea Actions, workflows in `.gitea/workflows/`: deleted. - **`--metrics-bind-address` is parsed but ignored**; metrics are still served on controller-runtime's default `:8080`. Logging is hardcoded to zap dev mode. +- **`make lint` pins `GOTOOLCHAIN` to the go.mod version.** golangci-lint cannot + type-check a standard library newer than the Go it was built with, so running + `golangci-lint run` directly fails when the host Go is ahead of it. - **No leader election**; safe only at `replicas: 1`. - **Deployment uses the mutable `:latest` tag**, so a new image does not roll out on its own. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c13e53c --- /dev/null +++ b/Makefile @@ -0,0 +1,56 @@ +BINARY := manager +BIN_DIR := bin +IMG ?= gateway-cert-operator:dev + +# GIT_COMMIT is baked into the image (-ldflags in the Dockerfile); -dirty +# covers staged and untracked changes too, which `git diff --quiet` misses. +GIT_COMMIT ?= $(shell git rev-parse --short=12 HEAD 2>/dev/null || echo unknown)$(shell test -z "$$(git status --porcelain 2>/dev/null)" || echo -dirty) + +# golangci-lint type-checks the standard library of whatever toolchain is active, +# and fails on one newer than the Go it was built with. Linting with the go.mod +# version keeps it working when the host Go is ahead, and matches CI. +GO_MOD_VERSION := $(shell awk '$$1 == "go" {print $$2}' go.mod) + +.PHONY: all build run test test-short lint vet fmt tidy check docker-build clean help + +all: check build + +build: ## Build the manager binary to bin/manager + mkdir -p $(BIN_DIR) + go build -o $(BIN_DIR)/$(BINARY) . + +run: ## Run the manager against the current kubeconfig context + go run . + +test: ## Run the full test suite with the race detector + go test -race -cover ./... + +test-short: ## Run unit tests only — skips tests guarded by testing.Short() + go test -short -cover ./... + +lint: ## Run golangci-lint + GOTOOLCHAIN=go$(GO_MOD_VERSION) golangci-lint run ./... + +vet: ## Run go vet + go vet ./... + +fmt: ## Format all Go files with gofumpt + gofumpt -w . + +tidy: ## Tidy go.mod and go.sum + go mod tidy + +check: lint vet test-short ## Run all quality checks (lint + vet + test-short) + +docker-build: ## Build the container image (IMG=name:tag) + docker build --build-arg GIT_COMMIT=$(GIT_COMMIT) -t $(IMG) . + +clean: ## Remove build artifacts + rm -rf $(BIN_DIR) + +help: ## Show available targets + @echo 'Usage: make ' + @echo '' + @echo 'Targets:' + @grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | \ + awk 'BEGIN {FS = ":.*## "}; {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}' diff --git a/docs/plans-executions/2026-10-08-2028-house-conventions.md b/docs/plans-executions/2026-10-08-2028-house-conventions.md index d2344fb..189bf39 100644 --- a/docs/plans-executions/2026-10-08-2028-house-conventions.md +++ b/docs/plans-executions/2026-10-08-2028-house-conventions.md @@ -5,7 +5,7 @@ Plan: `docs/plans/2026-10-08-2028-house-conventions.md` - [x] Step 0 — Save and commit the plan - [x] Step 1 — CLAUDE.md - [x] Step 2 — `.claude/` and docs scaffolding -- [ ] Step 3 — Makefile, lint, formatting +- [x] Step 3 — Makefile, lint, formatting - [ ] Step 4 — Module path and version identity - [ ] Step 5 — Baseline tests - [ ] Step 6 — CI build workflow @@ -51,3 +51,36 @@ Worth noting: `.claude/settings.json` leaves out `git commit`, `git push` and `git tag` on purpose, but `~/.claude/settings.json` allows `git commit` and `git push` globally, so on this machine the push confirmation rests on CLAUDE.md, not on the permission system. + +## Step 3 — Makefile, lint, formatting + +Added `Makefile` (uh-cli's shape plus `run`, `docker-build` and `-race` on `test`), +`.golangci.yml` (v2 defaults) and `.dockerignore` (egress's allowlist). + +`make lint` failed on first run, before reaching this repo's code: + +``` +$ golangci-lint run ./... +.../go/1.27.1/libexec/src/crypto/internal/randutil/randutil.go:11:2: could not import math/rand/v2 +(.../math/rand/v2/rand.go:213:17: method must have no type parameters) (typecheck) +``` + +The installed golangci-lint 2.12.2 was built with go1.26.4 and cannot type-check the +Go 1.27 standard library. The `lint` target now runs under the go.mod toolchain, +which is also what CI uses: + +```make +GO_MOD_VERSION := $(shell awk '$$1 == "go" {print $$2}' go.mod) +lint: + GOTOOLCHAIN=go$(GO_MOD_VERSION) golangci-lint run ./... +``` + +With that, lint reported the two expected dead variables (`gatewayGroup`, +`gatewayKind` in `patch.go`), which were removed. `make fmt` reformatted `main.go` +(import order) and the `patch.go` var block. + +Worth noting: this is likely the same failure the egress changelog records as +"`make lint` is blocked by a Go 1.27 toolchain/staticcheck panic"; the same +`GOTOOLCHAIN` pin should unblock it there. Rebuilding golangci-lint with Go 1.27 is +the other fix. `.golangci.yml` carries no settings yet: uh-cli's `errcheck` +exclusions are CLI-specific and nothing here needed one. diff --git a/internal/gateway/patch.go b/internal/gateway/patch.go index 911424f..ed62409 100644 --- a/internal/gateway/patch.go +++ b/internal/gateway/patch.go @@ -10,11 +10,9 @@ import ( ) var ( - defaultPort gwapiv1.PortNumber = 443 - tlsModeTerminate = gwapiv1.TLSModeTerminate - namespacesFromAll gwapiv1.FromNamespaces = gwapiv1.NamespacesFromAll - gatewayGroup gwapiv1.Group = gwapiv1.GroupName - gatewayKind gwapiv1.Kind = "Gateway" + defaultPort gwapiv1.PortNumber = 443 + tlsModeTerminate = gwapiv1.TLSModeTerminate + namespacesFromAll gwapiv1.FromNamespaces = gwapiv1.NamespacesFromAll ) // BuildListenersFromCertificates creates the desired set of managed listeners diff --git a/main.go b/main.go index 043bd61..b5892f8 100644 --- a/main.go +++ b/main.go @@ -4,8 +4,8 @@ import ( "flag" "os" - gozap "go.uber.org/zap" cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + gozap "go.uber.org/zap" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme"