Skip to content

ci: cache the lg binary and Playwright browsers; align Go with the deploy - #163

Merged
mparrett merged 3 commits into
mainfrom
ci/actions-caching
Jul 28, 2026
Merged

ci: cache the lg binary and Playwright browsers; align Go with the deploy#163
mparrett merged 3 commits into
mainfrom
ci/actions-caching

Conversation

@mparrett

@mparrett mparrett commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Follow-through from the CI audit on the let-go side (nooga/let-go#581, #583, #584): the xsofy workflows are cheap per run, but their fixed costs repeat on every run and none of them were cached.

Cache the built lg binary. xsofy has no go.sum, so setup-go's dependency cache never engaged — every run of tests, deploy, and preview compiled let-go from source (~1–3 min each). The binary is now cached keyed on the resolved let-go version; the tests' latest lane resolves the moving tag to its concrete version first (go list -m) so it caches on the same footing. A version bump or new release misses the cache once and rebuilds, which is the correct behavior.

Cache Playwright's chromium. Each fresh deploy downloaded Chromium and its supporting browser assets into Playwright's shared Linux cache; the later e2e install already reused that directory within the same job. A cache keyed on the two lockfiles avoids repeating the cross-run download while the pinned versions hold. The e2e step also switches to npm ci against its committed lockfile.

Go 1.26 in tests. The floor lane was testing on Go 1.24 while deploy-pages.yml builds the shipped bundle with 1.26 — the version the tests validate now matches the version that ships.

One mechanical note: pr-preview.yml runs on pull_request_target, which takes its workflow from main, so the restore steps activate after this merges rather than on this PR's own preview. GitHub gives pull_request_target runs restore-only access to default-branch caches, so previews benefit after a trusted deploy or manual run seeds the matching cache; a preview cache miss installs normally but is not saved.

🤖 Generated with Claude Code

@mparrett
mparrett requested a review from nooga July 20, 2026 13:49

@nnunley nnunley left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you check if ~/.cache is the correct git actions directory for shared build caches? There's also the comment on using GOPATH rather than ~/go

Comment thread .github/workflows/deploy-pages.yml Outdated
id: lgcache
uses: actions/cache@v4
with:
path: ~/go/bin/let-go

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Wouldn't using GOPATH be more idiomatic, rather than rather than ~/go?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good question. I checked this against both the tool docs and the actual PR run. On Unix, Go’s default GOPATH is $HOME/go, and actions/cache supports ~ expansion in path. The run resolved this to /home/runner/go/bin/let-go and successfully saved the cache. Using GOPATH directly in a with.path value would not be shell expansion; making it dynamic would require an extra step that exports go env GOPATH as an output. Given these jobs are all ubuntu-latest, I think ~/go/bin/let-go is correct as written.

References: Go GOPATH, actions/cache path handling

Comment thread .github/workflows/pr-preview.yml Outdated
id: lgcache
uses: actions/cache@v4
with:
path: ~/go/bin/let-go

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same concern here with ~/go vs GOPATH

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Checked here as well: this job is also ubuntu-latest, where the default GOPATH is $HOME/go. actions/cache expands ~, and the current test run proved the same path resolves to /home/runner/go/bin/let-go and saves successfully. I’d keep this consistent with the deploy workflow.

Comment thread .github/workflows/test.yml Outdated
uses: actions/cache@v4
with:
go-version: '1.24'
path: ~/go/bin/let-go

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

and here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same result in the test workflow: the run resolved ~/go/bin/let-go to /home/runner/go/bin/let-go, found the installed binary there, and successfully saved both matrix cache entries. I’d keep this path as written unless we intentionally add a separate go env GOPATH output step.

@mparrett mparrett left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review follow-up after checking the workflow behavior and logs:

  • Playwright path: ~/.cache/ms-playwright is the documented Linux browser location, and all affected jobs use ubuntu-latest. The recent deploy log confirms installation under /home/runner/.cache/ms-playwright. One factual correction: that log shows only the first Playwright install downloaded Chromium; the second install reused it. The PR description should therefore say the download repeats once per fresh runner, not twice within the deploy job. Playwright also notes that restoring a browser cache can take about as long as downloading it, so keeping this cache is a performance tradeoff worth validating rather than a correctness requirement.
  • Preview cache semantics: pr-preview.yml runs on pull_request_target. GitHub gives those runs restore-only access to default-branch caches: they can restore an existing cache but cannot save a miss. I recommend using actions/cache/restore@v4 in that workflow and clarifying that preview runs benefit only after a trusted deploy/manual run has populated the main-branch caches. If previews need to populate caches themselves, that needs a trusted cache-warming path or a larger workflow redesign.
  • Verification: both PR test jobs are green, both lg binary caches were saved successfully, and npm ci --dry-run passes in tests/e2e.

I’m leaving this as a comment rather than requesting changes so we can decide whether the Playwright cache and preview restore-only cleanup belong in this PR.

References: Playwright browser paths, Playwright CI caching guidance, GitHub pull_request_target cache behavior

@mparrett

Copy link
Copy Markdown
Collaborator Author

Follow-up implemented in edf27f8:

  • pr-preview.yml now uses actions/cache/restore@v4 for both the let-go binary and Playwright browser caches, matching GitHub's restore-only behavior for pull_request_target.
  • Step names and comments now explain that trusted deploy/manual runs seed those caches.
  • The PR description now says Playwright downloads once per fresh runner, not twice within one deploy job, and documents the preview cache limitation.
  • ~/go/bin/let-go remains unchanged; the PR run verified that it resolves to /home/runner/go/bin/let-go and restores/saves correctly.

Validation: actionlint .github/workflows/pr-preview.yml, git diff --check, and npm ci --dry-run in tests/e2e all pass. The required pinned/deploy-floor check on the new commit passed in 1m49s and skipped installation on its cache hit.

The non-required upstream-latest lane resolved the newly released let-go v1.12.0 and is currently hanging in Run tests; that is separate from this workflow edit. I have left the run active. A timeout guard for the advisory lane would be a sensible follow-up if we want to cap this kind of upstream hang.

@mparrett

mparrett commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator Author

@nnunley

Follow-up on the GOPATH threads: rereading them, I may have answered a narrower question than you asked. If the intent was "derive the path from go env GOPATH instead of hardcoding ~/go", that takes one extra step per workflow, since actions/cache doesn't expand env vars in path:

- run: echo "GOPATH=$(go env GOPATH)" >> "$GITHUB_ENV"

then ${{ env.GOPATH }}/bin/let-go in the cache paths. My default is to leave the tilde paths as-is (they match the actions/cache Go examples, and all three jobs are ubuntu-latest), but if the dynamic form is what you were after I'll push it- let me know!

@nnunley

nnunley commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

I guess it's fine as it is. I'm just being pedantic right now

@mparrett mparrett closed this Jul 21, 2026
@mparrett mparrett reopened this Jul 21, 2026
mparrett and others added 2 commits July 20, 2026 19:57
…ploy

xsofy has no go.sum, so setup-go's dependency cache never engaged and
every CI run compiled let-go from source (~1-3 min in each of tests,
deploy, and preview). Cache the built binary keyed on the resolved
version instead; the latest lane resolves the moving 'latest' to its
concrete version first so it caches too. Playwright's chromium
(~150MB, downloaded twice in the deploy: smoke + e2e) gets a cache
keyed on the two lockfiles.

Also: tests now run Go 1.26 to match deploy-pages.yml (the floor lane
was testing on 1.24 while the shipped bundle builds with 1.26), and
the e2e step uses npm ci against its committed lockfile.

Note: pr-preview.yml runs on pull_request_target, which takes the
workflow from main — its changes activate after merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mparrett

Copy link
Copy Markdown
Collaborator Author

Review context for this and the other five ready PRs, with suggested order and merge-order notes: #182

Review follow-up: the cache paths restated defaults (`~/go`, `~/.cache/ms-playwright`)
that nothing in the workflows declared. Both are correct on today's ubuntu-latest
runners, which is why the caches work, but correctness rested on a property the
files never asserted. A runner or a job-level GOPATH that disagreed would point
the cache somewhere `go install` never writes, and the symptom would be a silent
permanent miss, which is the exact cost these caches exist to remove.

Ask the tools instead. `go env GOPATH` and an explicit PLAYWRIGHT_BROWSERS_PATH
go into GITHUB_ENV once per job; the cache steps consume those. Setting the
Playwright variable also means the cache path and what `playwright install`
actually writes are one value rather than two strings that happen to match.

Same values, same behavior; the assumption is now declared rather than verified
after the fact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mparrett

Copy link
Copy Markdown
Collaborator Author

@nnunley Went with your version in b061151.

You were right that it was an assumption. ~/go and ~/.cache/ms-playwright are correct on ubuntu-latest, which is why the caches worked and why the run output I quoted checked out, but nothing in the workflows declared either one. The failure mode if that ever stopped holding is a silent permanent cache miss, which is the exact cost these caches exist to remove, so it is not worth resting on a property the files never state.

Both are now resolved once per job into GITHUB_ENV and consumed by the cache steps:

- name: Resolve cache paths
  run: |
    echo "GOPATH=$(go env GOPATH)" >> "$GITHUB_ENV"
    echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/ms-playwright" >> "$GITHUB_ENV"

Setting PLAYWRIGHT_BROWSERS_PATH rather than only reading it means the cache path and what playwright install actually writes are one value instead of two strings that happen to agree.

Verified on the branch: go env GOPATH resolves to /home/runner/go, the cache step logs path: /home/runner/go/bin/let-go (byte-identical to before), the first run saved lg-bin-Linux-go1.26-v1.12.2, and a re-run reported Cache restored from key on both lanes with the install step skipped. Same values, same behavior, all four checks green.

Good to approve if this settles it.

@mparrett
mparrett merged commit 2b18152 into main Jul 28, 2026
6 checks passed
@mparrett
mparrett deleted the ci/actions-caching branch July 28, 2026 19:40
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-28 19:40 UTC

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.

2 participants