Makefile · 9787 bytes Raw Blame History
1 # shithub Makefile
2 # Targets mirror what CI runs. The Makefile is the source of truth.
3
4 .DEFAULT_GOAL := help
5 .PHONY: help dev build test test-race lint lint-policy lint-markdown lint-org-plan lint-secret-logs lint-spdx lint-unused lint-migrations verify-api-docs fmt tidy clean ci assets install-tools version deploy deploy-check restore-drill bench-staging docs docs-serve docs-verify gen-third-party-notices audit-a11y audit-a11y-pa11y audit-a11y-axe load-test
6
7 # Build metadata embedded into the binary via -ldflags.
8 VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
9 COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
10 BUILT := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
11 LDFLAGS := -X github.com/tenseleyFlow/shithub/internal/version.Version=$(VERSION) \
12 -X github.com/tenseleyFlow/shithub/internal/version.Commit=$(COMMIT) \
13 -X github.com/tenseleyFlow/shithub/internal/version.BuiltAt=$(BUILT)
14
15 GOFLAGS := -trimpath
16 BIN := bin/shithubd
17 RUNNER_BIN := bin/shithubd-runner
18
19 # Tools installed via 'go install' live in GOBIN (or GOPATH/bin). Reference
20 # them by absolute path so make recipes don't depend on PATH ordering.
21 GOBIN := $(shell go env GOBIN)
22 ifeq ($(GOBIN),)
23 GOBIN := $(shell go env GOPATH)/bin
24 endif
25 GOFUMPT := $(GOBIN)/gofumpt
26 GOIMPORTS := $(GOBIN)/goimports
27 AIR := $(GOBIN)/air
28
29 help: ## Show this help.
30 @awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*##/ {printf " %-20s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
31
32 dev: ## Run the web server with hot reload via air. Sources .env if present.
33 @if [ -f .env ]; then set -a; . ./.env; set +a; fi; $(AIR)
34
35 dev-migrate: ## Apply DB migrations against $$SHITHUB_DATABASE_URL (sources .env).
36 @if [ -f .env ]; then set -a; . ./.env; set +a; fi; \
37 go run ./cmd/shithubd migrate up
38
39 dev-run: ## Run the binary directly (no air); sources .env.
40 @if [ -f .env ]; then set -a; . ./.env; set +a; fi; \
41 go run ./cmd/shithubd web
42
43 build: ## Build shithubd and shithubd-runner into bin/.
44 @mkdir -p $(dir $(BIN)) $(dir $(RUNNER_BIN))
45 go build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BIN) ./cmd/shithubd
46 go build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(RUNNER_BIN) ./cmd/shithubd-runner
47
48 test: ## Run unit tests.
49 go test $(GOFLAGS) ./...
50
51 test-race: ## Run unit tests with the race detector.
52 go test $(GOFLAGS) -race ./...
53
54 lint: ## Run golangci-lint.
55 golangci-lint run
56
57 fmt: ## Format the codebase with gofumpt and goimports.
58 $(GOFUMPT) -l -w cmd internal pkg
59 $(GOIMPORTS) -local github.com/tenseleyFlow/shithub -w cmd internal pkg
60
61 tidy: ## Tidy go.mod / go.sum.
62 go mod tidy
63
64 clean: ## Remove build artifacts.
65 rm -rf bin tmp coverage.out
66
67 assets: ## Copy Primer CSS into internal/web/static/ for embedding.
68 @mkdir -p internal/web/static/primer
69 @if [ -d .refs/primer-css/dist ]; then \
70 cp -R .refs/primer-css/dist/* internal/web/static/primer/; \
71 else \
72 echo "warn: .refs/primer-css/dist not found; run 'git clone https://github.com/primer/css .refs/primer-css' first"; \
73 fi
74
75 ci: lint lint-policy lint-markdown lint-org-plan lint-secret-logs lint-spdx lint-unused lint-migrations verify-api-docs test build ## Full CI pipeline (matches .github/workflows/ci.yml).
76 @echo "ci: ok"
77
78 lint-policy: ## Enforce policy-package boundary (no inline auth checks in handlers/git/cmd).
79 @scripts/lint-policy-boundary.sh
80
81 lint-markdown: ## Enforce markdown-package boundary (no goldmark/bluemonday outside internal/markdown).
82 @scripts/lint-markdown-boundary.sh
83
84 lint-org-plan: ## Enforce paid org entitlement boundary (no direct orgs.plan feature gates).
85 @scripts/lint-org-plan-boundary.sh
86
87 lint-secret-logs: ## Fail when source emits log lines containing token-prefix patterns.
88 @scripts/lint-secret-logs.sh
89
90 lint-spdx: ## Verify every Go + shell source carries the SPDX license header.
91 @scripts/verify-spdx-headers.sh
92
93 lint-unused: ## Fail when source carries dead-code 'silence unused import' shims (var _ = symbol).
94 @scripts/lint-unused.sh
95
96 lint-migrations: ## Fail when goose migration numeric versions collide.
97 @scripts/lint-migration-versions.sh
98
99 verify-api-docs: ## Fail when an /api/v1 route in code is missing from docs/public/api/.
100 @scripts/verify-api-docs.sh
101
102 bench-small: ## Run the bench harness against $$BENCH_TARGET (default localhost:8080).
103 @go run ./bench -target=$${BENCH_TARGET:-http://localhost:8080} -iters=$${BENCH_ITERS:-20}
104
105 bench-full: ## Placeholder — runs nightly off-CI against big fixtures (see bench/fixtures/README.md).
106 @echo "bench-full: big-fixture generators land in a follow-up — see bench/fixtures/README.md"
107 @exit 0
108
109 install-tools: ## Install development tools via 'go install'.
110 go install mvdan.cc/gofumpt@latest
111 go install golang.org/x/tools/cmd/goimports@latest
112 go install github.com/air-verse/air@latest
113 go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
114
115 dev-db: ## Bring up Postgres in docker-compose.
116 docker compose up -d postgres
117 @echo "Waiting for postgres to become healthy..."
118 @until docker compose exec -T postgres pg_isready -U shithub -d shithub >/dev/null 2>&1; do sleep 1; done
119 @echo "Postgres ready at 127.0.0.1:5432"
120
121 dev-db-down: ## Stop the dev Postgres container.
122 docker compose down
123
124 dev-db-reset: ## Drop the dev Postgres volume and re-create.
125 docker compose down -v
126 $(MAKE) dev-db
127
128 dev-storage: ## Bring up MinIO + run minio-init to seed the bucket.
129 docker compose up -d minio
130 docker compose run --rm minio-init
131 @echo "MinIO S3 API: http://127.0.0.1:9000 console: http://127.0.0.1:9001"
132 @echo "Credentials: shithub-dev / shithub-dev-secret-please-change"
133
134 dev-storage-down: ## Stop the MinIO container (volume persists).
135 docker compose stop minio
136
137 dev-storage-reset: ## Drop the MinIO volume and re-seed.
138 docker compose down minio
139 docker volume rm -f shithub-miniodata
140 $(MAKE) dev-storage
141
142 storage-check: build ## Run shithubd storage check against the configured backend.
143 ./bin/shithubd storage check
144
145 dev-email: ## Bring up MailHog for local email capture (S05).
146 docker compose up -d mailhog
147 @echo "MailHog SMTP: 127.0.0.1:1025 web UI: http://127.0.0.1:8025"
148
149 dev-email-down: ## Stop MailHog.
150 docker compose stop mailhog
151
152 migrate-up: ## Apply all pending migrations.
153 ./bin/shithubd migrate up
154
155 migrate-down: ## Roll back the most recent migration.
156 ./bin/shithubd migrate down
157
158 migrate-status: ## Show migration status.
159 ./bin/shithubd migrate status
160
161 sqlc-generate: ## Regenerate sqlc Go code from queries.
162 $(GOBIN)/sqlc generate
163
164 test-integration: ## Run tests with SHITHUB_TEST_DATABASE_URL set against the dev Postgres.
165 SHITHUB_TEST_DATABASE_URL=$${SHITHUB_TEST_DATABASE_URL:-postgres://shithub:shithub_dev@127.0.0.1:5432/postgres?sslmode=disable} \
166 go test -trimpath ./...
167
168 version: ## Print version info that would be embedded into the binary.
169 @echo "Version: $(VERSION)"
170 @echo "Commit: $(COMMIT)"
171 @echo "Built: $(BUILT)"
172
173 # --- deploy ---
174 # Inventory selection: ANSIBLE_INVENTORY=production make deploy (default: staging).
175 ANSIBLE_INVENTORY ?= staging
176 ANSIBLE_TAGS ?=
177 ANSIBLE_LIMIT ?=
178
179 deploy-check: ## Dry-run the Ansible playbook (--check) against $$ANSIBLE_INVENTORY.
180 cd deploy/ansible && ansible-playbook -i inventory/$(ANSIBLE_INVENTORY) site.yml --check --diff \
181 $(if $(ANSIBLE_TAGS),--tags $(ANSIBLE_TAGS)) \
182 $(if $(ANSIBLE_LIMIT),--limit $(ANSIBLE_LIMIT))
183
184 deploy: ## Apply the Ansible playbook against $$ANSIBLE_INVENTORY (set to production for prod).
185 cd deploy/ansible && ansible-playbook -i inventory/$(ANSIBLE_INVENTORY) site.yml \
186 $(if $(ANSIBLE_TAGS),--tags $(ANSIBLE_TAGS)) \
187 $(if $(ANSIBLE_LIMIT),--limit $(ANSIBLE_LIMIT))
188
189 restore-drill: ## Run the restore drill on the backup host (must be run via ssh on that host).
190 deploy/restore-drill/run.sh
191
192 bench-staging: ## Run the bench harness against staging (BENCH_TARGET must be set to the staging URL).
193 @if [ -z "$$BENCH_TARGET" ]; then echo "set BENCH_TARGET=https://staging.shithub.example"; exit 2; fi
194 go run ./bench -target=$$BENCH_TARGET -iters=$${BENCH_ITERS:-50}
195
196 # --- docs ---
197 docs: ## Build the public docs site to build/docs/ via mdBook.
198 cd docs/public && mdbook build
199
200 docs-serve: ## Serve the public docs site locally on http://127.0.0.1:3000.
201 cd docs/public && mdbook serve --port 3000
202
203 docs-verify: verify-api-docs ## Verify docs are in sync (API routes documented + SPDX headers).
204 @$(MAKE) lint-spdx
205 @if command -v mdbook >/dev/null 2>&1; then \
206 cd docs/public && mdbook build >/dev/null && echo "mdbook build: ok"; \
207 else \
208 echo "mdbook not installed; skipping site build"; \
209 fi
210
211 gen-third-party-notices: ## Regenerate THIRD_PARTY_NOTICES.md from the active go.mod.
212 @scripts/gen-third-party-notices.sh > THIRD_PARTY_NOTICES.md
213 @echo "gen-third-party-notices: wrote THIRD_PARTY_NOTICES.md"
214
215 # --- S39 hardening ---
216 audit-a11y-pa11y: ## pa11y-ci scan of anonymous routes (needs running shithub on 127.0.0.1:8080).
217 @command -v pa11y-ci >/dev/null 2>&1 || { echo "pa11y-ci not installed; npm i -g pa11y-ci"; exit 2; }
218 pa11y-ci --config tests/a11y/pa11y-config.json
219
220 audit-a11y-axe: ## axe-core scan of authenticated routes (needs SHITHUB_USER + SHITHUB_PASS).
221 @command -v node >/dev/null 2>&1 || { echo "node not installed"; exit 2; }
222 node tests/a11y/axe-runner.js
223
224 audit-a11y: audit-a11y-pa11y audit-a11y-axe ## Run both accessibility scans.
225
226 load-test: ## Run a k6 scenario (set K6_SCENARIO=mixed-read|auth-mix|issue-comment-storm|search-load; default mixed-read).
227 @command -v k6 >/dev/null 2>&1 || { echo "k6 not installed; see https://k6.io/docs/getting-started/installation/"; exit 2; }
228 @if [ -z "$$BASE" ] && [ -z "$$BENCH_TARGET" ]; then echo "set BASE or BENCH_TARGET (e.g. https://staging.shithub.example)"; exit 2; fi
229 BASE="$${BASE:-$$BENCH_TARGET}" k6 run tests/load/k6/scenarios/$${K6_SCENARIO:-mixed-read}.js