CI / changes (pull_request) Successful in 4s
CI / api (pull_request) Successful in 2m6s
CI / fast-checks (pull_request) Successful in 2m32s
CI / security (pull_request) Successful in 1m2s
CI / harness (pull_request) Successful in 5m36s
CI / gate (pull_request) Successful in 2s
100 lines
5.1 KiB
Markdown
100 lines
5.1 KiB
Markdown
---
|
|
quick_id: 260618-tg2
|
|
slug: persistent-ci-dependency-caches-pnpm-sto
|
|
description: Persistent CI dependency caches (pnpm store + Playwright browsers)
|
|
type: quick
|
|
created: 2026-06-19
|
|
files_modified:
|
|
- .gitea/workflows/ci.yml
|
|
- docs/DEVELOPMENT.md
|
|
- apps/api/Dockerfile
|
|
- .gitea/workflows/publish.yml
|
|
---
|
|
|
|
# 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:
|
|
```yaml
|
|
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-playwright` present 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-store` and `/ms-playwright`.
|
|
- These require the act_runner `config.yaml` `container.options` to 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 `.npmrc` registry 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]
|