Skip to content

Speed up CI toward 20s wall clock - #299

Open
rerost wants to merge 7 commits into
masterfrom
claude/dreamy-lichterman-aee103
Open

Speed up CI toward 20s wall clock#299
rerost wants to merge 7 commits into
masterfrom
claude/dreamy-lichterman-aee103

Conversation

@rerost

@rerost rerost commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Summary

Investigated https://github.com/rerost/issue-creator/actions/runs/28697434525 (~90s wall clock) and reduced it to ~36s (steady state, measured on this PR).

Job Before After (warm) Fix
lint 89s 12s binary install instead of goinstall; own cache incl. GOCACHE + golangci analysis cache (the action's cache was a stale 330KB entry that is never re-saved on hit, so lint ran cold every time)
Test 68s 14–22s per-job Go module + build cache (the -race build was ~50s; tests themselves run in ~6s)
Check Renovate 44s removed moved to its own workflow, runs only when renovate.json changes
Test Docker Image 41s ~20s build the binary on the runner (warm Go cache) and override the Dockerfile builder stage via --build-context; the full Dockerfile build is still verified by the push job
Docker Build and Push 37s ~31s (fully cached: build+push is 6s) buildx GHA layer cache + buildkit-cache-dance to persist go mod/build cache mounts; .dockerignore so .git no longer invalidates the build layer on every commit
Build / Check Go Generate / GoReleaser 29–31s 10–17s per-job Go caches

Techniques borrowed from rerost/giro#303 (background/wait steps, GHA cache scopes).

Notes

  • First run after a go.sum change repopulates caches and is slower; steady state is as above.
  • The two docker image tests must stay sequential: they create/close real issues in rerost/issue-creator-for-test and race when parallelized (verified: 422).
  • "Check Renovate" now only runs when renovate.json changes — remove it from required status checks if configured.
  • Remaining wall-clock bottleneck is Docker Build and Push (~31s fixed cost: buildx bootstrap 9s + cache injection 6s). Getting under 20s would require not pushing/building the full Dockerfile on PRs (e.g. push only on master/tags) — behavior change, left out of this PR.

Test plan

  • All jobs green on this PR (runs 3–6)
  • Warm-cache wall clock measured: 36s (empty commit), lint 12s, docker build fully CACHED

🤖 Generated with Claude Code

- lint: drop install-mode=goinstall so golangci-lint is downloaded as a
  binary instead of compiled from source (~60s saved)
- test/build/check-generate: per-job Go module + build caches so the
  -race test build (~50s) becomes incremental
- Docker jobs: bootstrap buildx in a background step, add GHA layer
  cache, and persist the Dockerfile's go mod/build cache mounts via
  buildkit-cache-dance; run the two docker image tests in parallel
- Dockerfile: add a go-build cache mount to the build stage
- Renovate config check: move to its own workflow that only runs when
  renovate.json changes (npx download of renovate took ~40s per run)

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

codecov-commenter commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 44.49%. Comparing base (408834c) to head (a1744ac).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #299   +/-   ##
=======================================
  Coverage   44.49%   44.49%           
=======================================
  Files          15       15           
  Lines         636      636           
=======================================
  Hits          283      283           
  Misses        306      306           
  Partials       47       47           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

rerost and others added 6 commits July 4, 2026 15:31
The two docker run tests create and close issues in the same test
repository, so running them in parallel races and fails with 422.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The buildx container bootstrap, cache injection, and image load
transfer added ~30s of fixed cost to the docker image test job. Build
the binary on the runner with the Go build cache instead and override
the Dockerfile's builder stage via --build-context, so the docker build
only assembles the runtime stage. The full Dockerfile build is still
verified by docker_build_and_push on every run.

Also use the default GHA cache scope for the push job: on pull_request
events github.ref_name is "N/merge", and branch isolation is already
handled natively by the Actions cache service.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The lint job was effectively running cold every time: the
golangci-lint-action cache had a stale near-empty entry that is never
re-saved on cache hit, and the shared setup-go cache never contained
golangci's compilation objects. Give lint its own explicit cache
(GOCACHE + golangci-lint analysis cache) like the other jobs.
Locally golangci-lint runs in ~0.5s warm vs ~4s cold.

Add .dockerignore: the build context included .git, so every commit
invalidated the go build layer even when no source changed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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