CI: cache the system packages Playwright dowloads for WebKit - #80846
Conversation
`npx playwright install --with-deps` downloads 114MB of Debian packages from the Ubuntu mirror. The mirror throttles that fetch often enough to stall an end-to-end job: recent runs on trunk took 14, 15, 17 and 56 minutes on the step, against a median of 48 seconds. Every one of those 200 packages belongs to WebKit. The runner image already satisfies Chromium and Firefox, so those jobs download nothing. Cache the packages through a composite action, and engage the cache only when the browser list includes WebKit. Install Chromium alone in the two jobs that never launch another browser: the RTC WebSocket suite matches no spec tagged `@webkit` or `@firefox`, and the Storybook test runner only launches Chromium.
|
👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @adimoldovan! In case you missed it, we'd love to have you join us in our Slack community. If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information. |
Cache entries are immutable, so `actions/cache` does not save again on an exact key hit. With a fixed key, any package that Ubuntu updates would be re-downloaded on every run until the runner image rotated. Put a fingerprint of the cached packages in the key and split the restore and save steps. The save step runs only when the package set changed, so an unchanged run uploads nothing and an updated one writes a new entry.
|
Flaky tests detected in 389a30e. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/30643720620
|
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
lancewillett
left a comment
There was a problem hiding this comment.
No blockers.
- Verified the composite action’s cache flow and workflow callers: a WebKit job restored the 109 MB package cache, while RTC and Storybook correctly skipped it for Chromium-only runs
AI use: gpt-5.6-sol
|
The Playwright documentation doesn't recommend caching browser binaries: https://playwright.dev/docs/ci#caching-browsers. |
@Mamaduka and this PR doesn't do that, which is already mentioned in PR the description, along with the same link. |
|
Sorry, somehow I missed that 🙇 |
Resolve storybook-check.yml against #81017, which moved the smoke-test deps into the storybook workspace: keep that workspace refactor, and install browsers through .github/setup-playwright with chromium only.
Sort the fingerprint under LC_ALL=C so collation cannot perturb the hash, and install only Chromium in the Storybook workspace's setup script, matching what CI installs and what the test runner launches. Document why the exact cache key never matches, and what apt does and does not verify about a cached package.
|
Size Change: 0 B Total Size: 7.78 MB |
lancewillett
left a comment
There was a problem hiding this comment.
No blockers found.
What I tested:
- Reviewed the changes since the prior approval.
- Confirmed Storybook and the composite action resolve Playwright 1.62.1.
- Confirmed all Playwright shards, RTC, Storybook smoke, actionlint, and Zizmor passed.
Adversarial review · gpt-5.6-sol
| env: | ||
| BROWSERS: ${{ inputs.browsers }} | ||
| run: | | ||
| VERSION="$(node -p "require('playwright-core/package.json').version")" |
There was a problem hiding this comment.
| sudo cp -r --update=none "$HOME/apt-cache/." /var/cache/apt/archives/ | ||
|
|
||
| # shellcheck disable=SC2086 # The browser list is intentionally split into separate arguments. | ||
| npx playwright install $BROWSERS --with-deps |
There was a problem hiding this comment.
For the same reason as #81017, we don't want to use npx in CI workflows for security reasons.
| BROWSERS_KEY="$(echo "${BROWSERS:-all}" | tr ' ' '-')" | ||
| # Packages cached under another runner image mostly miss. | ||
| IMAGE="${ImageOS:-unknown}-${ImageVersion:-unknown}" | ||
| echo "PREFIX=playwright-apt-${RUNNER_OS}-${RUNNER_ARCH}-${IMAGE}-${VERSION}-${BROWSERS_KEY}-" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
Also, it's better to add prefixes to the variables to make their end result readable in CI logs
For example, it currently outputs this
playwright-apt-Linux-X64-ubuntu24-20260720.247.2-1.62.1-chromium-firefox-webkit-afecb67c668a2145
From that string, it's difficult to understand what those numbers mean. I would expect it to be like this
"PREFIX=os-${RUNNER_OS}--arc-${RUNNER_ARCH}--img-${IMAGE}--playwright-${VERSION}--browsers-${BROWSERS_KEY}-"
which would result in
os-Linux-X64--arc-ubuntu24-20260720.247.2--playwright-1.62.1--browsers-chromium-firefox-webkit-afecb67c668a2145
What?
Cache the Debian packages that
npx playwright install --with-depsdownloads. Install only Chromium in the two jobs that never launch another browser.Why?
--with-depsfetches 114MB fromazure.archive.ubuntu.com, and the mirror sometimes throttles it. Across the last six runs on trunk (54 jobs) the step took a median of 48 seconds, but three jobs took 917s, 987s and 1072s, and one took 56 minutes:This buys reliability, not speed. A healthy run fetches the same 114MB at 53.8 MB/s, in two seconds, so the cache saves almost nothing on a good day.
All 200 packages belong to WebKit.
Playwright advises against caching browser binaries, because restoring the cache costs about as much as the download, and because the system dependencies "are not cacheable". These measurements agree on the first point, so this caches the apt layer instead. It does not contradict the second: apt still installs the packages on every run, which takes about 11 seconds of dpkg work that no cache can remove. Only the download is cached.
How?
.github/setup-playwrightcopies the cached packages into/var/cache/apt/archivesbefore installing, where apt finds them instead of downloading. The cache engages only when the browser list includes WebKit. Its key holds the runner OS and architecture,ImageOS,ImageVersion, theplaywright-coreversion, the browser list, and a fingerprint of the packages themselves.The action also gives the three workflows one place to install browsers, next to
.github/setup-node. Each one used to carry its own copy of the command, and each browser list now states what that job actually launches.The fingerprint keeps the cache fresh. A fixed key would go stale once a package is updated in apt. Instead, the save step runs only when the package set changed, writing a new entry and uploading nothing on an unchanged run.
install-depsstill runsapt-get update, so 10.9MB of package lists still come from the mirror. This cuts the exposure roughly tenfold, not to zero.Testing Instructions
Fetched 114 MB in ...line. This run seeds the cache.Use of AI Tools
Opus 5: the CI log analysis, the composite action, the workflow changes, and adversarial review.
Sol-5.6: review.