From 0e32ee9b56bd0815c0dc23a1c3fbb81aa8c43a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Wed, 28 Oct 2026 09:52:07 +0000 Subject: [PATCH] ci: keep the bun cache warm and skip binary downloads in preflight (#6648) * ci: keep the bun cache warm and skip binary downloads in preflight * test(ci): pin the single cache writer and preflight's skipped downloads * test(ci): keep the cache-writer scan out of the test body --- .github/actions/preflight/action.yml | 5 ++++ .github/workflows/ci.yml | 3 +- package.json | 2 +- scripts/ci-cache-workflows.test.mjs | 45 ++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 scripts/ci-cache-workflows.test.mjs diff --git a/.github/actions/preflight/action.yml b/.github/actions/preflight/action.yml index ff2c94967d..b94c9d9e23 100644 --- a/.github/actions/preflight/action.yml +++ b/.github/actions/preflight/action.yml @@ -21,7 +21,12 @@ runs: restore-keys: | bun-${{ runner.os }}- + # Lint and format need neither binary; skip their install-time downloads. + - uses: ./.github/actions/prepare-ffmpeg-bin + - shell: bash + env: + PUPPETEER_SKIP_DOWNLOAD: "true" run: bun install --frozen-lockfile - shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ecec5c11d..071c327f59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -303,7 +303,8 @@ jobs: target: beginframe-contract push: false cache-from: type=gha,scope=gcp-beginframe-contract - cache-to: type=gha,mode=max,scope=gcp-beginframe-contract + # One writer (main): ~1 GB exports per PR run evict the bun cache, and a cold bun install can stall. + cache-to: ${{ github.event_name == 'push' && 'type=gha,mode=max,scope=gcp-beginframe-contract' || '' }} build: name: Build diff --git a/package.json b/package.json index 7142ee0f85..9376f29557 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "player:perf": "bun run --filter @hyperframes/player perf", "format:check": "oxfmt --check .", "knip": "knip", - "test:scripts": "node --import tsx --test scripts/animejs-v4-guidance.test.mjs scripts/check-tracked-artifacts.test.mjs scripts/check-registry-set-delta.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-pr-captures.test.mjs scripts/check-comment-citations.test.mjs scripts/comments-workflow.test.mjs scripts/comment-ratchet.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-media-use-copy-parity.test.mjs scripts/check-svg-sanitize-parity.test.mjs scripts/check-media-use-svg-sanitize-generated.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/check-cli-lazy-deps.test.mjs scripts/file-url-paths.test.mjs scripts/check-studio-copy-dashes.test.mjs scripts/check-large-files.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/clawhub-sync.test.mjs scripts/clawhub-unlist-retired.test.mjs scripts/publish-workflow.test.mjs scripts/pr-edit-concurrency.test.mjs scripts/merge-queue-workflows.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/check-edit-accuracy-filter.test.mjs scripts/edit-accuracy-retry.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/catalog-payload-assets.test.ts scripts/host-registry-assets.test.ts scripts/catalog-preview-temp.test.ts scripts/backfill-block-previews.test.ts scripts/catalog-hosted-files.test.ts scripts/player-cdn-pin.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/rewrite-relative-import-extensions.test.mjs scripts/lint-skills.test.mjs scripts/check-core-skills.test.mjs scripts/creator-editing-recipes.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs packages/core/scripts/writeGeneratedFile.test.ts scripts/catalog-publication.test.mjs scripts/ci/resolve-workflow-pr.test.mjs scripts/lefthook-order.test.mjs scripts/inline-gsap.test.mjs scripts/ci/flake-gate.test.mjs scripts/ci/base-file.test.mjs scripts/ci/release-only-diff.test.mjs scripts/check-catalog-source-pr.test.mjs scripts/generate-registry-items.test.ts scripts/catalog-drift.test.ts scripts/catalog-fetch-mirror.test.ts scripts/catalog-script-inlining.test.ts scripts/catalog-detail.test.ts scripts/generate-catalog-pages.test.ts scripts/verify-catalog-payloads.test.ts scripts/registry-theme-fallbacks.test.ts scripts/registry-skill-files.test.ts scripts/creator-editing-capabilities.test.mjs scripts/generate-catalog-previews.test.ts scripts/registry-primitive-payloads.test.ts registry/components/pan-stations/pan-stations.test.mjs registry/components/filmed-screen/filmed-screen.test.mjs registry/components/echo-smear/echo-smear.test.mjs && vitest run scripts/catalog/ scripts/contrastRatchet.test.ts scripts/generate-catalog-payloads.test.ts", + "test:scripts": "node --import tsx --test scripts/animejs-v4-guidance.test.mjs scripts/check-tracked-artifacts.test.mjs scripts/check-registry-set-delta.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-pr-captures.test.mjs scripts/check-comment-citations.test.mjs scripts/comments-workflow.test.mjs scripts/comment-ratchet.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-media-use-copy-parity.test.mjs scripts/check-svg-sanitize-parity.test.mjs scripts/check-media-use-svg-sanitize-generated.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/check-cli-lazy-deps.test.mjs scripts/file-url-paths.test.mjs scripts/check-studio-copy-dashes.test.mjs scripts/check-large-files.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/clawhub-sync.test.mjs scripts/clawhub-unlist-retired.test.mjs scripts/publish-workflow.test.mjs scripts/pr-edit-concurrency.test.mjs scripts/merge-queue-workflows.test.mjs scripts/ci-cache-workflows.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/check-edit-accuracy-filter.test.mjs scripts/edit-accuracy-retry.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/catalog-payload-assets.test.ts scripts/host-registry-assets.test.ts scripts/catalog-preview-temp.test.ts scripts/backfill-block-previews.test.ts scripts/catalog-hosted-files.test.ts scripts/player-cdn-pin.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/rewrite-relative-import-extensions.test.mjs scripts/lint-skills.test.mjs scripts/check-core-skills.test.mjs scripts/creator-editing-recipes.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs packages/core/scripts/writeGeneratedFile.test.ts scripts/catalog-publication.test.mjs scripts/ci/resolve-workflow-pr.test.mjs scripts/lefthook-order.test.mjs scripts/inline-gsap.test.mjs scripts/ci/flake-gate.test.mjs scripts/ci/base-file.test.mjs scripts/ci/release-only-diff.test.mjs scripts/check-catalog-source-pr.test.mjs scripts/generate-registry-items.test.ts scripts/catalog-drift.test.ts scripts/catalog-fetch-mirror.test.ts scripts/catalog-script-inlining.test.ts scripts/catalog-detail.test.ts scripts/generate-catalog-pages.test.ts scripts/verify-catalog-payloads.test.ts scripts/registry-theme-fallbacks.test.ts scripts/registry-skill-files.test.ts scripts/creator-editing-capabilities.test.mjs scripts/generate-catalog-previews.test.ts scripts/registry-primitive-payloads.test.ts registry/components/pan-stations/pan-stations.test.mjs registry/components/filmed-screen/filmed-screen.test.mjs registry/components/echo-smear/echo-smear.test.mjs && vitest run scripts/catalog/ scripts/contrastRatchet.test.ts scripts/generate-catalog-payloads.test.ts", "typecheck:scripts": "tsc --noEmit -p scripts/tsconfig.json", "test:skills": "HYPERFRAMES_MEDIA_HOME_REQUIRED=1 node --import ./packages/cli/scripts/test-home.mjs --test 'skills/**/*.test.mjs' 'packages/cli/src/media-use/**/*.test.mjs'", "generate:previews": "tsx scripts/generate-template-previews.ts", diff --git a/scripts/ci-cache-workflows.test.mjs b/scripts/ci-cache-workflows.test.mjs new file mode 100644 index 0000000000..7401874d2b --- /dev/null +++ b/scripts/ci-cache-workflows.test.mjs @@ -0,0 +1,45 @@ +import assert from "node:assert/strict"; +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import test from "node:test"; +import { parse } from "yaml"; + +const root = join(import.meta.dirname, ".."); +const workflowsDir = join(root, ".github", "workflows"); +const load = (path) => parse(readFileSync(path, "utf8")); +const workflows = readdirSync(workflowsDir) + .filter((file) => /\.ya?ml$/.test(file)) + .map((file) => ({ file, doc: load(join(workflowsDir, file)) })); +const events = (on) => + typeof on === "string" ? [on] : Array.isArray(on) ? on : Object.keys(on ?? {}); + +const dispatchOnly = ["fast-video-validation.yml"]; +const ungatedCacheWrites = (list) => + list + .filter(({ file }) => !dispatchOnly.includes(file)) + .flatMap(({ file, doc }) => + Object.entries(doc.jobs ?? {}).flatMap(([name, job]) => + (job.steps ?? []) + .map((step) => String(step.with?.["cache-to"] ?? "")) + .filter((to) => to.includes("type=gha") && !to.includes("github.event_name == 'push'")) + .map(() => `${file} ${name}`), + ), + ); + +// The Actions cache holds 10 GB; per-PR image exports evict the bun cache and leave installs cold. +test("only pushes to main write image layers to the Actions cache", () => { + for (const file of dispatchOnly) { + const { doc } = workflows.find((w) => w.file === file); + assert.deepEqual(events(doc.on), ["workflow_dispatch"], `${file} must stay dispatch-only`); + } + assert.deepEqual(ungatedCacheWrites(workflows), []); +}); + +test("preflight installs without downloading ffmpeg or Chrome", () => { + const steps = load(join(root, ".github", "actions", "preflight", "action.yml")).runs.steps; + const ffmpeg = steps.findIndex((step) => step.uses === "./.github/actions/prepare-ffmpeg-bin"); + const install = steps.findIndex((step) => /\bbun install\b/.test(step.run ?? "")); + assert.ok(install >= 0, "preflight runs bun install"); + assert.ok(ffmpeg >= 0 && ffmpeg < install, "prepare-ffmpeg-bin runs before bun install"); + assert.equal(steps[install].env?.PUPPETEER_SKIP_DOWNLOAD, "true"); +});