-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
342 lines (293 loc) · 10.6 KB
/
Makefile
File metadata and controls
342 lines (293 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# Makefile for APX CLI
# Build variables
BINARY_NAME := apx
MAIN_PACKAGE := ./cmd/apx
BUILD_DIR := bin
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
# Go variables
GOOS := $(shell go env GOOS)
GOARCH := $(shell go env GOARCH)
GOVERSION := $(shell go version | cut -d ' ' -f 3)
# Linker flags
LDFLAGS := -s -w
LDFLAGS += -X main.version=$(VERSION)
LDFLAGS += -X main.commit=$(COMMIT)
LDFLAGS += -X main.date=$(DATE)
# Tools
GORELEASER_VERSION := v2.6.1
.PHONY: help build clean clean-all test test-unit test-integration test-all coverage lint fmt mod-tidy install dev tools check release snapshot docker-build docker-push docker-run docker-clean enforce-principles integration-tests ci-quick
## help: Show this help message
help:
@if [ -z "$$CI$$GITHUB_ACTIONS$$JENKINS_HOME$$NO_COLOR" ]; then \
BOLD="\033[1m"; CYAN="\033[36m"; RESET="\033[0m"; \
else \
BOLD=""; CYAN=""; RESET=""; \
fi; \
printf "$${BOLD}Usage:$${RESET} make [target]\n"; \
printf "\n"; \
printf "$${BOLD}Available targets:$${RESET}\n"; \
awk -v cyan="$${CYAN}" -v reset="$${RESET}" \
'/^## / { \
line = substr($$0, 4); \
colon = index(line, ":"); \
if (colon > 0) { \
target = substr(line, 1, colon-1); \
desc = substr(line, colon+2); \
printf " %s%-22s%s %s\n", cyan, target, reset, desc; \
} \
}' $(MAKEFILE_LIST) | sort
## build: Build the binary
build:
@echo "Building $(BINARY_NAME) $(VERSION)..."
@mkdir -p $(BUILD_DIR)
CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME) $(MAIN_PACKAGE)
@echo "Built $(BUILD_DIR)/$(BINARY_NAME)"
## clean: Clean build artifacts
clean:
@echo "Cleaning..."
@rm -rf $(BUILD_DIR)
@rm -rf dist/
@rm -rf coverage.out
@go clean -cache -testcache -modcache
## clean-all: Clean all artifacts including Docker cache
clean-all: clean docker-clean
## test: Run all tests
test: test-unit test-integration
## test-unit: Run unit tests
test-unit:
@echo "Running unit tests..."
@go test -race -v ./internal/...
## test-integration: Run integration tests
test-integration:
@echo "Running integration tests..."
@go test -race -v ./tests/integration/...
## test-all: Run all tests with coverage
test-all:
@echo "Running all tests with coverage..."
@go test -race -coverprofile=coverage.out -covermode=atomic ./...
## coverage: Generate and view test coverage
coverage: test-all
@echo "Generating coverage report..."
@go tool cover -html=coverage.out -o coverage.html
@echo "Coverage report generated: coverage.html"
## lint: Run go vet
lint:
@echo "Running go vet..."
@go vet ./...
## fmt: Format code
fmt:
@echo "Formatting code..."
@go fmt ./...
@gofmt -s -w .
## mod-tidy: Tidy go modules
mod-tidy:
@echo "Tidying go modules..."
@go mod tidy
@go mod verify
## install: Install the binary
install:
@echo "Installing $(BINARY_NAME)..."
@go install -ldflags="$(LDFLAGS)" $(MAIN_PACKAGE)
## dev: Build and install for development
dev: fmt lint build install
## tools: Install development tools
tools:
@echo "Installing development tools..."
@go install github.com/goreleaser/goreleaser@$(GORELEASER_VERSION)
## check: Run all checks (format, lint, test)
check: fmt lint test-all
## release: Create a release using goreleaser
release:
@echo "Creating release..."
@goreleaser release --clean
## snapshot: Create a snapshot release
snapshot:
@echo "Creating snapshot release..."
@goreleaser release --snapshot --clean
## cross-build: Build for multiple platforms
cross-build:
@echo "Building for multiple platforms..."
@for os in linux darwin windows; do \
for arch in amd64 arm64; do \
if [ "$$os" = "windows" ] && [ "$$arch" = "arm64" ]; then continue; fi; \
echo "Building for $$os/$$arch..."; \
GOOS=$$os GOARCH=$$arch CGO_ENABLED=0 go build \
-ldflags="$(LDFLAGS)" \
-o $(BUILD_DIR)/$(BINARY_NAME)-$$os-$$arch \
$(MAIN_PACKAGE); \
if [ "$$os" = "windows" ]; then \
mv $(BUILD_DIR)/$(BINARY_NAME)-$$os-$$arch $(BUILD_DIR)/$(BINARY_NAME)-$$os-$$arch.exe; \
fi; \
done; \
done
## install-tools: Install external tools
install-tools:
@echo "Installing external tools..."
@./scripts/install-tools.sh
## up-gitea: Start local Gitea instance for testing
up-gitea:
@echo "Starting Gitea for local testing..."
@docker compose up -d gitea || docker-compose up -d gitea || { \
echo "Starting Gitea container directly..."; \
docker run -d --name gitea \
-p 3000:3000 \
-p 222:22 \
-v gitea_data:/data \
gitea/gitea:latest; \
}
@echo "Waiting for Gitea to be ready..."
@sleep 5
@echo "✓ Gitea running at http://localhost:3000"
## reset-gitea: Reset Gitea instance (clean slate)
reset-gitea:
@echo "Resetting Gitea..."
@docker stop gitea 2>/dev/null || true
@docker rm gitea 2>/dev/null || true
@docker volume rm gitea_data 2>/dev/null || true
@echo "✓ Gitea reset complete"
## install-e2e-deps: Install E2E test dependencies (k3d, kubectl)
install-e2e-deps:
@echo "Installing E2E test dependencies..."
@./scripts/install-e2e-tools.sh
## test-e2e: Run end-to-end integration tests
test-e2e:
@echo "Running E2E integration tests..."
@echo "This will create a k3d cluster and deploy Gitea..."
@go test -v -timeout 15m ./tests/e2e/...
## clean-e2e: Clean up E2E test resources (clusters, containers, volumes)
clean-e2e:
@echo "Cleaning up E2E test resources..."
@echo "Deleting k3d clusters..."
@k3d cluster list -o json 2>/dev/null | grep -o 'apx-e2e-[0-9]*' | xargs -I {} k3d cluster delete {} 2>/dev/null || true
@echo "Deleting Gitea containers..."
@docker ps -a --filter "name=k3d-apx-e2e" --format "{{.ID}}" | xargs -r docker rm -f 2>/dev/null || true
@echo "Deleting Gitea volumes..."
@docker volume ls --filter "name=k3d-apx-e2e" --format "{{.Name}}" | xargs -r docker volume rm 2>/dev/null || true
@echo "✓ E2E cleanup complete"
validate-tools:
@echo "Validating external tools..."
@command -v buf >/dev/null 2>&1 || { echo "buf is not installed"; exit 1; }
@command -v spectral >/dev/null 2>&1 || { echo "spectral is not installed"; exit 1; }
@command -v oasdiff >/dev/null 2>&1 || { echo "oasdiff is not installed"; exit 1; }
@command -v protoc >/dev/null 2>&1 || { echo "protoc is not installed"; exit 1; }
@echo "All external tools are available"
## benchmark: Run benchmarks
benchmark:
@echo "Running benchmarks..."
@go test -bench=. -benchmem ./...
## deps: Show dependency graph
deps:
@echo "Dependency graph:"
@go list -m all
## outdated: Check for outdated dependencies
outdated:
@echo "Checking for outdated dependencies..."
@go list -u -m all
## security: Run security checks
security:
@echo "Running security checks..."
@go list -json -deps ./... | nancy sleuth
## size: Show binary size
size: build
@echo "Binary size:"
@ls -lh $(BUILD_DIR)/$(BINARY_NAME)
## info: Show build information
info:
@echo "Build Information:"
@echo " Binary Name: $(BINARY_NAME)"
@echo " Version: $(VERSION)"
@echo " Commit: $(COMMIT)"
@echo " Date: $(DATE)"
@echo " Go Version: $(GOVERSION)"
@echo " OS/Arch: $(GOOS)/$(GOARCH)"
## docker-build: Build Docker image
docker-build:
@echo "Building Docker image..."
@docker build -t apx:$(VERSION) -t apx:latest .
## docker-push: Push Docker image to registry
docker-push:
@echo "Pushing Docker image..."
@docker push apx:$(VERSION)
@docker push apx:latest
## docker-run: Run in Docker container
docker-run: docker-build
@docker run --rm -it -v $(PWD):/workspace apx:$(VERSION)
## docker-clean: Clean Docker images and cache
docker-clean:
@echo "Cleaning Docker images and cache..."
@docker image prune -f
@docker system prune -f
## generate: Generate code (mocks, etc.)
generate:
@echo "Generating code..."
@go generate ./...
## tidy-all: Run all tidy operations
tidy-all: mod-tidy fmt
## pre-commit: Run all pre-commit checks
pre-commit: tidy-all lint test-all
## enforce-principles: Enforce coding principles (matches CI check)
enforce-principles: build
@echo "Enforcing coding principles..."
@echo "🔍 Checking Principle 3: No os.Exit outside main.go..."
@if git grep -n 'os\.Exit' -- '*.go' ':!cmd/**/main.go' ':!*_test.go'; then \
echo "❌ VIOLATION: os.Exit found outside cmd/**/main.go files"; \
echo "Principle 3 requires that only main() calls os.Exit"; \
exit 1; \
else \
echo "✅ PASS: No os.Exit violations found"; \
fi
@echo "🔍 Checking colorless CI output..."
@if CI=1 NO_COLOR=1 $(BUILD_DIR)/$(BINARY_NAME) help 2>&1 | grep -q $$'\033'; then \
echo "❌ VIOLATION: ANSI escape codes found in CI output"; \
echo "Principle 4 requires colorless output in CI"; \
exit 1; \
else \
echo "✅ PASS: No ANSI escape codes in CI output"; \
fi
@echo "🔍 Verifying testable command structure..."
@if ! git grep -q 'func NewApp' cmd/apx/main.go; then \
echo "❌ VIOLATION: NewApp function not found in main.go"; \
echo "Principle 3 requires exporting NewApp for testing"; \
exit 1; \
else \
echo "✅ PASS: NewApp function exported"; \
fi
@echo "🔍 Checking for proper error handling..."
@if git grep -n 'cli\.Exit' -- '*.go' ':!*_test.go'; then \
echo "❌ VIOLATION: cli.Exit found in code"; \
echo "Commands should return regular errors, not cli.Exit"; \
exit 1; \
else \
echo "✅ PASS: No cli.Exit violations found"; \
fi
@echo "✅ All principle checks passed!"
## integration-tests: Run integration tests (matches CI)
integration-tests: build
@echo "Running integration tests..."
@echo "🔍 Testing binary execution..."
@CI=1 NO_COLOR=1 APX_DISABLE_TTY=1 $(BUILD_DIR)/$(BINARY_NAME) --version
@CI=1 NO_COLOR=1 APX_DISABLE_TTY=1 $(BUILD_DIR)/$(BINARY_NAME) help >/dev/null
@CI=1 NO_COLOR=1 APX_DISABLE_TTY=1 $(BUILD_DIR)/$(BINARY_NAME) help init >/dev/null
@echo "🔍 Testing config commands..."
@CI=1 NO_COLOR=1 APX_DISABLE_TTY=1 $(BUILD_DIR)/$(BINARY_NAME) config init || true
@CI=1 NO_COLOR=1 APX_DISABLE_TTY=1 $(BUILD_DIR)/$(BINARY_NAME) config validate || true
@echo "🔍 Testing cross-platform output consistency..."
@CI=1 NO_COLOR=1 APX_DISABLE_TTY=1 $(BUILD_DIR)/$(BINARY_NAME) help > output1.txt
@CI=1 NO_COLOR=1 APX_DISABLE_TTY=1 $(BUILD_DIR)/$(BINARY_NAME) help > output2.txt
@if ! diff output1.txt output2.txt >/dev/null 2>&1; then \
echo "❌ VIOLATION: Non-deterministic output detected"; \
rm -f output1.txt output2.txt; \
exit 1; \
else \
echo "✅ PASS: Output is deterministic"; \
rm -f output1.txt output2.txt; \
fi
@echo "✅ All integration tests passed!"
## ci: Run CI pipeline locally
ci: clean tools pre-commit build cross-build enforce-principles integration-tests
## ci-quick: Run essential CI checks locally (faster)
ci-quick: fmt lint test-unit enforce-principles
# Default target
.DEFAULT_GOAL := build