-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
293 lines (245 loc) · 9.03 KB
/
Makefile
File metadata and controls
293 lines (245 loc) · 9.03 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
SHELL = /bin/bash
# ========================================
# Configuration & Variables
# ========================================
# Load and export environment variables from .env file if it exists
ifneq (,$(wildcard ./.env))
include .env
export $(shell sed 's/=.*//' .env)
else
$(error .env file not found)
endif
# Get the number of CPU cores for parallelism
get_cpu_cores = \
if [ "$$(uname)" = "Linux" ]; then \
nproc; \
elif [ "$$(uname)" = "Darwin" ]; then \
sysctl -n hw.ncpu; \
else \
echo "Unsupported OS, default to 1"; \
echo 1; \
fi
cpu_cores := $(shell $(get_cpu_cores))
# Project-specific variables
PROJECT_NAME := $(shell basename "$(PWD)" | tr '[:upper:]' '[:lower:]')
VERSION ?= $(shell git rev-parse --short HEAD)
LDFLAGS := -ldflags "-X main.version=$(VERSION)"
MODULE := $(shell go list -m)
TEST_COVERAGE_THRESHOLD := 70
# Docker variables
DOCKER_IMAGE_NAME := $(PROJECT_NAME):$(VERSION)
DOCKER_CONTAINER_NAME := $(PROJECT_NAME)-$(VERSION)
# Helper variables
GO_BUILD_CMD := CGO_ENABLED=0 go build $(LDFLAGS) -o $(PROJECT_NAME)
GO_TEST_CMD := go test -race ./... -v -coverprofile=coverage.out -covermode=atomic -parallel=$(cpu_cores)
# ========================================
# Development & Running
# ========================================
## Start all necessary services and API server
.PHONY: start
start: setup run ## Start all necessary services and API server
## Start only dependencies (Docker Compose services)
.PHONY: setup
setup: docker-compose-up ## Start only dependencies
## Run the API server locally
.PHONY: run
run: ## Run the API server
go run $(LDFLAGS) main.go
# ========================================
# Build & Version
# ========================================
## Build the API server binary
.PHONY: build
build: ## Build the API server binary
$(GO_BUILD_CMD) $(MODULE)
## Display the current version of the API server
.PHONY: version
version: ## Display the current version of the API server
@echo $(VERSION)
# ========================================
# Testing & Coverage
# ========================================
## Run tests with coverage
.PHONY: test
test: ## Run tests with coverage
$(GO_TEST_CMD)
## Generate and display the code coverage report
.PHONY: coverage
coverage: test ## Generate and display the code coverage report
@echo "Total test coverage:"
@go tool cover -func=coverage.out | grep total
@go tool cover -html=coverage.out
## Check if test coverage meets the threshold (for CI)
.PHONY: ci-coverage
ci-coverage: test ## Check if test coverage meets the threshold
@coverage=$(shell go tool cover -func=coverage.out | grep total | awk '{print $$3}' | sed 's/%//g'); \
echo "Current unit test coverage: $$coverage"; \
echo "Test Coverage Threshold: $(TEST_COVERAGE_THRESHOLD)"; \
if [ -z "$$coverage" ]; then \
echo "Test coverage output is empty. Make sure the tests ran successfully."; \
exit 1; \
elif [ $$(echo "$$coverage < $(TEST_COVERAGE_THRESHOLD)" | bc) -eq 1 ]; then \
echo "Test coverage below threshold. Please add more tests."; \
exit 1; \
else \
echo "Test coverage meets the threshold."; \
fi
# ========================================
# Code Quality & Formatting
# ========================================
## Tidy Go modules
.PHONY: tidy
tidy: ## Tidy Go modules
go mod tidy
## Format Go code
.PHONY: format
format: ## Format Go code
go fmt ./...
## Run the linter
.PHONY: lint
lint: ## Run the linter
golangci-lint run
## Run the linter and fix issues
.PHONY: lint-fix
lint-fix: ## Run the linter and fix issues
golangci-lint run --fix
# ========================================
# Debugging & Diagnostics
# ========================================
## Analyze a trace file with go tool trace
.PHONY: trace
trace: ## Analyze a trace file (usage: make trace TRACE_FILE=./traces/slow-request-GET-orders-1234567890.trace)
@if [ -z "$(TRACE_FILE)" ]; then \
echo "Error: TRACE_FILE is required"; \
echo "Usage: make trace TRACE_FILE=./traces/slow-request-GET-orders-1234567890.trace"; \
echo ""; \
echo "Available trace files:"; \
if [ -d "./traces" ] && [ -n "$$(ls -A ./traces 2>/dev/null)" ]; then \
ls -lhtr ./traces/*.trace 2>/dev/null | tail -10 || echo " No .trace files found in ./traces"; \
else \
echo " No traces directory or no trace files found"; \
fi; \
exit 1; \
fi; \
if [ ! -f "$(TRACE_FILE)" ]; then \
echo "Error: Trace file not found: $(TRACE_FILE)"; \
exit 1; \
fi; \
echo "Analyzing trace file: $(TRACE_FILE)"; \
echo "This will start a web server and open the trace viewer in your browser..."; \
go tool trace $(TRACE_FILE)
# ========================================
# Utilities & Miscellaneous
# ========================================
## Generate OWASP report
.PHONY: owasp-report
owasp-report: ## Generate OWASP report
vacuum html-report -z OpenApi-v1.yaml
## Generate Go work file
.PHONY: go-work
go-work: ## Generate Go work file
go work init .
# ========================================
# Docker Compose Services
# ========================================
## Start docker-compose services
.PHONY: docker-compose-up
docker-compose-up:
docker-compose up -d
## Stop docker-compose services
.PHONY: docker-compose-down
docker-compose-down:
docker-compose down
## Stop docker-compose services and remove volumes
.PHONY: docker-compose-down-volumes
docker-compose-down-volumes:
docker-compose down -v
## Remove only the docker-compose volumes (database data)
.PHONY: clean-volumes
clean-volumes:
@echo "Removing docker-compose volumes..."
@docker volume ls -q --filter name=orders | xargs -r docker volume rm
@echo "Volumes removed."
# ========================================
# Docker Image & Container Management
# ========================================
## Build the Docker image
.PHONY: docker-build
docker-build: ## Build the Docker image
$(info ---> Building Docker Image: $(DOCKER_IMAGE_NAME))
@if [ "$$(uname)" = "Darwin" ]; then \
DOCKER_BUILDKIT=1 docker-buildx build --output=type=docker --tag $(DOCKER_IMAGE_NAME) --build-arg port=$(port) .; \
else \
DOCKER_BUILDKIT=1 docker buildx build --output=type=docker --tag $(DOCKER_IMAGE_NAME) --build-arg port=$(port) .; \
fi
## Build the Docker image without cache
.PHONY: docker-build-debug
docker-build-debug: ## Build the Docker image without cache
$(info ---> Building Docker Image: $(DOCKER_IMAGE_NAME))
@if [ "$$(uname)" = "Darwin" ]; then \
DOCKER_BUILDKIT=1 docker-buildx build --no-cache --progress=plain --build-arg port=$(port) --tag $(DOCKER_IMAGE_NAME) --output=type=docker .; \
else \
DOCKER_BUILDKIT=1 docker buildx build --no-cache --progress=plain --build-arg port=$(port) --tag $(DOCKER_IMAGE_NAME) --output=type=docker .; \
fi
## Run the Docker container
.PHONY: docker-run
docker-run: ## Run the Docker container
$(info ---> Running Docker Container: $(DOCKER_CONTAINER_NAME) in Environment: $(profile))
docker run --name $(DOCKER_CONTAINER_NAME) -it --env environment=$(profile) $(DOCKER_IMAGE_NAME)
## Build and run the Docker container
.PHONY: docker-start
docker-start: docker-build docker-run ## Build and run the Docker container
## Stop the Docker container
.PHONY: docker-stop
docker-stop:
@if [ -n "$$(docker ps -q --filter name=$(DOCKER_CONTAINER_NAME))" ]; then \
echo "Stopping container: $(DOCKER_CONTAINER_NAME)"; \
docker stop $(DOCKER_CONTAINER_NAME); \
else \
echo "No container to stop with name: $(DOCKER_CONTAINER_NAME)"; \
fi
## Remove Docker images and containers
.PHONY: docker-remove
docker-remove:
@if [ -n "$$(docker ps -a -q --filter name=$(DOCKER_CONTAINER_NAME))" ]; then \
echo "Removing container: $(DOCKER_CONTAINER_NAME)"; \
docker rm $(DOCKER_CONTAINER_NAME); \
else \
echo "No container to remove with name: $(DOCKER_CONTAINER_NAME)"; \
fi
@if [ -n "$$(docker images -q $(DOCKER_IMAGE_NAME))" ]; then \
echo "Removing image: $(DOCKER_IMAGE_NAME)"; \
docker rmi $(DOCKER_IMAGE_NAME); \
else \
echo "No image to remove with name: $(DOCKER_IMAGE_NAME)"; \
fi
## Clean all Docker resources
.PHONY: docker-clean
docker-clean: docker-stop docker-remove docker-clean-build-images ## Clean all Docker resources
## Remove build images
.PHONY: docker-clean-build-images
docker-clean-build-images:
@if [ -n "$$(docker images --filter label="builder=true" -q)" ]; then \
echo "Removing build images..."; \
docker rmi $$(docker images --filter label="builder=true" -q); \
else \
echo "No build images to remove."; \
fi
## Clean all Docker resources (keeps database data)
.PHONY: clean
clean: docker-compose-down docker-clean ## Clean all Docker resources (keeps database data)
## Clean all Docker resources including volumes (removes database data)
.PHONY: clean-all
clean-all: docker-compose-down-volumes docker-clean ## Clean all Docker resources including volumes (removes database data)
# ========================================
# Help
# ========================================
## Display help
.PHONY: help
help:
@echo
@echo "Available commands for $(PROJECT_NAME):"
@echo
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " %-30s %s\n", $$1, $$2}' | sort
@echo