Skip to content

Build/test tools: Cache the verified Gutenberg build across runs - #12702

Closed
lancewillett wants to merge 2 commits into
WordPress:trunkfrom
lancewillett:fix/gutenberg-download-cache
Closed

Build/test tools: Cache the verified Gutenberg build across runs#12702
lancewillett wants to merge 2 commits into
WordPress:trunkfrom
lancewillett:fix/gutenberg-download-cache

Conversation

@lancewillett

@lancewillett lancewillett commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Trac ticket: https://core.trac.wordpress.org/ticket/65721

Second of two changes on this ticket, and it builds on #12701. Because a cross-repo pull request can only target a branch that exists here, this one is opened against trunk, so its diff carries the download-once commit as well. Review only the second commit, "Cache the verified Gutenberg build across runs." Once #12701 lands, this branch reduces to that single commit.

Summary

Cache the verified Gutenberg archive across runs.

  • Key the cache on the immutable source SHA plus the blob SHA-256.
  • Re-verify (SHA-256 and size) on every restore and fail closed on a mismatch.
  • Resolve fresh metadata before every restore, so the cache can never select which build version is used.
  • Write the cache only from protected-branch pushes; pull requests and forks restore only.

Why

Downloading once per run cut the registry fetches from every matrix job to one. Caching removes even that fetch on a warm hit, which keeps a flaky external registry off the hot path entirely rather than just narrowing the window.

Two safety properties are worth calling out. The cache is keyed on content, not on a branch or a date, so a restore either matches the exact archive the metadata asked for or is rejected. And because metadata resolves first, a stale entry can never pin CI to an old Gutenberg build. Restricting writes to protected-branch pushes keeps untrusted pull requests out of a cache that trusted runs read.

Follow up to the Gutenberg artifact-fetching work in #64393 on Trac.

Testing

  • actionlint passes on the reusable workflow.
  • Unit tests cover cache-hit verification, mismatch rejection, and the metadata-before-restore ordering. Run with npm run test:tools.

Note on overlap with #12700

That pull request and this one both add tools/gutenberg/tests/download.test.js from scratch and both add a test:tools script to package.json, so they conflict with each other. Suggested order is to land #12700 first; this branch then rebases so its cache tests extend that file rather than replace it. Happy to do that rebase whenever it suits the review order.

Related

Stacked on the download-once change (#12701); both are Trac https://core.trac.wordpress.org/ticket/65721. This reimplements bounded download retries as part of the refactor, so it supersedes the interim retry fix (#12700, Trac https://core.trac.wordpress.org/ticket/65720). Suggested order: #12700, then #12701, then this; on the overlapping files keep this branch's version.

Each matrix job independently streams the same ~36 MB Gutenberg archive from
the GitHub Container Registry, so any one flaky stream can redden a run. Add a
prepare-gutenberg reusable workflow that fetches and verifies the build once
(SHA-256 and size) and uploads it as a run artifact; every PHPUnit caller
consumes the shared artifact and no longer contacts the registry. The prep job
runs only when a consumer runs. Test coverage is unchanged.

See #65721.

Props lance.willett@automattic.com
Download-once cut the per-run registry fetches to one; caching the verified
archive removes that fetch on a warm hit and keeps the flaky registry off the
hot path. Key the cache on the immutable source SHA and the blob SHA-256, and
re-verify (SHA-256 and size) on every restore, failing closed on a mismatch.
Fresh metadata resolves before every restore, so the cache can never select the
build version. Write the cache only from protected-branch pushes; pull requests
and forks restore only.

See #65721.

Props lance.willett@automattic.com
Copilot AI review requested due to automatic review settings July 26, 2026 23:50
@github-actions

Copy link
Copy Markdown

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 props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props lancewillett.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

rm -f .ci/gutenberg/archive.tar.gz
node tools/gutenberg/download.js \
--archive .ci/gutenberg/archive.tar.gz \
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
node tools/gutenberg/download.js \
--archive .ci/gutenberg/archive.tar.gz \
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
--blob-sha256 "${{ steps.metadata.outputs.blob-sha256 }}" \
--archive .ci/gutenberg/archive.tar.gz \
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
--blob-sha256 "${{ steps.metadata.outputs.blob-sha256 }}" \
--blob-size "${{ steps.metadata.outputs.blob-size }}"
run: |
node tools/gutenberg/download.js \
--archive .ci/gutenberg/archive.tar.gz \
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
node tools/gutenberg/download.js \
--archive .ci/gutenberg/archive.tar.gz \
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
--blob-sha256 "${{ steps.metadata.outputs.blob-sha256 }}" \
--archive .ci/gutenberg/archive.tar.gz \
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
--blob-sha256 "${{ steps.metadata.outputs.blob-sha256 }}" \
--blob-size "${{ steps.metadata.outputs.blob-size }}"
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
--blob-sha256 "${{ steps.metadata.outputs.blob-sha256 }}" \
--blob-size "${{ steps.metadata.outputs.blob-size }}"
echo "gutenberg-sha=${{ steps.metadata.outputs.source-sha }}" >> "$GITHUB_OUTPUT"

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the existing Gutenberg build preparation work by adding cross-run caching of the verified Gutenberg archive in GitHub Actions, while preserving “fail closed” verification on every restore and keeping cache writes limited to protected-branch pushes.

Changes:

  • Adds a reusable workflow that resolves immutable Gutenberg blob metadata, restores/saves a cache keyed by immutable SHAs/digests, and uploads the extracted build as a run artifact.
  • Updates PHPUnit and coverage workflows to depend on the shared “prepare Gutenberg” job and to avoid re-resolving mutable tags in matrix jobs.
  • Refactors the Gutenberg downloader to support metadata output, stable-archive mode (for cache), and verification/extraction semantics with tests.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tools/gutenberg/utils.js Allows workflows to supply an expected Gutenberg SHA to avoid re-resolving mutable refs per matrix job.
tools/gutenberg/download.js Implements metadata resolution, verified stable-archive download, retries, and safe extraction/replace behavior for caching.
tools/gutenberg/tests/download.test.js Adds unit tests covering metadata outputs, archive verification, cache-archive path validation, and retry/cleanup behavior.
package.json Adds test:tools to run the new Gutenberg tool tests via Node’s test runner.
.gitignore Ignores the cached Gutenberg archive path within the checkout.
.github/workflows/test-coverage.yml Wires coverage jobs to the reusable prepare-Gutenberg workflow and passes artifact/SHA inputs.
.github/workflows/reusable-prepare-gutenberg.yml New reusable workflow that restores/saves the verified archive cache and uploads the extracted Gutenberg artifact.
.github/workflows/reusable-phpunit-tests-v3.yml Adds inputs for prepared Gutenberg artifact and expected SHA; sets env to prevent mutable-tag re-resolution.
.github/workflows/phpunit-tests.yml Adds a shared prepare-Gutenberg job and makes PHPUnit matrices consume its outputs/artifact.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/gutenberg/utils.js
Comment on lines +124 to +134
const workflowSha = process.env.GUTENBERG_EXPECTED_SHA;
if ( workflowSha ) {
if ( ! SHA_PATTERN.test( workflowSha ) ) {
throw new Error(
`GUTENBERG_EXPECTED_SHA must be a 40-character Git SHA, received "${ workflowSha }"`
);
}

return workflowSha;
}

Comment on lines +53 to +62
- name: Download verified Gutenberg archive
if: ${{ steps.restore.outputs.cache-hit != 'true' }}
run: |
rm -f .ci/gutenberg/archive.tar.gz
node tools/gutenberg/download.js \
--archive .ci/gutenberg/archive.tar.gz \
--source-sha "${{ steps.metadata.outputs.source-sha }}" \
--blob-sha256 "${{ steps.metadata.outputs.blob-sha256 }}" \
--blob-size "${{ steps.metadata.outputs.blob-size }}"

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@lancewillett lancewillett changed the title Build/Test Tools: Cache the verified Gutenberg build across runs Build/test tools: Cache the verified Gutenberg build across runs Jul 27, 2026
@lancewillett

Copy link
Copy Markdown
Contributor Author

Closing to keep the flake fix minimal. #12701 (download once per run) removes the download flake by cutting ~177 GHCR fetches per run to one. Cross-run caching is a separate speed optimization, not needed for the flake, so deferring it as a possible small follow-up on top of #12701 rather than a parallel change. If revived, two things to fix from this branch: the prepare workflow verified and extracted the archive twice on a cold run, and the archive-path guard defended against input that cannot occur.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants