Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
223 lines (178 loc) · 8.58 KB
/
Copy pathMakefile
File metadata and controls
223 lines (178 loc) · 8.58 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
SHELL := /bin/sh
GO ?= go
BIN := bin
# Tool versions are pinned so CI and every developer machine agree.
GOLANGCI_VERSION := v2.13.2
GOOSE_VERSION := v3.28.0
SQLC_VERSION := v1.31.1
TYGO_VERSION := v0.2.21
KUBECONFORM_VERSION := v0.7.0
ifeq ($(OS),Windows_NT)
RM_DIR = cmd //c "if exist $(1) rmdir /s /q $(1)"
else
RM_DIR = rm -rf $(1)
endif
POSTGRES_USER ?= tennis
POSTGRES_DB ?= tennis
# The go command walks into web/node_modules, which ships the odd vendored Go
# file inside an npm package, and it has no flag for skipping a directory.
# Evaluated inside the recipes that need it rather than on every make run.
GO_PACKAGES = $$($(GO) list ./... | grep -v '/web/node_modules/')
MIGRATIONS := ./migrations
# Matches the published compose port; 5432 is usually already taken.
DATABASE_URL ?= postgres://tennis:tennis@localhost:5433/tennis?sslmode=disable
# Exported so the cmd/ binaries see it; they read DATABASE_URL from the
# environment and every target below would otherwise need it passed by hand.
export DATABASE_URL
# Matches the published compose port. Unset it to run the API with no cache,
# which is a supported configuration and the one every test runs in.
REDIS_URL ?= redis://localhost:6380/0
export REDIS_URL
.DEFAULT_GOAL := help
## help: list available targets
help:
@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/## //' | awk -F':' '{printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}'
## up: start Postgres and Redis, wait until healthy
# Named explicitly: `docker compose up` also builds and runs the API and the
# frontend, which is the whole site but a slow inner loop for Go work.
up:
docker compose up -d --wait postgres redis
## site: build and run the whole stack, frontend included, on :5174
site:
docker compose up -d --build --wait
# Where CI publishes. Overridable so a fork builds under its own account.
IMAGE_PREFIX ?= ghcr.io/sami0076/tennis-wiki
## images: build the three published images locally and print their sizes
# CI builds these same three from these same files, and this is the target the
# sizes in docs/performance.md are measured with -- so it pins the platform CI
# publishes rather than taking the host's. On an Arm laptop the two differ.
IMAGE_BUILD = docker build --platform linux/amd64 --provenance=false
images:
$(IMAGE_BUILD) -f deploy/docker/api.Dockerfile -t $(IMAGE_PREFIX)/api:local .
$(IMAGE_BUILD) -f deploy/docker/tools.Dockerfile --build-arg GOOSE_VERSION=$(GOOSE_VERSION) -t $(IMAGE_PREFIX)/tools:local .
$(IMAGE_BUILD) -f web/Dockerfile -t $(IMAGE_PREFIX)/web:local ./web
@docker image ls $(IMAGE_PREFIX)/* --format '{{.Repository}} {{.Size}}'
## k8s-validate: check deploy/k8s against the Kubernetes schemas
# In a container, so this needs no local install, and pinned so CI and a
# developer machine disagree about nothing. The CRD catalogue covers the two
# kinds cert-manager and Traefik add; without it those are skipped silently
# rather than checked.
CRD_SCHEMAS = https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json
k8s-validate:
docker run --rm -v "$(CURDIR)":/repo -w /repo \
ghcr.io/yannh/kubeconform:$(KUBECONFORM_VERSION) \
-strict -summary -schema-location default -schema-location '$(CRD_SCHEMAS)' \
deploy/k8s/
## down: stop the stack, keeping data
down:
docker compose down
## reset: stop the stack and delete all data
reset:
docker compose down -v
## psql: open a shell on the database
psql:
docker compose exec postgres psql -U $(POSTGRES_USER) -d $(POSTGRES_DB)
## build: compile every binary into bin/
build:
$(GO) build -o $(BIN)/ ./cmd/...
# Only the two targets below use this. It is deliberately not exported: the
# tests start their own Postgres, and an exported default would silently point
# them at the compose stack instead.
TEST_DATABASE_URL ?= postgres://tennis:tennis@localhost:5433/tennis_test?sslmode=disable
## testdb: create a database for TEST_DATABASE_URL (optional; tests start their own)
testdb:
-docker compose exec -T postgres psql -U $(POSTGRES_USER) -d $(POSTGRES_DB) -c "CREATE DATABASE tennis_test"
$(MAKE) migrate-test
## migrate-test: apply migrations to the test database
# Split out of testdb because CI gets its database from a service container and
# so needs the migration step without the compose call above.
migrate-test:
$(GO) run github.com/pressly/goose/v3/cmd/goose@$(GOOSE_VERSION) -dir $(MIGRATIONS) postgres "$(TEST_DATABASE_URL)" up
## test: run the test suite
# Integration tests start their own Postgres per package via testcontainers, so
# they need Docker but no setup. Set TEST_DATABASE_URL to use a server you
# already have instead; the database must be named *test*.
test:
$(GO) test $(GO_PACKAGES)
## test-race: run the test suite with the race detector (used by CI)
# The race detector is unsupported on windows/arm64, so this is a separate
# target rather than the default. CI runs on linux/amd64 and always uses it.
test-race:
$(GO) test -race $(GO_PACKAGES)
## fmt: format and tidy
fmt:
$(GO) fmt $(GO_PACKAGES)
$(GO) mod tidy
## lint: run golangci-lint
lint:
$(GO) run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_VERSION) run
## migrate-up: apply all migrations
migrate-up:
$(GO) run github.com/pressly/goose/v3/cmd/goose@$(GOOSE_VERSION) -dir $(MIGRATIONS) postgres "$(DATABASE_URL)" up
## migrate-down: roll back one migration
migrate-down:
$(GO) run github.com/pressly/goose/v3/cmd/goose@$(GOOSE_VERSION) -dir $(MIGRATIONS) postgres "$(DATABASE_URL)" down
## migrate-reset: roll every migration back, dropping every table
migrate-reset:
$(GO) run github.com/pressly/goose/v3/cmd/goose@$(GOOSE_VERSION) -dir $(MIGRATIONS) postgres "$(DATABASE_URL)" down-to 0
## sqlc: regenerate typed queries from migrations
sqlc:
$(GO) run github.com/sqlc-dev/sqlc/cmd/sqlc@$(SQLC_VERSION) generate
## seed: start the stack, migrate, load the seed fixture and rate it
# `rate` is part of seeding, not an extra step. Ingest writes matches but no
# ratings, and a database with matches and no ratings is not a working site:
# the Elo leaderboard, every surface strip, the rating chart and both
# simulators read the ratings table, so all of them come up empty. That looks
# like a bug in the page rather than a stage nobody ran.
seed: up migrate-up ingest rate
## api: run the HTTP API on port 8080
api:
$(GO) run ./cmd/api
# The seasons the seed fixture covers. Narrowing the plan keeps the run quiet
# rather than reporting three hundred files the fixture was never going to have.
SEED_SEASONS := 1975,2015,2019,2026
## ingest: load the small seed fixture (fast, for local development)
ingest:
$(GO) run ./cmd/ingest --local-path ./testdata --seasons $(SEED_SEASONS)
## ingest-full: load the complete dataset (skips files unchanged since the last run)
ingest-full:
$(GO) run ./cmd/ingest
## ingest-force: as ingest-full, but re-read every file regardless
ingest-force:
$(GO) run ./cmd/ingest --force
## dataqual: report data-quality anomalies
dataqual:
$(GO) run ./cmd/dataqual
## prune: repair rows that predate a rule the ingest now enforces
prune:
$(GO) run ./cmd/ingest --stage prune
## rate: recompute Elo ratings from scratch over every match
rate:
$(GO) run ./cmd/rate
## web: run the frontend dev server against the local API
web:
cd web && npm install && npm run dev
## web-build: type-check, lint, test and build the frontend
web-build:
cd web && npm install && npm run typecheck && npm run lint && npm run test && npm run build
## web-types: regenerate the TypeScript types from the Go response structs
web-types:
$(GO) run github.com/gzuidhof/tygo@$(TYGO_VERSION) generate
## validate: report the rating-engine validation checks
# --weights configs/weights.json tries another tier weighting without a rebuild,
# which is the reason ADR-0004 made the weights configuration.
validate:
$(GO) run ./cmd/validate
## validation-json: refresh docs/validation.json, the run the methodology page quotes
# Bigger samples than the defaults, because these figures are published: 30,000
# matches and 300 draws is the run the methodology document was written against.
validation-json:
$(GO) run ./cmd/validate -json -simulation-matches 30000 -simulation-events 300 > docs/validation.json
## clean: remove build artefacts
clean:
$(call RM_DIR,$(BIN))
.PHONY: help up down reset psql testdb migrate-test build test test-race fmt lint migrate-up migrate-down migrate-reset sqlc seed api ingest ingest-full ingest-force prune dataqual rate validate validation-json site images k8s-validate web web-build web-types clean
# print-VAR: echo a make variable, so CI can read the pinned tool versions
# from here rather than duplicating them in a workflow file.
print-%:
@echo $($*)