Skip to content

Commit c5db39b

Browse files
authored
Merge pull request #53 from numtide/makefile-cleanup
Clean up Makefile to match with the multi module setup
2 parents e6e0ce3 + 4dac4d5 commit c5db39b

File tree

5 files changed

+243
-43
lines changed

5 files changed

+243
-43
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ go.work
1313
go.work.sum
1414
cover.out
1515
cover.html
16+
coverage/
1617

1718
# kubebuilder
1819
bin/
20+
21+
# kind local development
22+
kubeconfig.yaml

Makefile

Lines changed: 225 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
1-
# Image URL to use all building/pushing image targets
2-
# if :latest then Kubernetes defaults imagePullPolicy: Always
3-
# which fails if the image tag is intended to be used only locally
4-
# so default to :dev for improved DX and override when needed in pipelines
5-
IMG ?= controller:dev
1+
###----------------------------------------
2+
## Variables
3+
#------------------------------------------
4+
# Multi-module paths
5+
# Each module must be tagged with its directory path prefix for Go module resolution
6+
# Example tags: v0.1.0 (root), api/v0.1.0, pkg/cluster-handler/v0.1.0, etc.
7+
MODULES := . ./api ./pkg/cluster-handler ./pkg/data-handler ./pkg/resource-handler
8+
9+
# Version from git tags (for root module - operator binary)
10+
# Root module uses tags like v0.1.0 (without prefix)
11+
VERSION ?= $(shell git describe --tags --match "v*" --always --dirty 2>/dev/null || echo "v0.0.1-dev")
12+
VERSION_SHORT ?= $(shell echo $(VERSION) | sed 's/^v//')
13+
14+
# Image configuration
15+
IMG_PREFIX ?= ghcr.io/numtide
16+
IMG_REPO ?= multigres-operator
17+
IMG ?= $(IMG_PREFIX)/$(IMG_REPO):$(VERSION_SHORT)
18+
19+
# Build metadata
20+
BUILD_DATE ?= $(shell date -u '+%Y-%m-%dT%H:%M:%SZ')
21+
GIT_COMMIT ?= $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
22+
23+
# LDFLAGS for version info
24+
LDFLAGS := -X main.version=$(VERSION) \
25+
-X main.buildDate=$(BUILD_DATE) \
26+
-X main.gitCommit=$(GIT_COMMIT)
627

728
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
829
ifeq (,$(shell go env GOBIN))
@@ -17,11 +38,49 @@ endif
1738
# tools. (i.e. podman)
1839
CONTAINER_TOOL ?= docker
1940

41+
# Kind cluster name for local development
42+
KIND_CLUSTER ?= multigres-operator-dev
43+
44+
# Local kubeconfig for kind cluster (doesn't modify user's ~/.kube/config)
45+
KIND_KUBECONFIG ?= $(shell pwd)/kubeconfig.yaml
46+
2047
# Setting SHELL to bash allows bash commands to be executed by recipes.
2148
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
2249
SHELL = /usr/bin/env bash -o pipefail
2350
.SHELLFLAGS = -ec
2451

52+
## Location to install dependencies to
53+
LOCALBIN ?= $(shell pwd)/bin
54+
$(LOCALBIN):
55+
mkdir -p $(LOCALBIN)
56+
57+
## Tool Binaries
58+
KUBECTL ?= kubectl
59+
KIND ?= kind
60+
KUSTOMIZE ?= $(LOCALBIN)/kustomize
61+
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
62+
ENVTEST ?= $(LOCALBIN)/setup-envtest
63+
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
64+
65+
## Tool Versions
66+
# renovate: datasource=github-releases depName=kubernetes-sigs/kustomize
67+
KUSTOMIZE_VERSION ?= v5.6.0
68+
# renovate: datasource=github-releases depName=kubernetes-sigs/controller-tools
69+
CONTROLLER_TOOLS_VERSION ?= v0.18.0
70+
# renovate: datasource=github-releases depName=golangci/golangci-lint
71+
GOLANGCI_LINT_VERSION ?= v2.3.0
72+
73+
## Envtest
74+
#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20)
75+
ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
76+
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
77+
# NOTE: This version should match the version defined in devshell.nix
78+
ENVTEST_K8S_VERSION ?= 1.33
79+
80+
###----------------------------------------
81+
## Comamnds
82+
#------------------------------------------
83+
2584
.PHONY: all
2685
all: build
2786

@@ -42,28 +101,93 @@ all: build
42101
help: ## Display this help.
43102
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
44103

104+
##@ Multi-Module Operations
105+
106+
.PHONY: modules-tidy
107+
modules-tidy: ## Run go mod tidy on all modules
108+
@for mod in $(MODULES); do \
109+
echo "==> Tidying $$mod..."; \
110+
(cd $$mod && go mod tidy) || exit 1; \
111+
done
112+
113+
.PHONY: modules-download
114+
modules-download: ## Download dependencies for all modules
115+
@for mod in $(MODULES); do \
116+
echo "==> Downloading dependencies for $$mod..."; \
117+
(cd $$mod && go mod download) || exit 1; \
118+
done
119+
120+
.PHONY: modules-verify
121+
modules-verify: ## Verify dependencies for all modules
122+
@for mod in $(MODULES); do \
123+
echo "==> Verifying $$mod..."; \
124+
(cd $$mod && go mod verify) || exit 1; \
125+
done
126+
45127
##@ Development
46128

47129
.PHONY: manifests
48130
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
49-
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
131+
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./api/..." output:crd:artifacts:config=config/crd/bases
50132

51133
.PHONY: generate
52134
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
53135
$(CONTROLLER_GEN) object paths="./api/..."
54136
# $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
55137

56138
.PHONY: fmt
57-
fmt: ## Run go fmt against code.
58-
go fmt ./...
139+
fmt: ## Run go fmt against code in all modules
140+
@for mod in $(MODULES); do \
141+
echo "==> Formatting $$mod..."; \
142+
(cd $$mod && go fmt ./...) || exit 1; \
143+
done
59144

60145
.PHONY: vet
61-
vet: ## Run go vet against code.
62-
go vet ./...
146+
vet: ## Run go vet against code in all modules
147+
@for mod in $(MODULES); do \
148+
echo "==> Vetting $$mod..."; \
149+
(cd $$mod && go vet ./...) || exit 1; \
150+
done
63151

64152
.PHONY: test
65-
test: manifests generate fmt vet setup-envtest ## Run tests.
66-
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
153+
test: manifests generate fmt vet setup-envtest ## Run tests for all modules
154+
@echo "==> Running tests across all modules"
155+
@for mod in $(MODULES); do \
156+
echo "==> Testing $$mod..."; \
157+
(cd $$mod && \
158+
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \
159+
go test $$(go list ./... | grep -v /e2e) -coverprofile=cover.out) || exit 1; \
160+
done
161+
162+
.PHONY: test-unit
163+
test-unit: manifests generate fmt vet setup-envtest ## Run unit tests for all modules (fast, no e2e)
164+
@echo "==> Running unit tests across all modules"
165+
@for mod in $(MODULES); do \
166+
echo "==> Unit testing $$mod..."; \
167+
(cd $$mod && \
168+
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \
169+
go test $$(go list ./... | grep -v /e2e) -short -v) || exit 1; \
170+
done
171+
172+
.PHONY: test-coverage
173+
test-coverage: manifests generate fmt vet setup-envtest ## Generate coverage report with HTML
174+
@mkdir -p coverage
175+
@echo "==> Generating coverage across all modules"
176+
@for mod in $(MODULES); do \
177+
modname=$$(basename $$mod); \
178+
[ "$$modname" = "." ] && modname="root"; \
179+
echo "==> Coverage for $$mod..."; \
180+
(cd $$mod && \
181+
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \
182+
go test ./... -coverprofile=../coverage/$$modname.out -covermode=atomic -coverpkg=./...) || exit 1; \
183+
done
184+
@echo "==> Generating HTML reports"
185+
@for out in coverage/*.out; do \
186+
html=$${out%.out}.html; \
187+
go tool cover -html=$$out -o=$$html; \
188+
echo "Generated: $$html"; \
189+
done
190+
@echo "Coverage reports in coverage/"
67191

68192
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
69193
# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally.
@@ -95,22 +219,49 @@ cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests
95219
@$(KIND) delete cluster --name $(KIND_CLUSTER)
96220

97221
.PHONY: lint
98-
lint: golangci-lint ## Run golangci-lint linter
99-
$(GOLANGCI_LINT) run
222+
lint: golangci-lint ## Run golangci-lint linter across all modules
223+
@for mod in $(MODULES); do \
224+
echo "==> Linting $$mod..."; \
225+
(cd $$mod && $(GOLANGCI_LINT) run) || exit 1; \
226+
done
100227

101228
.PHONY: lint-fix
102229
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
103-
$(GOLANGCI_LINT) run --fix
230+
@for mod in $(MODULES); do \
231+
echo "==> Fixing lint issues in $$mod..."; \
232+
(cd $$mod && $(GOLANGCI_LINT) run --fix) || exit 1; \
233+
done
104234

105235
.PHONY: lint-config
106236
lint-config: golangci-lint ## Verify golangci-lint linter configuration
107237
$(GOLANGCI_LINT) config verify
108238

239+
##@ Code Quality
240+
241+
.PHONY: check
242+
check: lint test ## Run all checks before committing (lint + test)
243+
@echo "==> All checks passed!"
244+
245+
.PHONY: verify
246+
verify: manifests generate ## Verify generated files are up to date
247+
@echo "==> Verifying generated files are committed"
248+
@git diff --exit-code config/crd api/ || { \
249+
echo "ERROR: Generated files are out of date."; \
250+
echo "Run 'make manifests generate' and commit the changes."; \
251+
exit 1; \
252+
}
253+
@echo "==> Verification passed!"
254+
255+
.PHONY: pre-commit
256+
pre-commit: modules-tidy fmt vet lint test ## Run full pre-commit checks (tidy, fmt, vet, lint, test)
257+
@echo "==> Pre-commit checks passed!"
258+
109259
##@ Build
110260

111261
.PHONY: build
112-
build: manifests generate fmt vet ## Build manager binary.
113-
go build -o bin/manager cmd/multigres-operator/main.go
262+
build: manifests generate fmt vet ## Build manager binary with version metadata
263+
@echo "==> Building operator binary (version: $(VERSION))"
264+
go build -ldflags="$(LDFLAGS)" -o bin/multigres-operator cmd/multigres-operator/main.go
114265

115266
.PHONY: run
116267
run: manifests generate fmt vet ## Run a controller from your host.
@@ -119,16 +270,16 @@ run: manifests generate fmt vet ## Run a controller from your host.
119270
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
120271
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
121272
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
122-
.PHONY: docker-build
123-
docker-build: ## Build docker image with the manager.
273+
.PHONY: container
274+
container: ## Build container image
124275
$(CONTAINER_TOOL) build -t ${IMG} .
125276

126277
.PHONY: minikube-load
127278
minikube-load:
128279
minikube image load ${IMG}
129280

130-
.PHONY: docker-push
131-
docker-push: ## Push docker image with the manager.
281+
.PHONY: container-push
282+
container-push: ## Push container image
132283
$(CONTAINER_TOOL) push ${IMG}
133284

134285
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
@@ -177,29 +328,53 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in
177328
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
178329
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
179330

180-
##@ Dependencies
181-
182-
## Location to install dependencies to
183-
LOCALBIN ?= $(shell pwd)/bin
184-
$(LOCALBIN):
185-
mkdir -p $(LOCALBIN)
331+
##@ Kind Cluster (Local Development)
186332

187-
## Tool Binaries
188-
KUBECTL ?= kubectl
189-
KIND ?= kind
190-
KUSTOMIZE ?= $(LOCALBIN)/kustomize
191-
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
192-
ENVTEST ?= $(LOCALBIN)/setup-envtest
193-
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
333+
.PHONY: kind-up
334+
kind-up: ## Create a kind cluster for local development
335+
@command -v $(KIND) >/dev/null 2>&1 || { \
336+
echo "ERROR: kind is not installed."; \
337+
echo "Install it from: https://kind.sigs.k8s.io/docs/user/quick-start/"; \
338+
exit 1; \
339+
}
340+
@if $(KIND) get clusters | grep -q "^$(KIND_CLUSTER)$$"; then \
341+
echo "Kind cluster '$(KIND_CLUSTER)' already exists."; \
342+
else \
343+
echo "Creating kind cluster '$(KIND_CLUSTER)'..."; \
344+
$(KIND) create cluster --name $(KIND_CLUSTER); \
345+
fi
346+
@echo "==> Exporting kubeconfig to $(KIND_KUBECONFIG)"
347+
@$(KIND) get kubeconfig --name $(KIND_CLUSTER) > $(KIND_KUBECONFIG)
348+
@echo "==> Cluster ready. Use: export KUBECONFIG=$(KIND_KUBECONFIG)"
349+
350+
.PHONY: kind-load
351+
kind-load: container ## Build and load image into kind cluster
352+
@echo "==> Loading image $(IMG) into kind cluster..."
353+
$(KIND) load docker-image $(IMG) --name $(KIND_CLUSTER)
354+
355+
.PHONY: kind-deploy
356+
kind-deploy: kind-up manifests kustomize kind-load ## Deploy operator to kind cluster
357+
@echo "==> Installing CRDs..."
358+
KUBECONFIG=$(KIND_KUBECONFIG) $(KUSTOMIZE) build config/crd | KUBECONFIG=$(KIND_KUBECONFIG) $(KUBECTL) apply -f -
359+
@echo "==> Deploying operator..."
360+
cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
361+
KUBECONFIG=$(KIND_KUBECONFIG) $(KUSTOMIZE) build config/default | KUBECONFIG=$(KIND_KUBECONFIG) $(KUBECTL) apply -f -
362+
@echo "==> Deployment complete!"
363+
@echo "Check status: KUBECONFIG=$(KIND_KUBECONFIG) kubectl get pods -n multigres-operator-system"
364+
365+
.PHONY: kind-redeploy
366+
kind-redeploy: kind-load ## Rebuild image, reload to kind, and restart pods
367+
@echo "==> Restarting operator pods..."
368+
KUBECONFIG=$(KIND_KUBECONFIG) $(KUBECTL) rollout restart deployment -n multigres-operator-system
369+
370+
.PHONY: kind-down
371+
kind-down: ## Delete the kind cluster
372+
@echo "==> Deleting kind cluster '$(KIND_CLUSTER)'..."
373+
$(KIND) delete cluster --name $(KIND_CLUSTER)
374+
@rm -f $(KIND_KUBECONFIG)
375+
@echo "==> Cluster and kubeconfig deleted"
194376

195-
## Tool Versions
196-
KUSTOMIZE_VERSION ?= v5.6.0
197-
CONTROLLER_TOOLS_VERSION ?= v0.18.0
198-
#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20)
199-
ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
200-
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
201-
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
202-
GOLANGCI_LINT_VERSION ?= v2.3.0
377+
##@ Dependencies
203378

204379
.PHONY: kustomize
205380
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
@@ -252,3 +427,11 @@ check-coverage:
252427
go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./...
253428
go tool cover -html=cover.out -o=cover.html
254429
echo now open cover.html
430+
431+
##@ Backward Compatibility Aliases
432+
433+
.PHONY: docker-build
434+
docker-build: container ## Alias for container (backward compatibility)
435+
436+
.PHONY: docker-push
437+
docker-push: container-push ## Alias for container-push (backward compatibility)

cmd/multigres-operator/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ import (
4242
)
4343

4444
var (
45+
// Version information - set via ldflags at build time
46+
version = "dev"
47+
buildDate = "unknown"
48+
gitCommit = "unknown"
49+
4550
scheme = runtime.NewScheme()
4651
setupLog = ctrl.Log.WithName("setup")
4752
)
@@ -127,6 +132,12 @@ func main() {
127132

128133
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
129134

135+
setupLog.Info("Starting Multigres Operator",
136+
"version", version,
137+
"buildDate", buildDate,
138+
"gitCommit", gitCommit,
139+
)
140+
130141
// if the enable-http2 flag is false (the default), http/2 should be disabled
131142
// due to its vulnerabilities. More specifically, disabling http/2 will
132143
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and

0 commit comments

Comments
 (0)