From c912388ed68da163218e527ee56069c8ce2e85de Mon Sep 17 00:00:00 2001 From: stroblme Date: Fri, 21 Aug 2026 14:34:14 +0200 Subject: [PATCH] Make lint report instead of rewriting, and stop verify guessing the domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `make lint-frontend` was `biome check --write --unsafe ./` — a lint target that reformatted the whole tree rather than checking it, which is why every parallel change in this repo has had to work around it. `lint` checks now and a new `format` writes. The pre-commit hook and CI needed no edit at all: both call `bun run lint`, so they became checks the moment its meaning changed. `app/Makefile` assigned DOMAIN from .env, and a plain assignment beats an inherited environment variable and is not exported — so `cd app && make dev-local` served localhost while the same checkout's tests targeted the configured domain. `export DOMAIN ?=` gives the lattice that was intended: command line, then environment, then .env. Alongside: the backend's htmlcov bind mount created that directory as root, so `make test-backend` died on the coverage step after every test had passed, which reads like a test failure and is not one. The alerts screen's copy of ALERTING_EVENTS is now checked by a test rather than trusted. And the shard comment claimed two spec files where there are nine. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Uq8mtNb97A7praJLyeEYgs --- .gitea/workflows/playwright.yml | 7 ++++--- Makefile | 7 +++++-- backend/tests/flow/test_alerts.py | 17 +++++++++++++++++ development.md | 21 ++++++++++++--------- docker/compose.dev.yml | 1 - frontend/package.json | 3 ++- frontend/src/routes/_layout/alerts.tsx | 7 ++++--- package.json | 1 + scripts/generate-client.sh | 2 +- 9 files changed, 46 insertions(+), 20 deletions(-) diff --git a/.gitea/workflows/playwright.yml b/.gitea/workflows/playwright.yml index bda9934..4c6bc25 100644 --- a/.gitea/workflows/playwright.yml +++ b/.gitea/workflows/playwright.yml @@ -37,9 +37,10 @@ jobs: strategy: fail-fast: false matrix: - # Two spec files (tests/flows.spec.ts, tests/admin.spec.ts) plus - # tests/auth.setup.ts, which every shard reruns as its setup project. - # More shards than that would only pay container startup twice over. + # Nine spec files under tests/, plus tests/auth.setup.ts, which every + # shard reruns as its setup project. Split two ways: each shard pays a + # full compose stack's startup, so more of them would spend more time + # booting than testing. shardIndex: [1, 2] shardTotal: [2] env: diff --git a/Makefile b/Makefile index 24effbc..b9a38b1 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ .PHONY: dev-utils dev dev-local up down update install dev-backend dev-frontend \ generate-client seed-example seed-demo seed-house seed-aircon seed-hosted-demo test test-backend test-frontend soak bench-startup lint lint-backend \ - lint-frontend umami clean help + lint-frontend format-frontend umami clean help COMPOSE_ROOT := $(CURDIR) # Explicit project name keeps this stack isolated from the sibling website @@ -133,7 +133,7 @@ test-backend: ## Run backend tests (pytest + coverage) # deployment carries the deployment's domain, and *.fluksio.com resolves to the # live instance from here — which is why the run below maps both names onto the # local Traefik by address and never lets DNS decide. -DOMAIN = $(shell sed -n 's/^DOMAIN=//p' $(COMPOSE_ROOT)/.env | head -1) +export DOMAIN ?= $(shell sed -n 's/^DOMAIN=//p' $(COMPOSE_ROOT)/.env | head -1) PW_VERSION = $(shell sed -n 's/.*"@playwright\/test": "[^0-9]*\([0-9.]*\)".*/\1/p' frontend/package.json | head -1) test-frontend: ## Run frontend tests (Playwright e2e) against the local stack @@ -174,6 +174,9 @@ lint-backend: ## Lint backend with ruff + mypy lint-frontend: ## Lint frontend with biome cd frontend && bun run lint +format-frontend: ## Apply biome's fixes to the frontend (what `lint-frontend` only reports) + cd frontend && bun run format + # ── Cleanup ─────────────────────────────────────────────────────── clean: ## Remove build artifacts and caches diff --git a/backend/tests/flow/test_alerts.py b/backend/tests/flow/test_alerts.py index 20d03bf..2197073 100644 --- a/backend/tests/flow/test_alerts.py +++ b/backend/tests/flow/test_alerts.py @@ -1,10 +1,13 @@ """Alerting: failing loudly once, not thirty-six thousand times.""" import asyncio +import re +from pathlib import Path import pytest from app.flow.alerts import ( + ALERTING_EVENTS, FLAP_THRESHOLD, RATE_LIMIT, Alert, @@ -230,3 +233,17 @@ def test_a_dashboard_channel_without_a_message_says_so(): asyncio.run( alerts.send(channel, Alert(title="t", body="b"), raise_on_error=True) ) + + +ALERTS_ROUTE = Path(__file__).parents[3] / "frontend/src/routes/_layout/alerts.tsx" + + +@pytest.mark.skipif(not ALERTS_ROUTE.exists(), reason="no frontend in this checkout") +def test_the_alerts_screen_offers_every_alerting_event(): + """The chooser lists the events by hand, so it can drift out of this set. + + Only the ids have to agree — the labels beside them are UI copy. + """ + block = re.search(r"const EVENTS[^=]*= \[(.*?)\n\]", ALERTS_ROUTE.read_text(), re.S) + assert block, "the EVENTS list moved — this test needs following" + assert set(re.findall(r'\["(\w+)"', block.group(1))) == ALERTING_EVENTS diff --git a/development.md b/development.md index 07fd33a..fe68ff6 100644 --- a/development.md +++ b/development.md @@ -14,9 +14,9 @@ SPA, the API and the marketing site answer on one port. `make status` lists the `make down` stops everything. The hostname comes from `DOMAIN` in `app/.env`, which `scripts/setup.sh` copies out of the -root `.env` — change it there and re-run `make init`. `make dev DOMAIN=…` at the root does -*not* reach this stack: `app/Makefile` assigns `DOMAIN` from `app/.env`, and a makefile -assignment overrides an inherited environment variable. +root `.env` — change it there and re-run `make init`. `app/Makefile` takes that value as a +default only (`export DOMAIN ?= …`), so `make dev DOMAIN=…` overrides it and the override +reaches the recipes. **App only.** `cd app && make dev` starts this stack on its own Traefik with all host ports published, in the foreground. `make dev-utils` starts just db, adminer, proxy, mailcatcher @@ -145,15 +145,18 @@ run when either origin resolves outside loopback or the private ranges, because creates and deletes flows, dashboards and users. `PLAYWRIGHT_ALLOW_PUBLIC=1` overrides it. **Visual check.** From the root, `make verify` logs in and screenshots both themes into -`app/frontend/screenshots/{light,dark}/`; `make verify-docker` does the same from the -Playwright container when the host lacks the browser libraries. Both default to `localhost` -rather than reading `.env`, so on a checkout configured for a deployment name the domain the -stack actually serves: `make verify DOMAIN=example.com`. +`app/frontend/screenshots/{light,dark}/`. It is an alias for `make verify-docker`: the run +always happens in the Playwright container, which pins the browser by reading +`frontend/package.json`. Running Playwright on the host is unsupported — the workspace pins a +browser revision whose install is incomplete. The domain comes from `.env`, and +`make verify DOMAIN=example.com` still wins. ## Lint, hooks and the generated client -`make lint` runs ruff, mypy and biome. `make hooks` at the root installs the pre-commit -hooks in both stacks; `.pre-commit-config.yaml` holds them. One is worth knowing about: +`make lint` runs ruff, mypy and biome, and only reports — it is what the pre-commit hook and +CI run, so neither rewrites the tree. `make format-frontend` is the writing half, applying +biome's fixes. `make hooks` at the root installs the pre-commit hooks in both stacks; +`.pre-commit-config.yaml` holds them. One is worth knowing about: `generate-frontend-sdk` regenerates the SPA's API client from the backend's OpenAPI schema whenever anything under `backend/` changes, so a route change reaches the frontend without being asked. `make generate-client` forces it. diff --git a/docker/compose.dev.yml b/docker/compose.dev.yml index cfc535a..384bfe2 100644 --- a/docker/compose.dev.yml +++ b/docker/compose.dev.yml @@ -105,7 +105,6 @@ services: - path: ../backend/pyproject.toml action: rebuild volumes: - - ../backend/htmlcov:/app/backend/htmlcov # What makes --reload above mean anything in the detached flow (`make dev`, # `make dev-local`): it starts the stack with `up -d`, which never runs the # sync above — only `docker compose watch` does. Without the mount the diff --git a/frontend/package.json b/frontend/package.json index 94e2fb1..a34b216 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,8 @@ "scripts": { "dev": "vite", "build": "tsc -p tsconfig.build.json && vite build", - "lint": "biome check --write --unsafe --no-errors-on-unmatched --files-ignore-unknown=true ./", + "lint": "biome check --no-errors-on-unmatched --files-ignore-unknown=true ./", + "format": "biome check --write --unsafe --no-errors-on-unmatched --files-ignore-unknown=true ./", "preview": "vite preview", "generate-client": "openapi-ts", "test": "bunx playwright test", diff --git a/frontend/src/routes/_layout/alerts.tsx b/frontend/src/routes/_layout/alerts.tsx index 1c00162..992187b 100644 --- a/frontend/src/routes/_layout/alerts.tsx +++ b/frontend/src/routes/_layout/alerts.tsx @@ -35,9 +35,10 @@ const alertsKey = ["alerts", "config"] const SECTION = "text-xs font-medium uppercase tracking-[0.5px] text-muted-foreground" -/** What the engine can alert on. Mirrors `ALERTING_EVENTS` in the backend; a - * rule with none of them ticked still covers everything, including any event - * added there later. */ +/** What the engine can alert on. Mirrors `ALERTING_EVENTS` in the backend, and + * `backend/tests/flow/test_alerts.py` reads this list to fail when the two + * drift apart. A rule with none of them ticked still covers everything, + * including any event added there later. */ const EVENTS: [string, string][] = [ ["node_error", "A node failed"], ["node_health", "A connection dropped"], diff --git a/package.json b/package.json index 4941f1e..83ac1d9 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "bun run --filter frontend dev", "lint": "bun run --filter frontend lint", + "format": "bun run --filter frontend format", "test": "bun run --filter frontend test", "test:ui": "bun run --filter frontend test:ui" } diff --git a/scripts/generate-client.sh b/scripts/generate-client.sh index dc7640b..9af6b63 100644 --- a/scripts/generate-client.sh +++ b/scripts/generate-client.sh @@ -8,4 +8,4 @@ uv run python -c "import app.main; import json; print(json.dumps(app.main.app.op cd .. mv openapi.json frontend/ bun run --filter frontend generate-client -bun run lint +bun run format