Skip to content

Commit ee5d7b1

Browse files
committed
chore: add Makefile
1 parent 6212a8f commit ee5d7b1

File tree

5 files changed

+263
-3
lines changed

5 files changed

+263
-3
lines changed

.githooks/pre-commit

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
set -e
3+
make format-check
4+
make vet
5+
make test-short

.gitignore

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# If you prefer the allow list template instead of the deny list, see community template:
22
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
33
#
4+
# Build output
5+
/build/
6+
/dist/
7+
48
# Binaries for programs and plugins
59
*.exe
610
*.exe~
@@ -26,7 +30,9 @@ go.work.sum
2630

2731
# env file
2832
.env
33+
.asc/
2934

30-
# Editor/IDE
31-
# .idea/
32-
# .vscode/
35+
# BMAD (Build, Manage, Automate, Deploy) workflow system
36+
_bmad/
37+
_bmad-output/
38+
worktrees/

Makefile

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
# Binary & paths
2+
BINARY_NAME := deeplink
3+
CMD_DIR := ./cmd
4+
BUILD_DIR := build
5+
DIST_DIR := dist
6+
INSTALL_PREFIX ?= /usr/local/bin
7+
8+
# Version info baked into binary at link time
9+
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
10+
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
11+
DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
12+
LDFLAGS := -ldflags "-X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.date=$(DATE)"
13+
14+
# Go toolchain
15+
GO := go
16+
GOBIN := $(shell $(GO) env GOPATH)/bin
17+
18+
# Lint timeout
19+
GOLANGCI_LINT_TIMEOUT ?= 5m
20+
21+
# Colors
22+
GREEN := \033[0;32m
23+
YELLOW := \033[0;33m
24+
BLUE := \033[0;34m
25+
RED := \033[0;31m
26+
NC := \033[0m
27+
28+
.PHONY: all
29+
all: build
30+
31+
## build: Compile the binary
32+
.PHONY: build
33+
build:
34+
@echo "$(BLUE)Building $(BINARY_NAME) $(VERSION)...$(NC)"
35+
@mkdir -p $(BUILD_DIR)
36+
$(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME) $(CMD_DIR)
37+
@echo "$(GREEN)✓ Build complete: $(BUILD_DIR)/$(BINARY_NAME)$(NC)"
38+
39+
## build-debug: Compile with debug symbols (no optimisations)
40+
.PHONY: build-debug
41+
build-debug:
42+
@echo "$(BLUE)Building debug binary...$(NC)"
43+
@mkdir -p $(BUILD_DIR)
44+
$(GO) build -gcflags="all=-N -l" -o $(BUILD_DIR)/$(BINARY_NAME)-debug $(CMD_DIR)
45+
@echo "$(GREEN)✓ Debug binary: $(BUILD_DIR)/$(BINARY_NAME)-debug$(NC)"
46+
47+
## release: Cross-compile for macOS (arm64/amd64), Linux, Windows
48+
.PHONY: release
49+
release: clean
50+
@echo "$(BLUE)Cross-compiling for all platforms...$(NC)"
51+
@mkdir -p $(DIST_DIR)
52+
GOOS=darwin GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(DIST_DIR)/$(BINARY_NAME)-darwin-arm64 $(CMD_DIR)
53+
GOOS=darwin GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(DIST_DIR)/$(BINARY_NAME)-darwin-amd64 $(CMD_DIR)
54+
GOOS=linux GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(DIST_DIR)/$(BINARY_NAME)-linux-amd64 $(CMD_DIR)
55+
GOOS=linux GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(DIST_DIR)/$(BINARY_NAME)-linux-arm64 $(CMD_DIR)
56+
GOOS=windows GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(DIST_DIR)/$(BINARY_NAME)-windows-amd64.exe $(CMD_DIR)
57+
@echo "$(GREEN)✓ Release binaries in $(DIST_DIR)/$(NC)"
58+
@ls -lh $(DIST_DIR)
59+
60+
## run: Build and run with --help
61+
.PHONY: run
62+
run: build
63+
@echo "$(BLUE)Running $(BINARY_NAME)...$(NC)"
64+
./$(BUILD_DIR)/$(BINARY_NAME) --help
65+
66+
## test: Run all unit tests
67+
.PHONY: test
68+
test:
69+
@echo "$(BLUE)Running tests...$(NC)"
70+
$(GO) test -v -race ./...
71+
@echo "$(GREEN)✓ All tests passed$(NC)"
72+
73+
## test-coverage: Run tests and open HTML coverage report
74+
.PHONY: test-coverage
75+
test-coverage:
76+
@echo "$(BLUE)Running tests with coverage...$(NC)"
77+
$(GO) test -race -coverprofile=coverage.out ./...
78+
$(GO) tool cover -html=coverage.out -o coverage.html
79+
@echo "$(GREEN)✓ Coverage report: coverage.html$(NC)"
80+
@$(GO) tool cover -func=coverage.out | grep total
81+
82+
## test-short: Run tests skipping slow/integration tests
83+
.PHONY: test-short
84+
test-short:
85+
@echo "$(BLUE)Running short tests...$(NC)"
86+
$(GO) test -short ./...
87+
88+
## lint: Run golangci-lint (falls back to go vet if not installed)
89+
.PHONY: lint
90+
lint:
91+
@echo "$(BLUE)Linting...$(NC)"
92+
@if command -v golangci-lint >/dev/null 2>&1; then \
93+
golangci-lint run --timeout=$(GOLANGCI_LINT_TIMEOUT) ./...; \
94+
else \
95+
echo "$(YELLOW)golangci-lint not found, falling back to go vet$(NC)"; \
96+
echo "$(YELLOW)Install with: make tools$(NC)"; \
97+
$(GO) vet ./...; \
98+
fi
99+
@echo "$(GREEN)✓ Lint passed$(NC)"
100+
101+
## format: Format code with gofmt + gofumpt
102+
.PHONY: format
103+
format:
104+
@echo "$(BLUE)Formatting code...$(NC)"
105+
$(GO) fmt ./...
106+
@if command -v gofumpt >/dev/null 2>&1; then \
107+
gofumpt -w .; \
108+
else \
109+
echo "$(YELLOW)gofumpt not found — only gofmt applied. Install with: make tools$(NC)"; \
110+
fi
111+
@echo "$(GREEN)✓ Code formatted$(NC)"
112+
113+
## format-check: Check formatting without writing files (CI-safe)
114+
.PHONY: format-check
115+
format-check:
116+
@echo "$(BLUE)Checking formatting...$(NC)"
117+
@unformatted="$$(gofmt -l .)"; \
118+
if [ -n "$$unformatted" ]; then \
119+
echo "$(RED)✗ Unformatted files (run 'make format'):$(NC)"; \
120+
echo "$$unformatted"; \
121+
exit 1; \
122+
fi
123+
@if command -v gofumpt >/dev/null 2>&1; then \
124+
unformatted_gofumpt="$$(gofumpt -l .)"; \
125+
if [ -n "$$unformatted_gofumpt" ]; then \
126+
echo "$(RED)✗ gofumpt issues detected (run 'make format'):$(NC)"; \
127+
echo "$$unformatted_gofumpt"; \
128+
exit 1; \
129+
fi; \
130+
fi
131+
@echo "$(GREEN)✓ Formatting OK$(NC)"
132+
133+
## vet: Run go vet
134+
.PHONY: vet
135+
vet:
136+
@echo "$(BLUE)Running go vet...$(NC)"
137+
$(GO) vet ./...
138+
@echo "$(GREEN)✓ vet passed$(NC)"
139+
140+
## security: Check for known vulnerabilities (requires gosec)
141+
.PHONY: security
142+
security:
143+
@echo "$(BLUE)Checking for vulnerabilities...$(NC)"
144+
@if command -v gosec >/dev/null 2>&1; then \
145+
gosec ./...; \
146+
else \
147+
echo "$(YELLOW)gosec not found. Install with: go install github.com/securego/gosec/v2/cmd/gosec@latest$(NC)"; \
148+
fi
149+
150+
## deps: Download and tidy dependencies
151+
.PHONY: deps
152+
deps:
153+
@echo "$(BLUE)Installing dependencies...$(NC)"
154+
$(GO) mod download
155+
$(GO) mod tidy
156+
@echo "$(GREEN)✓ Dependencies ready$(NC)"
157+
158+
## update-deps: Upgrade all dependencies to latest
159+
.PHONY: update-deps
160+
update-deps:
161+
@echo "$(BLUE)Updating dependencies...$(NC)"
162+
$(GO) get -u ./...
163+
$(GO) mod tidy
164+
@echo "$(GREEN)✓ Dependencies updated$(NC)"
165+
166+
## tools: Install dev tools via mise (see .mise.toml)
167+
.PHONY: tools
168+
tools:
169+
@echo "$(BLUE)Installing dev tools via mise...$(NC)"
170+
@if ! command -v mise >/dev/null 2>&1; then \
171+
echo "$(RED)✗ mise not found.$(NC)"; \
172+
echo "$(YELLOW)Install: curl https://mise.run | sh$(NC)"; \
173+
echo "$(YELLOW)Docs: https://mise.jdx.dev$(NC)"; \
174+
exit 1; \
175+
fi
176+
mise install
177+
@echo "$(GREEN)✓ Tools installed (versions pinned in .mise.toml)$(NC)"
178+
179+
## install: Build and install binary to INSTALL_PREFIX (default: /usr/local/bin)
180+
.PHONY: install
181+
install: build
182+
@echo "$(BLUE)Installing to $(INSTALL_PREFIX)/$(BINARY_NAME)...$(NC)"
183+
@install -d $(INSTALL_PREFIX)
184+
@install -m 755 $(BUILD_DIR)/$(BINARY_NAME) $(INSTALL_PREFIX)/$(BINARY_NAME)
185+
@echo "$(GREEN)✓ Installed: $(INSTALL_PREFIX)/$(BINARY_NAME)$(NC)"
186+
187+
## uninstall: Remove installed binary
188+
.PHONY: uninstall
189+
uninstall:
190+
@echo "$(BLUE)Uninstalling $(BINARY_NAME)...$(NC)"
191+
@if [ -f "$(INSTALL_PREFIX)/$(BINARY_NAME)" ]; then \
192+
rm -f $(INSTALL_PREFIX)/$(BINARY_NAME); \
193+
echo "$(GREEN)✓ Removed $(INSTALL_PREFIX)/$(BINARY_NAME)$(NC)"; \
194+
else \
195+
echo "$(YELLOW)$(BINARY_NAME) not found at $(INSTALL_PREFIX)/$(BINARY_NAME)$(NC)"; \
196+
fi
197+
198+
## install-hooks: Install pre-commit git hook (format-check + lint + test)
199+
.PHONY: install-hooks
200+
install-hooks:
201+
@echo "$(BLUE)Installing git hooks...$(NC)"
202+
@mkdir -p .githooks
203+
@printf '#!/bin/sh\nset -e\nmake format-check\nmake vet\nmake test-short\n' > .githooks/pre-commit
204+
@chmod +x .githooks/pre-commit
205+
@git config core.hooksPath .githooks
206+
@echo "$(GREEN)✓ pre-commit hook installed (.githooks/pre-commit)$(NC)"
207+
208+
## clean: Remove build artifacts and coverage files
209+
.PHONY: clean
210+
clean:
211+
@echo "$(BLUE)Cleaning...$(NC)"
212+
@rm -rf $(BUILD_DIR) $(DIST_DIR)
213+
@rm -f coverage.out coverage.html
214+
@echo "$(GREEN)✓ Clean$(NC)"
215+
216+
## dev: Full dev cycle — format, vet, lint, test, build
217+
.PHONY: dev
218+
dev: format vet lint test build
219+
@echo "$(GREEN)✓ Dev cycle complete — ready to ship!$(NC)"
220+
221+
## ci: What CI runs — no writes, strict checks
222+
.PHONY: ci
223+
ci: deps format-check vet lint test
224+
@echo "$(GREEN)✓ CI checks passed$(NC)"
225+
226+
## help: Show this help
227+
.PHONY: help
228+
help:
229+
@echo ""
230+
@echo "$(GREEN)$(BINARY_NAME)$(NC) $(VERSION) — Build System"
231+
@echo ""
232+
@echo "Usage: make [target]"
233+
@echo ""
234+
@awk 'BEGIN {FS = ":.*?## "} /^## / { \
235+
split($$0, a, ": "); \
236+
printf " $(BLUE)%-22s$(NC) %s\n", a[2], substr($$0, index($$0, a[2]) + length(a[2]) + 2) \
237+
}' $(MAKEFILE_LIST) | sort
238+
@echo ""
239+
@echo "Variables:"
240+
@echo " $(BLUE)INSTALL_PREFIX$(NC) Install path (default: /usr/local/bin)"
241+
@echo " $(BLUE)VERSION$(NC) $(VERSION)"
242+
@echo " $(BLUE)COMMIT$(NC) $(COMMIT)"
243+
@echo ""

cmd/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package main
2+
3+
func main() {}

mise.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
[tools]
22
git-cliff = "2.9.1"
3+
golangci-lint = "2.10.1"
4+
gofumpt = "0.9.2"
5+
"aqua:securego/gosec" = "2.24.0"
36

47
[settings]
58
experimental = true

0 commit comments

Comments
 (0)