refactor(app): migrate App.vue to Pinia (47 commits — App 2211→72 code lines, + store tests/debt) #1284
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Browser E2E tests via Playwright. Separate from ci.yml because the | |
| # job needs Playwright's browser deps (~300 MB chromium runtime) and | |
| # is slower than the lint/unit tests — keeping it isolated means a | |
| # fast CI iteration if you don't touch frontend/. | |
| # | |
| # Workflow ALWAYS triggers (no `paths:` filter at the workflow level) | |
| # so the `playwright` context required by branch protection is always | |
| # reported. A `Detect e2e-relevant changes` step short-circuits the | |
| # heavy steps when nothing in frontend/, pkg/, *.go, or the OpenAPI | |
| # spec changed — docs-only and release-please PRs go green in ~10s | |
| # instead of leaving `playwright` stuck on "Expected — Waiting for | |
| # status to be reported". | |
| # | |
| # Mirrors the local `task test-e2e` recipe: | |
| # 1. build the frontend (Vite → frontend/dist) | |
| # 2. build the serveronly binary (//go:embed pulls in frontend/dist) | |
| # 3. install Playwright chromium with system deps | |
| # 4. run `npx playwright test` (Playwright's webServer block boots | |
| # the binary on :7099 with HOME=/tmp/recall-e2e for isolation) | |
| # | |
| # All ${{ }} expressions inside `run:` blocks go through env vars (the | |
| # PR_BODY-safe pattern); SHAs from `github.event.pull_request.base.sha` | |
| # / `github.event.before` / `github.sha` are validated to be 40-hex by | |
| # GitHub, but env-var passing is the conservative default. | |
| name: E2E | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| permissions: | |
| contents: read | |
| jobs: | |
| playwright: | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| # Full history so the path-detect step can diff against the | |
| # PR base / push-event predecessor. | |
| fetch-depth: 0 | |
| - name: Detect e2e-relevant changes | |
| id: changes | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| BEFORE_SHA: ${{ github.event.before }} | |
| HEAD_SHA: ${{ github.sha }} | |
| run: | | |
| set -eu | |
| # PR events: diff against base.sha. Push events: diff | |
| # against `before` (the previous tip of main). On a brand- | |
| # new branch or initial push, both can be empty / all-zeros | |
| # — fall back to HEAD~1 (or HEAD if even that's missing). | |
| base="" | |
| if [ -n "${BASE_SHA:-}" ]; then | |
| base="$BASE_SHA" | |
| elif [ -n "${BEFORE_SHA:-}" ] && [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then | |
| base="$BEFORE_SHA" | |
| else | |
| base="$(git rev-parse "${HEAD_SHA}^" 2>/dev/null || echo "$HEAD_SHA")" | |
| fi | |
| changed="$(git diff --name-only "${base}..${HEAD_SHA}" || true)" | |
| relevant=false | |
| if printf '%s\n' "$changed" | grep -qE '^(frontend/|pkg/|api/openapi\.yaml$|\.github/workflows/e2e\.yml$)|\.go$'; then | |
| relevant=true | |
| fi | |
| echo "relevant=$relevant" >> "$GITHUB_OUTPUT" | |
| if [ "$relevant" = "false" ]; then | |
| echo "::notice::No e2e-relevant changes (diff: ${base}..${HEAD_SHA}) — skipping Playwright, posting success." | |
| fi | |
| # go (build serveronly) + node (frontend build + Playwright) from | |
| # mise.toml's pins; also loads [env] (GOTOOLCHAIN=local, …). | |
| - uses: jdx/mise-action@dba19683ed58901619b14f395a24841710cb4925 # v4.1.0 | |
| if: steps.changes.outputs.relevant == 'true' | |
| with: | |
| install_args: go node | |
| - name: Install Tesseract (the parser shells out to it) | |
| if: steps.changes.outputs.relevant == 'true' | |
| # golden-parse.spec.ts drives the real OCR → parser → store pipeline (the | |
| # single biggest lever for Go integration coverage). The server | |
| # auto-detects tesseract via exec.LookPath, so it just needs to be on | |
| # PATH. No version-match gate here: the spec asserts loosely (a record was | |
| # produced), tolerant of OCR drift; golden-fidelity is enforced in ci.yml. | |
| run: | | |
| sudo apt-get update -y | |
| sudo apt-get install -y --no-install-recommends tesseract-ocr | |
| - name: Install frontend deps | |
| if: steps.changes.outputs.relevant == 'true' | |
| working-directory: frontend | |
| run: npm ci --no-audit --no-fund | |
| - name: Build frontend (instrumented for e2e coverage) | |
| if: steps.changes.outputs.relevant == 'true' | |
| working-directory: frontend | |
| # E2E_COVERAGE=1 emits inline source maps so monocart can remap the | |
| # browser's V8 coverage back to .ts/.vue source. Behaviour-neutral — | |
| # the suite still validates correctness exactly as before. | |
| env: | |
| E2E_COVERAGE: '1' | |
| run: npm run build | |
| - name: Build serveronly binary (coverage-instrumented) | |
| if: steps.changes.outputs.relevant == 'true' | |
| # `go build -cover` instruments the server so Playwright's HTTP traffic | |
| # produces Go integration coverage; counters flush to GOCOVERDIR on the | |
| # graceful SIGTERM shutdown Playwright's webServer sends on teardown. | |
| run: | | |
| mkdir -p /tmp/recall-e2e "${GITHUB_WORKSPACE}/coverage/e2e/go-covdata" | |
| go build -cover -coverpkg=./... -tags serveronly -o /tmp/recall-e2e/recall-server . | |
| - name: Install Playwright chromium + webkit (with system deps) | |
| if: steps.changes.outputs.relevant == 'true' | |
| working-directory: frontend | |
| # webkit = the macOS Wails WKWebView engine; the `webkit` project | |
| # (scoped to *-webkit.spec.ts) guards engine-specific regressions the | |
| # chromium suite can't see. See playwright.config.ts. | |
| run: npx playwright install --with-deps chromium webkit | |
| - name: Run Playwright E2E suite | |
| if: steps.changes.outputs.relevant == 'true' | |
| working-directory: frontend | |
| # E2E_COVERAGE + GOCOVERDIR turn on best-effort coverage collection | |
| # (V8 frontend coverage via monocart + Go binary coverage). Collection | |
| # is wrapped so it can never fail a test — the suite gates correctness, | |
| # not coverage. GOCOVERDIR must be absolute (the server's cwd differs). | |
| env: | |
| E2E_COVERAGE: '1' | |
| GOCOVERDIR: ${{ github.workspace }}/coverage/e2e/go-covdata | |
| run: npx playwright test | |
| # ── Integration coverage (informational; never gates merge) ────────── | |
| # Go: covdata → coverprofile → func/cobertura. Frontend lcov/cobertura | |
| # are produced by the Playwright globalTeardown (monocart). Both steps | |
| # continue-on-error so a coverage hiccup never reds the e2e job. | |
| - name: Build Go integration coverage report | |
| if: ${{ always() && steps.changes.outputs.relevant == 'true' }} | |
| continue-on-error: true | |
| run: | | |
| set -eu | |
| mkdir -p coverage/e2e/go | |
| go tool covdata textfmt -i="${GITHUB_WORKSPACE}/coverage/e2e/go-covdata" -o coverage/e2e/go/coverage.out | |
| go tool cover -func=coverage/e2e/go/coverage.out > coverage/e2e/go/coverage.txt | |
| go install github.com/boumenot/gocover-cobertura@latest | |
| # GOFLAGS=-tags=serveronly so gocover-cobertura's internal `go list` | |
| # sees the serveronly build-tag files (app_server.go, main_server.go) | |
| # that the instrumented binary — and thus the profile — include. | |
| GOFLAGS=-tags=serveronly gocover-cobertura < coverage/e2e/go/coverage.out > coverage/e2e/go/cobertura.xml | |
| - name: Write integration-coverage job summary | |
| if: ${{ always() && steps.changes.outputs.relevant == 'true' }} | |
| continue-on-error: true | |
| run: python3 scripts/ci/e2e-coverage-summary.py >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload Go integration coverage | |
| if: ${{ always() && steps.changes.outputs.relevant == 'true' }} | |
| continue-on-error: true | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: go-e2e-coverage | |
| path: coverage/e2e/go/ | |
| retention-days: 30 | |
| - name: Upload frontend integration coverage | |
| if: ${{ always() && steps.changes.outputs.relevant == 'true' }} | |
| continue-on-error: true | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: frontend-e2e-coverage | |
| path: coverage/e2e/frontend/ | |
| retention-days: 30 | |
| - name: Upload Playwright report on failure | |
| if: ${{ failure() && steps.changes.outputs.relevant == 'true' }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: playwright-report | |
| path: frontend/playwright-report/ | |
| retention-days: 7 |