-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
239 lines (218 loc) · 11 KB
/
Copy pathMakefile
File metadata and controls
239 lines (218 loc) · 11 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
# TrustedOSS Portal — operator make targets.
#
# Thin wrappers around docker-compose for routine dev-stack operations.
# Targets are grouped:
# dev-up / dev-down — bring the stack up / down
# dev-rebuild-worker — recover from a stale worker image
# dev-reset — destroy + recreate (delegates to script)
# dev-logs / dev-ps — tail logs / list services
#
# Required: docker-compose V1 (hyphen). CLAUDE.md core rule #10.
COMPOSE := docker-compose -f docker-compose.dev.yml
WORKER := celery-worker
FRONTEND_DIR := apps/frontend
SCREENSHOT_DIR := docs-site/static/img/screenshots
SCREENSHOT_STAGING := $(SCREENSHOT_DIR)/staging
WALKTHROUGH_DIR := docs-site/static/img/walkthroughs
WALKTHROUGH_RAW := apps/frontend/tests/walkthroughs/.output
.DEFAULT_GOAL := help
.PHONY: help
help:
@echo "TrustedOSS Portal — dev-stack targets"
@echo " make dev-up bring up the dev stack (detached)"
@echo " make dev-down stop the dev stack (preserves volumes)"
@echo " make dev-rebuild-worker rebuild celery-worker --no-cache + force-recreate"
@echo " make dev-reset scripts/dev-reset.sh (destroys volumes!)"
@echo " make dev-reset-rebuild dev-reset + worker rebuild + e2e seed"
@echo " make dev-logs tail backend + worker logs"
@echo " make dev-ps list service health"
@echo ""
@echo "Static checks (CI's lint / typecheck / shellcheck jobs, NOT the tests)"
@echo " make static-checks every static check CI runs"
@echo " make static-checks-backend ruff + mypy + ai-review selftest ONLY"
@echo " make static-checks-frontend eslint, tsc, i18n, tokens, repo linters ONLY"
@echo " make static-checks-scripts shellcheck ONLY"
@echo " green here is not a green CI: the test,"
@echo " e2e and build jobs are out of scope"
@echo ""
@echo "Guide screenshot capture (Playwright)"
@echo " make screenshots-capture regenerate guide PNGs via tests/screenshots/"
@echo " make screenshots-clean remove staging captures (keeps committed assets)"
@echo ""
@echo "Animated walkthroughs (Playwright + ffmpeg)"
@echo " make walkthroughs-capture record webm via tests/walkthroughs/"
@echo " make walkthroughs-encode convert webm to mp4 + gif under $(WALKTHROUGH_DIR)/"
# ER62: one entry point for CI's STATIC checks, so nobody has to decide per
# change which of them are worth running. Deciding by the shape of a change is
# how a test-only edit skips mypy.
#
# Named "static-checks" and not "local CI" on purpose. It runs the lint,
# typecheck and shellcheck jobs; the test, e2e, coverage and build jobs need a
# database, browsers or an image and are out of scope. A name promising CI
# would invite the surprise this exists to prevent.
#
# The command list lives in tools/static-checks/run.py and is compared against
# .github/workflows/ci.yml by tests/unit/test_static_checks_match_ci.py, which
# also asserts every job in that workflow is either covered or excluded with a
# reason. It cannot fall behind CI without a test failing.
#
# A missing tool FAILS rather than being skipped: a run that quietly covered
# less than it appears to and still ended green would be worse than no target.
.PHONY: static-checks
static-checks:
@python3 tools/static-checks/run.py --scope all
# Named for their scope. Passing one of these is not passing even the static
# checks, and the runner says so on its last line.
.PHONY: static-checks-backend
static-checks-backend:
@python3 tools/static-checks/run.py --scope backend
.PHONY: static-checks-frontend
static-checks-frontend:
@python3 tools/static-checks/run.py --scope frontend
.PHONY: static-checks-scripts
static-checks-scripts:
@python3 tools/static-checks/run.py --scope scripts
.PHONY: dev-up
dev-up:
$(COMPOSE) up -d
.PHONY: dev-down
dev-down:
$(COMPOSE) down
.PHONY: dev-rebuild-worker
dev-rebuild-worker:
$(COMPOSE) build --no-cache $(WORKER)
$(COMPOSE) up -d --force-recreate $(WORKER)
.PHONY: dev-reset
dev-reset:
bash scripts/dev-reset.sh
.PHONY: dev-reset-rebuild
dev-reset-rebuild:
bash scripts/dev-reset.sh --rebuild-worker --seed --no-prompt
.PHONY: dev-logs
dev-logs:
$(COMPOSE) logs -f backend $(WORKER)
.PHONY: dev-ps
dev-ps:
$(COMPOSE) ps
# ────────────────────────────────────────────────────────────────────
# Guide screenshot capture
#
# Drives `tests/screenshots/capture.spec.ts` via the dedicated Playwright
# config (`playwright.screenshots.config.ts`) so the e2e CI matrix never
# triggers a capture run accidentally. Output PNGs land directly under
# `$(SCREENSHOT_DIR)/` so the EN + KO Markdown share a single asset via
# the absolute `/img/screenshots/<file>.png` reference.
#
# Pre-requisites:
# - docker-compose dev stack healthy (the SPA must render against the
# real backend; `make dev-up` is enough for fresh stacks).
# - python3 on PATH for the seed helper (apps/frontend/tests/_harness/seed.ts).
#
# NOT the way to refresh what ships (R1-7). Capture the committed assets on
# CI:
#
# gh workflow run ui-gates.yml --ref <branch> -f capture_screenshots=true
# gh run download <id> -n doc-screenshots
#
# The runner seeds from an empty database. A developer's stack carries every
# project any previous run created, and capturing there put "APPROVALS
# WAITING 213" and ten seeded project names into the user guide. This target
# stays for checking a single screen while working on it — look at what it
# produces, do not commit it.
# ────────────────────────────────────────────────────────────────────
.PHONY: screenshots-capture
screenshots-capture:
cd $(FRONTEND_DIR) && npx playwright test --config=playwright.screenshots.config.ts
.PHONY: screenshots-clean
screenshots-clean:
rm -rf $(SCREENSHOT_STAGING)
@echo "removed $(SCREENSHOT_STAGING) (committed assets under $(SCREENSHOT_DIR) untouched)"
# Marathon bundle 9 (4f) — PNG compression automation.
# Runs oxipng (lossless) followed by pngquant (perceptual lossy quant).
# pngquant before oxipng would inflate the file; oxipng before pngquant
# loses oxipng's DEFLATE pass on the post-quant bitstream — pngquant
# pipes to oxipng in one shot for the optimal size.
#
# Tools are installed in a tiny Alpine container so operators do not
# have to apt/brew install on the host. The container mounts the
# screenshot dir read-write; processed files replace originals
# in-place. Idempotent — re-running after a clean capture saves a few
# more bytes from any pixel-noise drift.
#
# Quality:
# - oxipng -o 4 — exhaustive level 4 (vs the brutal -o max
# which costs minutes for ~5% extra savings).
# - pngquant 75-90 — quality floor 75, ceiling 90; the -- forces
# output to stdout so we can pipe to oxipng.
# No --skip-if-larger; we accept marginal
# "no-shrinkage" PNGs to keep the runner
# simple (the size-gate workflow catches
# regressions overall, not per-file).
# The `-s` guard on the temp file is not defensive programming — the `&&`
# chain it replaced destroyed all 44 assets. `> "$f.tmp"` succeeds whether
# or not the pipeline behind it wrote anything, so a failing oxipng left an
# empty file that `mv` then moved over the original. Every screenshot became
# 0 bytes, and the recipe reported "-> 0 (0%)" for each one as though that
# were a compression ratio.
#
# G0-5 — `--stdout`, not `--out -`. oxipng has no convention that `-` means
# standard output: it took the argument as a literal filename, wrote the
# optimized bytes into a file called `-`, and left its actual stdout empty.
# The `-s` guard above then did its job and kept every original, so the target
# was a no-op that reported "-> same size" on all 44 files while quietly
# leaving a `screenshots/-` artifact behind. The flag it wanted all along is
# `--stdout` (oxipng 9.x). With it the pipeline compresses as designed:
# 128,443 -> 38,988 bytes on the first asset measured, and no stray file.
.PHONY: screenshots-optimize
screenshots-optimize:
@docker run --rm -v $(PWD)/$(SCREENSHOT_DIR):/work alpine:3.20 \
sh -c 'apk add --no-cache oxipng pngquant >/dev/null && \
cd /work && \
for f in *.png; do \
[ -f "$$f" ] || continue; \
orig=$$(wc -c < "$$f"); \
pngquant --quality=75-90 --speed 1 --force --output - "$$f" 2>/dev/null \
| oxipng -o 4 --strip safe - --stdout > "$$f.tmp" 2>/dev/null; \
if [ -s "$$f.tmp" ]; then mv "$$f.tmp" "$$f"; else rm -f "$$f.tmp"; fi; \
after=$$(wc -c < "$$f"); \
printf "%-55s %8d -> %8d (%d%%)\n" "$$f" "$$orig" "$$after" "$$((after * 100 / orig))"; \
done'
@echo
@# Single quotes, not backticks. Backticks in a recipe are command
@# substitution: this line used to RUN `git diff --stat` and, worse,
@# `make screenshots-capture` — so optimising the assets silently
@# recaptured them from the local database, overwriting a set that had
@# just been pulled from CI. The message said "re-run if you suspect a
@# regression" while re-running unconditionally.
@echo "screenshots-optimize done. Review with 'git diff --stat'. Re-run 'make screenshots-capture' if visual regression is suspected."
# Marathon bundle 9 (4c) — Animated walkthroughs.
#
# Two-step pipeline:
# 1. ``walkthroughs-capture`` — runs the dedicated Playwright config
# that records each spec as a webm (1440x900, video=on).
# 2. ``walkthroughs-encode`` — postprocesses the webm files into
# mp4 (h264 baseline, ~700kbps, suitable for the docs <video>
# tag) + a low-FPS gif preview (24fps -> 12fps decimate, palette
# generation for sub-2MB output).
#
# Why two targets and not one: capture runs against the dev stack and
# may need re-runs while iterating on the user flow. Encode is purely
# CPU-bound and benefits from caching across iterations once the
# webm is captured cleanly. Splitting also lets CI run encode-only
# on artifact uploaded by an operator (no headless browser needed).
#
# The encode step pairs each spec's webm with the slug declared in
# the spec via ``test.info().annotations.push({type: "slug", ...})``.
# The slug lives in ``test-results.json`` next to the video. We avoid
# the brittle dance with Playwright's auto-generated test-output
# directory names — slug-driven naming is stable across spec renames.
.PHONY: walkthroughs-capture
walkthroughs-capture:
cd $(FRONTEND_DIR) && npx playwright test --config=playwright.walkthroughs.config.ts
.PHONY: walkthroughs-encode
walkthroughs-encode:
@bash scripts/encode-walkthroughs.sh "$(WALKTHROUGH_RAW)" "$(WALKTHROUGH_DIR)"
.PHONY: walkthroughs-clean
walkthroughs-clean:
rm -rf $(WALKTHROUGH_RAW)
@echo "removed $(WALKTHROUGH_RAW) (committed assets under $(WALKTHROUGH_DIR) untouched)"