5.1 KiB
quick_id, slug, description, type, created, files_modified
| quick_id | slug | description | type | created | files_modified | ||||
|---|---|---|---|---|---|---|---|---|---|
| 260618-tg2 | persistent-ci-dependency-caches-pnpm-sto | Persistent CI dependency caches (pnpm store + Playwright browsers) | quick | 2026-06-19 |
|
Quick Task 260618-tg2: Persistent CI dependency caches (pnpm store + Playwright)
Why
The Gitea runner re-downloads all deps every run: 4 jobs each run pnpm install --frozen-lockfile
cold (lines 54/110/197/478), and the harness job re-downloads Playwright browser binaries every
run (line 275). The runner is long-lived Docker-on-Unraid, so persisting these via host bind-mounts
(/pnpm-store, /ms-playwright, wired in the act_runner config.yaml container.options — a
separate manual host change) eliminates the repeat downloads. This avoids actions/cache@v4, which
the Phase-8 runner probe found times out on this runner (D-PROBE-04).
Scope this task: the two CI caches only. Verdaccio (registry mirror) and the Dockerfile BuildKit cache mount are explicitly OUT of scope for now.
Tasks
Task 1 — pnpm store: point all CI installs at the persistent store
In .gitea/workflows/ci.yml, change each of the four install steps:
run: pnpm install --frozen-lockfile
→
run: pnpm install --frozen-lockfile --store-dir /pnpm-store --prefer-offline
Lines 54 (fast-checks), 110 (api), 197 (harness), 478 (security). --store-dir and
--prefer-offline are valid pnpm 11.5.1 install flags (verify with pnpm install --help).
Do NOT add store-dir to a repo .npmrc — local dev has no /pnpm-store.
Update the stale comment near line 51 (the "no cache backend / ~30s acceptable" note) to reflect
that installs now use the persistent host-mounted store.
- verify:
grep -c -- '--store-dir /pnpm-store --prefer-offline' .gitea/workflows/ci.yml→ 4 - done: all four installs use the persistent store; YAML still valid.
Task 2 — Playwright: persist browser binaries on the harness job
Add a job-level env: to the harness: job so every step (browser install + test run) resolves
the same persistent path:
harness:
runs-on: ubuntu-latest
env:
PLAYWRIGHT_BROWSERS_PATH: /ms-playwright
(If the harness job already has a job-level env: map, add the key to it rather than duplicating.)
Leave npx playwright install --with-deps webkit chromium (line 275) as-is — the binary download
is now cached by version; the --with-deps apt step can't persist (add a one-line comment noting
"baking a runner image with browsers preinstalled would also drop the --with-deps apt step" as a
future optimization).
- verify:
PLAYWRIGHT_BROWSERS_PATH: /ms-playwrightpresent under the harness job; the test-run step (PLAYWRIGHT_BASE_URL ~line 340) inherits it. - done: Playwright browsers persist across runs.
Task 3 — Document the host-mount dependency
Add a short subsection to docs/DEVELOPMENT.md (CI/runner area) noting:
- CI now uses persistent caches at container paths
/pnpm-storeand/ms-playwright. - These require the act_runner
config.yamlcontainer.optionsto bind-mount host dirs to those paths (host change, not in this repo). - Without the mounts CI still works — it just falls back to uncached (writes to an ephemeral dir).
- done: the host-side requirement is discoverable from the repo.
Constraints
- Must pass local gates before each commit:
format:check(prettier), eslint, YAML validity (yq or actionlint if available), typecheck (no TS touched, but run if cheap). - Job names and the required-check contexts (CI / fast-checks, CI / api, CI / harness, CI / security, CI / gate) MUST stay identical so branch protection still matches. Do not rename jobs or restructure the job graph.
- Atomic commits (Task 1, Task 2, Task 3 may be one or separate commits — keep changes coherent).
Task 4 — Dockerfile BuildKit pnpm-store cache (added mid-task per user request)
apps/api/Dockerfile: add # syntax=docker/dockerfile:1 (line 1) and a BuildKit cache mount to
all three pnpm install stages (builder, pwa-builder, production):
RUN --mount=type=cache,target=/pnpm-store,id=pnpm-store,sharing=locked pnpm install ... --store-dir /pnpm-store.
sharing=locked because builder + pwa-builder run in parallel and would otherwise race the store.
.gitea/workflows/publish.yml: set DOCKER_BUILDKIT: '1' on the "Build production image" step so
the legacy builder can't break on the --mount syntax (BuildKit is default on Docker 23+; explicit
for safety).
- done: image build reuses a persistent BuildKit pnpm-store cache across builds.
OUT OF SCOPE (do not touch)
- Verdaccio / any
.npmrcregistry change (deferred — user will set up later).
must_haves
- truth: "All four ci.yml pnpm installs use --store-dir /pnpm-store --prefer-offline"
- truth: "The harness job sets PLAYWRIGHT_BROWSERS_PATH=/ms-playwright"
- truth: "ci.yml remains valid YAML with unchanged job names / required-check contexts"
- truth: "docs note the act_runner config.yaml host-mount requirement"
- artifacts: [.gitea/workflows/ci.yml, docs/DEVELOPMENT.md]