Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
194 lines (162 loc) · 9.83 KB
/
Copy pathMakefile
File metadata and controls
194 lines (162 loc) · 9.83 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
DOCKER_ORG ?= ddtcorex/govard-
HOST_OS := $(shell uname -s)
DOCKER_MULTIARCH_PLATFORMS ?= linux/amd64,linux/arm64
DOCKER_BAKE ?= ./scripts/docker-buildx-bake.sh
ifeq ($(HOST_OS),Darwin)
DOCKER_PLATFORMS ?= $(DOCKER_MULTIARCH_PLATFORMS)
else
DOCKER_PLATFORMS ?=
endif
comma := ,
DOCKER_PLATFORM_FLAGS := $(foreach platform,$(subst $(comma), ,$(DOCKER_PLATFORMS)),--set "*.platform=$(platform)")
BINARY_NAME=govard
BUILD_DIR=bin
TEST_BINARY=$(BUILD_DIR)/govard-test
TEST_BUDGET_BINARY=$(BUILD_DIR)/testbudget
UNIT_PACKAGES=$(shell go list ./... | grep -v '^govard/tests/integration$$')
COVER_PACKAGES=$(shell go list ./internal/... | tr '\n' ',' | sed 's/,$$//')
VERSION_RAW ?= $(shell git describe --tags --dirty --always 2>/dev/null || echo 1.0.0)
VERSION ?= $(patsubst v%,%,$(VERSION_RAW))
GOLANGCI_LINT_VERSION ?= v2.11.3
GOLANGCI_LINT_BIN ?= $(shell go env GOPATH)/bin/golangci-lint
LDFLAGS ?= -s -w -X govard/internal/cmd.Version=$(VERSION) -X govard/internal/desktop.Version=$(VERSION)
.PHONY: help install install-release build-test-binary build-test-budget build frontend build-frontend bindings bindings-check font-check clean test test-unit test-coverage test-integration test-integration-ci test-frontend test-frontend-behaviour lint lint-desktop lint-install fmt fmt-check vet generate generate-check images push
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
install: ## Build and install Govard CLI + Desktop binaries from current source tree
./install.sh --source --source-dir "$(CURDIR)" -y
install-release: ## Install latest release Govard CLI + Desktop binaries to system
./install.sh -y
# frontend builds the desktop UI with Vite into desktop/frontend/dist, which
# desktop/frontend/embed.go embeds. Every desktop binary build needs it first.
frontend:
@echo "Building desktop frontend..."
@cd desktop/frontend && pnpm install --frozen-lockfile && pnpm build
@# Vite's emptyOutDir also removes dist/.gitkeep, which //go:embed all:dist
@# needs on a checkout that has never been built. Restore it so the working
@# tree stays clean after every build.
@touch desktop/frontend/dist/.gitkeep
build-frontend: frontend
BINDINGS_DIR := desktop/frontend/bindings
# bindings regenerates the committed JS bindings from the Go services. The
# -f "-tags desktop" flag is mandatory: without it the generator finds no
# services, prints "0 Services" and still exits 0.
bindings:
@rm -rf $(BINDINGS_DIR)
go tool wails3 generate bindings -f "-tags desktop" -d $(BINDINGS_DIR) ./cmd/govard-desktop
# bindings-check fails when the committed bindings do not match the Go
# services, which is what happens when a service method is renamed and the
# regeneration is forgotten. The untracked check uses ls-files rather than
# git status, because status also reports staged additions and would fail on
# the commit that first adds the bindings. It also regenerates the preview's
# route defaults and id map (derived from those same bindings) and fails on
# drift, so a renamed Go method trips both checks in one command.
bindings-check: bindings
@git diff --exit-code -- $(BINDINGS_DIR) || (echo "Bindings are stale: run 'make bindings' and commit." && exit 1)
@test -z "$$(git ls-files --others -- $(BINDINGS_DIR))" || (echo "Untracked bindings: run 'make bindings' and commit." && exit 1)
@node desktop/frontend/scripts/generate-preview-route-defaults.mjs
@git diff --exit-code -- desktop/frontend/preview/route-defaults.generated.js desktop/frontend/preview/id-map.generated.js || (echo "Preview route defaults are stale: run 'node desktop/frontend/scripts/generate-preview-route-defaults.mjs' and commit." && exit 1)
# font-check fails when the committed icon subset does not match what the
# scanner sees in source. It must run before `make frontend`: the build
# regenerates the manifest from the same scanner, so the icon-coverage tests
# run after a build compare the scanner against its own output and cannot
# fail. Checked first, they pin the committed assets instead.
font-check: ## Fail when the committed icon subset drifts from source
@cd desktop/frontend && pnpm install --frozen-lockfile && node scripts/subset-icons.mjs
@git diff --exit-code -- desktop/frontend/assets/ || (echo "Icon subset is stale: run 'make frontend' and commit the regenerated assets." && exit 1)
@test -z "$$(git status --porcelain --untracked-files=all -- desktop/frontend/assets/ | grep '^??')" || (echo "Untracked icon assets: commit or remove them." && git status --porcelain --untracked-files=all -- desktop/frontend/assets/ | grep '^??' && exit 1)
build: generate ## Build Govard binary for the current platform
@echo "Building Govard..."
mkdir -p $(BUILD_DIR)
go build -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME) cmd/govard/main.go
build-test-binary:
@echo "Building test binary..."
mkdir -p $(BUILD_DIR)
go build -mod=mod -ldflags "$(LDFLAGS)" -tags integration -o $(TEST_BINARY) cmd/govard/main.go
generate: ## Regenerate internal/frameworks/all_generated.go
go generate ./internal/frameworks/...
generate-check: generate ## Fail if generated files are stale (CI drift check)
@if ! git diff --quiet -- internal/frameworks/all_generated.go; then \
echo "internal/frameworks/all_generated.go is out of date - run 'make generate' and commit the result:"; \
git diff -- internal/frameworks/all_generated.go; \
exit 1; \
fi
test: generate lint fmt-check vet test-frontend test-unit test-integration ## Run all tests
fmt-check:
@echo "Checking code formatting..."
@unformatted="$$(find . -type f -name '*.go' -not -path './vendor/*' -print0 | xargs -0 gofmt -s -l)"; \
if [ -n "$$unformatted" ]; then \
echo "The following files need formatting:"; \
echo "$$unformatted"; \
exit 1; \
fi
# The time-budget gate wraps the go test run rather than measuring it in a
# second pass: it reads the Elapsed field go test -json already reports, so the
# budget costs no wall time. It is built as a binary instead of `go run` so a
# budget breach exits quietly rather than trailing go run's own "exit status 1".
build-test-budget:
@echo "Building test time-budget gate..."
@mkdir -p $(BUILD_DIR)
go build -o $(TEST_BUDGET_BINARY) ./scripts/testbudget
# The unit suite runs under the race detector. Two data races in internal/deploy
# sat here for years precisely because nothing in the ordinary suite ran one, and
# the cost is ~10% on this suite: it spends its wall clock in `ps`, `git`,
# `docker` and time.Sleep, not in CPU-bound Go code, so the detector has little
# to instrument. Integration is left alone — it drives the real binary out of
# process, where the detector would only cover the test harness.
test-unit: build-test-budget
@echo "Running unit tests (time-budgeted, race detector on)..."
$(TEST_BUDGET_BINARY) -suite unit -stale -- go test $(UNIT_PACKAGES) -short -race -json
test-coverage:
@echo "Running unit tests with coverage..."
go test ./tests -coverprofile=coverage.out -covermode=atomic -coverpkg=$(COVER_PACKAGES)
go tool cover -func=coverage.out
@echo "Coverage profile written to coverage.out"
test-integration: build-test-binary build-test-budget
@echo "Running integration tests (time-budgeted)..."
$(TEST_BUDGET_BINARY) -suite integration -stale -- go test -tags integration ./tests/integration/... -json -timeout 30m
test-integration-ci: build-test-binary build-test-budget
@echo "Running integration tests (CI mode, time-budgeted)..."
$(TEST_BUDGET_BINARY) -suite integration -stale -- go test -tags integration ./tests/integration/... -json -timeout 30m -parallel 4
test-frontend: font-check
@echo "Running frontend unit tests..."
node --test tests/frontend/*.test.mjs tests/frontend/preview/*.test.mjs
pnpm --dir desktop/frontend install --frozen-lockfile
pnpm --dir desktop/frontend typecheck
# Behaviour scenarios drive the real UI over raw CDP, so they need a Chrome
# binary; CHROME_BIN overrides the search.
CHROME_BIN ?= $(shell command -v google-chrome || command -v chromium || command -v chromium-browser || echo /opt/google/chrome/chrome)
test-frontend-behaviour:
@test -x "$(CHROME_BIN)" || (echo "behaviour tests need Chrome; set CHROME_BIN (tried $$(command -v google-chrome), chromium, /opt/google/chrome/chrome)" && exit 1)
CHROME_BIN="$(CHROME_BIN)" node --test --test-concurrency=1 tests/frontend/behaviour/*.behaviour.test.mjs
lint-install: ## Install golangci-lint if missing
@if ! command -v $(GOLANGCI_LINT_BIN) >/dev/null 2>&1 || ! $(GOLANGCI_LINT_BIN) version | grep -q $(GOLANGCI_LINT_VERSION); then \
echo "Installing golangci-lint $(GOLANGCI_LINT_VERSION)..."; \
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION); \
fi
lint: lint-install ## Run linter (synchronized with CI)
@echo "Running linter..."
$(GOLANGCI_LINT_BIN) run ./...
# lint-desktop vets and lints the files behind //go:build desktop (Wails
# adapter, tray, lifecycle), which the untagged vet/lint never compile. It
# needs the GTK4 / WebKitGTK 6.0 headers (libgtk-4-dev libwebkitgtk-6.0-dev).
lint-desktop: lint-install
@echo "Running go vet and golangci-lint on desktop-tagged code..."
go vet -tags desktop,production ./...
$(GOLANGCI_LINT_BIN) run --build-tags desktop,production ./...
fmt:
@echo "Formatting code..."
go fmt ./...
vet:
@echo "Running go vet..."
go vet ./...
clean: ## Remove build artifacts and clean test cache
@echo "Cleaning build artifacts..."
rm -rf $(BUILD_DIR)
go clean -testcache
images: ## Build Govard Docker images
@echo "Building Govard Docker Images..."
DOCKER_ORG=$(DOCKER_ORG) DOCKER_PLATFORMS="$(DOCKER_PLATFORMS)" $(DOCKER_BAKE) -f docker/docker-bake.hcl $(DOCKER_PLATFORM_FLAGS)
push: ## Push Govard Docker images as multi-arch manifests
@echo "Pushing Govard Docker Images for $(DOCKER_PLATFORMS)..."
DOCKER_ORG=$(DOCKER_ORG) DOCKER_PLATFORMS="$(DOCKER_PLATFORMS)" $(DOCKER_BAKE) -f docker/docker-bake.hcl $(DOCKER_PLATFORM_FLAGS) --push