From 45054db5e6cfb20eb9af796034ddc6797b3bb4bd Mon Sep 17 00:00:00 2001 From: lilleman Date: Sun, 2 Aug 2026 14:37:12 +0200 Subject: [PATCH 1/6] Build the web image in ci.sh so typecheck and tests run the branch's own deps --- ci.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index f78f8d2..dc7e096 100755 --- a/ci.sh +++ b/ci.sh @@ -40,11 +40,14 @@ pkg=$(grep -oE '"@playwright/test": "[0-9.]+"' e2e-tests/package.json | grep -oE [ -n "$img" ] && [ "$img" = "$pkg" ] || { echo "Playwright pin mismatch/unreadable: image v$img vs @playwright/test $pkg"; exit 1; } echo "ok ($img)" +# --build: without it a stale web image from a previous branch supplies node_modules (the +# source is bind-mounted but deps are baked in), so a dep bump gets typechecked/tested +# against the OLD packages. Cheap when deps are unchanged (npm ci layer is cache-keyed). step "Typecheck" -docker compose run --rm --no-deps web npm run typecheck +docker compose run --build --rm --no-deps web npm run typecheck step "Unit tests" -units=$(docker compose run --rm --no-deps web npm test 2>&1) || { echo "$units"; exit 1; } +units=$(docker compose run --build --rm --no-deps web npm test 2>&1) || { echo "$units"; exit 1; } echo "$units" | grep -E '^. (tests|pass|fail) ' || true # Sanity floor: catch a glob that matches too few files (a full empty glob already exits non-zero above). count=$(echo "$units" | grep -oE 'tests [0-9]+' | grep -oE '[0-9]+' | head -1 || true) From 9213e5a0de85238be051e8a956841c68ed7b1d93 Mon Sep 17 00:00:00 2001 From: lilleman Date: Sun, 2 Aug 2026 15:02:33 +0200 Subject: [PATCH 2/6] Make the CI web-image rebuild its own step; note the shared-workspace image-tag race --- AGENTS.md | 6 ++++-- ci.sh | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 27e305d..83b03c6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -89,8 +89,10 @@ them. Revisit only if the stated reason stops holding. - **CI docker logins share the runner host's Docker config.** The act_runner is host-mode, so `docker login`/`logout` in the workflows mutate one shared `~/.docker/config.json`: concurrent jobs can race (one job's logout can 401 another's push — recover by re-running), - and tokens sit in that file between login and logout. Accepted for a single-maintainer - cadence; serialize with a workflow `concurrency` group if it ever bites. + and tokens sit in that file between login and logout. Same class: concurrent runs share the + workspace dir, so ci.sh's web-image build races another run's container creation on the + `-web` tag. Accepted for a single-maintainer cadence; serialize with a workflow + `concurrency` group if it ever bites. ## Docker only — no host tooling diff --git a/ci.sh b/ci.sh index dc7e096..d82cc16 100755 --- a/ci.sh +++ b/ci.sh @@ -40,14 +40,17 @@ pkg=$(grep -oE '"@playwright/test": "[0-9.]+"' e2e-tests/package.json | grep -oE [ -n "$img" ] && [ "$img" = "$pkg" ] || { echo "Playwright pin mismatch/unreadable: image v$img vs @playwright/test $pkg"; exit 1; } echo "ok ($img)" -# --build: without it a stale web image from a previous branch supplies node_modules (the -# source is bind-mounted but deps are baked in), so a dep bump gets typechecked/tested +# Explicit rebuild: without it a stale web image from a previous branch supplies node_modules +# (the source is bind-mounted but deps are baked in), so a dep bump gets typechecked/tested # against the OLD packages. Cheap when deps are unchanged (npm ci layer is cache-keyed). +step "Build web image" +docker compose build web + step "Typecheck" -docker compose run --build --rm --no-deps web npm run typecheck +docker compose run --rm --no-deps web npm run typecheck step "Unit tests" -units=$(docker compose run --build --rm --no-deps web npm test 2>&1) || { echo "$units"; exit 1; } +units=$(docker compose run --rm --no-deps web npm test 2>&1) || { echo "$units"; exit 1; } echo "$units" | grep -E '^. (tests|pass|fail) ' || true # Sanity floor: catch a glob that matches too few files (a full empty glob already exits non-zero above). count=$(echo "$units" | grep -oE 'tests [0-9]+' | grep -oE '[0-9]+' | head -1 || true) From de2ad42f5a42e054c2a4bdd718c8d10f7201b8f5 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 2 Aug 2026 04:17:58 +0000 Subject: [PATCH 3/6] chore(deps): update playwright to v1.62.1 Release-Bump: minor --- e2e-tests/Dockerfile | 2 +- e2e-tests/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-tests/Dockerfile b/e2e-tests/Dockerfile index 14a94f1..40fae2a 100644 --- a/e2e-tests/Dockerfile +++ b/e2e-tests/Dockerfile @@ -1,6 +1,6 @@ # Playwright runner — browsers preinstalled, pinned to match @playwright/test in e2e-tests/. # Built/run via e2e-tests/compose.visual.yml; targets the `web` service over the network. -FROM mcr.microsoft.com/playwright:v1.49.1-noble +FROM mcr.microsoft.com/playwright:v1.62.1-noble WORKDIR /e2e-tests diff --git a/e2e-tests/package.json b/e2e-tests/package.json index 344d1de..ea57bb6 100644 --- a/e2e-tests/package.json +++ b/e2e-tests/package.json @@ -8,6 +8,6 @@ "test": "playwright test" }, "devDependencies": { - "@playwright/test": "1.49.1" + "@playwright/test": "1.62.1" } } From c64156a9d583efb4d2012d7002b0452a4d6cd57a Mon Sep 17 00:00:00 2001 From: lilleman Date: Sun, 2 Aug 2026 14:38:06 +0200 Subject: [PATCH 4/6] Update e2e-tests lockfile for @playwright/test 1.62.1 --- e2e-tests/package-lock.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/e2e-tests/package-lock.json b/e2e-tests/package-lock.json index 25c4d88..d458f47 100644 --- a/e2e-tests/package-lock.json +++ b/e2e-tests/package-lock.json @@ -8,23 +8,23 @@ "name": "plainpages-e2e", "version": "0.1.0", "devDependencies": { - "@playwright/test": "1.49.1" + "@playwright/test": "1.62.1" } }, "node_modules/@playwright/test": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", - "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.49.1" + "playwright": "1.62.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/fsevents": { @@ -43,35 +43,35 @@ } }, "node_modules/playwright": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", - "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.49.1" + "playwright-core": "1.62.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", - "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } } } From 62d4c8b7cdd77fba38ee017f2aaceb20b53e78c0 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 2 Aug 2026 04:18:02 +0000 Subject: [PATCH 5/6] fix(deps): update dependency lucide-static to v1.28.0 Release-Bump: minor --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7fafd4..9b6eef6 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "@larvit/log": "2.3.0", "ejs": "3.1.10", - "lucide-static": "1.18.0" + "lucide-static": "1.28.0" }, "devDependencies": { "@types/ejs": "3.1.5", From ffeec70f8fa339027e998ae5974e8818ac095a76 Mon Sep 17 00:00:00 2001 From: lilleman Date: Sun, 2 Aug 2026 14:34:45 +0200 Subject: [PATCH 6/6] Update lockfile and regenerate icons.ejs for lucide-static 1.28.0 --- package-lock.json | 8 ++++---- views/partials/icons.ejs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c8b9062..b497fac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@larvit/log": "2.3.0", "ejs": "3.1.10", - "lucide-static": "1.18.0" + "lucide-static": "1.28.0" }, "devDependencies": { "@types/ejs": "3.1.5", @@ -110,9 +110,9 @@ } }, "node_modules/lucide-static": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-1.18.0.tgz", - "integrity": "sha512-0WRXLQnjbte5SXuzom6yfeGlVSFsEsC9rzxn66DZN0pXows3+N34CQHy3BHI1qA3uH7u/SUzx8LQhjeAnxd8JQ==", + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-1.28.0.tgz", + "integrity": "sha512-dC3VJwRFsjEVX7Iaq4rY88pm7Fi2OmOb8P0WRzXsUMgbt7sCmFX8bLhaDBeNW6JdRjuele+jKqqFaam4yr+Ygg==", "license": "ISC" }, "node_modules/minimatch": { diff --git a/views/partials/icons.ejs b/views/partials/icons.ejs index c47c028..a446e21 100644 --- a/views/partials/icons.ejs +++ b/views/partials/icons.ejs @@ -4,7 +4,7 @@ - +