ci: add playwright-update.yml for branch snapshot regeneration#816
ci: add playwright-update.yml for branch snapshot regeneration#816arcjet-rei merged 2 commits intomainfrom
Conversation
Manual workflow_dispatch-triggered workflow that runs against the dispatched ref, regenerates Playwright snapshots, and pushes the result back to the branch. Resolves the cross-arch snapshot problem documented in ENG-715: the existing CONTRIBUTING.md procedure works for Linux x86_64 contributors but produces ~few-thousand-pixel divergence for Apple Silicon contributors because Chromium font rasterization differs between native amd64 and Rosetta-emulated amd64, even inside the multi-arch devcontainer. Running the regen on the CI runner eliminates the host-arch concern entirely. Behavior: - workflow_dispatch only; no auto-trigger. - Refuses to run against main (guard job exits 1 if github.ref == refs/heads/main). - Uses --update-snapshots=all so a deliberate dispatch always produces a full refresh rather than relying on Playwright's "changed" heuristic. - No-ops if no snapshot files changed. - Pushes via GITHUB_TOKEN with contents: write. Does not skip pre-receive hooks. - Commit message links back to the workflow run for traceability. - Note: GITHUB_TOKEN pushes do not retrigger downstream workflows; the existing Playwright tests workflow needs another push or manual re-run after this one commits. Closes ENG-715. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Arcjet Review — 🟡 Medium Risk
Decision: Approved
Rationale: Adds a new manual workflow to regenerate Playwright snapshots on a feature branch from CI. Triggers the ci-cd-changes escalation. The change is well-scoped, isolated to a new file, and uses defensive practices: workflow_dispatch only, an explicit guard job that refuses to run on main, pinned action SHAs, harden-runner with audit egress, set -euo pipefail in the push step, and contents:write scoped only to this workflow. The 'secret' ARCJET_KEY is intentionally a dummy value per the inline comment. No real credentials are introduced and no untrusted PR-controlled inputs are evaluated. Approving with one inline nit about commit-message body indentation.
Summary of Changes
Adds .github/workflows/playwright-update.yml — a manually-dispatched workflow that regenerates Playwright snapshots on the dispatched feature branch (refusing to run against main), runs npm ci + Playwright with --update-snapshots=all, and commits/pushes the result back via GITHUB_TOKEN.
Escalation Triggers
- CI/CD Pipeline: Adds a new GitHub Actions workflow file under .github/workflows/.
Notes
Workflow uses pinned action SHAs and harden-runner — good supply-chain hygiene. PR is small (~97 lines added) and well below the size threshold.
Review: 777ce902 | Powered by Arcjet Review
Really? If its multi-arch that is very surprising...here is from my docs devcontainer uname -m
aarch64 |
- Reject non-branch refs (`refs/tags/...`) in the guard job alongside the existing `main` check, so the push step's `refs/heads/` strip always has something to strip. - Switch the commit step from a single multi-line `-m` argument to multiple `-m` flags so the body lines aren't committed with the YAML's leading indentation preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@qw-in Yeah — The workflow sidesteps the whole question by running the regen on the GitHub-hosted runner, which is amd64 by definition. |
|
@arcjet-rei im happy to have the ci run for this as well but with the specific chrome configuration it has been a pixel perfect match for the last 6 months or so Claude is really bad about it and gets very concerned and confused but in practice it's pretty stable |
Summary
Adds
.github/workflows/playwright-update.yml— a manualworkflow_dispatch-triggered workflow that runs against the dispatched ref, regenerates Playwright snapshots, and pushes the result back to the branch.Why
The existing snapshot regeneration procedure in
CONTRIBUTING.md(npm run pw:run -- --update-snapshots=changed) works on Linux x86_64 hosts, including the devcontainer when the host is Linux x86_64. It silently underperforms on Apple Silicon: the devcontainer image (mcr.microsoft.com/devcontainers/javascript-node:24) is multi-arch, so it pulls arm64 on Apple Silicon, and Chromium font rasterization diverges from native amd64 — text-heavy pages overflow themaxDiffPixels: 100threshold even when the rendered HTML and thedist/artifact are byte-identical.PR #815 (ENG-711) hit this on
troubleshooting-{light,dark}snapshots (~4000px diff each) and had to pin the baselines to bytes downloaded from the failing CI run's blob report. That works but is not a procedure we want future contributors to rediscover. Running the regeneration on the CI runner eliminates the host-arch concern entirely — the runner is amd64 by definition, so its renders match what the regular Playwright test job produces on the same architecture.Closes ENG-715. Related: ENG-711 (#815).
Behavior
workflow_dispatchonly. No auto-trigger on PR comments, labels, or pushes.gh workflow run playwright-update.yml --ref rei/feat/some-branch.--update-snapshots=allso a deliberate dispatch always produces a full refresh rather than depending on Playwright's "changed" heuristic.guardjob refuses to run ifgithub.ref == 'refs/heads/main'to prevent accidental baseline mutation against the protected branch.GITHUB_TOKENwithcontents: writepermission. Does not skip pre-receive hooks.Known limitation
Pushes from
GITHUB_TOKENdo not retrigger downstream workflow runs. After this workflow commits new snapshots, the existingPlaywright testsworkflow will not re-run automatically — you'll need to push another commit (or rerun the checks manually) to verify the regenerated snapshots actually pass. Documented in a header comment on the workflow file.Test plan
gh workflow run playwright-update.yml --ref rei/test/intentional-sidebar-tweaktest: regenerate Playwright snapshots from CIcommit appears on that branch.mainand confirm theguardjob fails immediately.🤖 Generated with Claude Code