From 498c13fe3774f5b30524fea0a68982c666c29b1d Mon Sep 17 00:00:00 2001 From: "Juan Carlos Moreno [ackstorm]" Date: Thu, 29 Oct 2026 09:59:24 +0100 Subject: [PATCH] ci: cache Go builds per job and run envtest alongside unit - setup-devtools keys the Go cache by job. With one shared key the first job to finish saved it; on PR #21 that was Security, which compiles nothing, so every job restored a 221-byte cache and never saved again. Also caches golangci-lint's own cache. - CI also runs on push to main (E2E skipped) so main holds warm caches: a PR can only restore caches from its own ref or main. - envtest no longer waits for unit; e2e waits for unit only. Co-Authored-By: Claude Opus 5.5 --- .github/actions/setup-devtools/action.yml | 10 ++++++++-- .github/workflows/ci.yml | 23 ++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/.github/actions/setup-devtools/action.yml b/.github/actions/setup-devtools/action.yml index 61873fc..2e79b24 100644 --- a/.github/actions/setup-devtools/action.yml +++ b/.github/actions/setup-devtools/action.yml @@ -25,14 +25,20 @@ description: Restore Go caches, pull pre-built devtools image from GHCR, fall ba runs: using: composite steps: + # One cache per job: each job compiles something different (lint, unit, + # envtest -race, e2e) and only a job that misses its key saves. A shared + # key is saved by whichever job finishes first; when that is Security, + # which compiles nothing, every other job hits an empty cache and never + # replaces it. - name: Cache Go module + build caches (mounted into devtools container) uses: actions/cache@v5 # v4.3.0 with: path: | .gocache/build .gocache/gopath - key: ${{ runner.os }}-devtools-${{ hashFiles('**/go.sum', 'Dockerfile.devtools') }} - restore-keys: ${{ runner.os }}-devtools- + .gocache/.cache/golangci-lint + key: ${{ runner.os }}-devtools-${{ github.job }}-${{ hashFiles('**/go.sum', 'Dockerfile.devtools') }} + restore-keys: ${{ runner.os }}-devtools-${{ github.job }}- - name: Compute devtools image reference id: ref diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ec05ad..65d8fa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,8 @@ name: ci -# PR-only: branch protection on main enforces the PR workflow, so the -# pull_request event is the single CI trigger. +# Gates run on pull_request. The push to main only warms the Go caches: a PR +# can restore caches from its own ref or from main, so without this every new +# PR starts cold. E2E is skipped on push (it builds images, not .gocache). # # The invariant that makes this file trustworthy: EVERY step below is # `./scripts/dev.sh make `. CI never reimplements a local command, so @@ -18,9 +19,16 @@ on: - 'NOTICE' - 'CODEOWNERS' - '.gitignore' + push: + branches: [main] + paths-ignore: + - '**/*.md' + - 'docs/**' + - 'LICENSE' + - 'NOTICE' + - 'CODEOWNERS' + - '.gitignore' -# main is PR-only (branch protection enforces). Post-merge content equals -# PR head content, so re-running on push main is redundant. concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -69,7 +77,6 @@ jobs: envtest: name: Envtest runs-on: ubuntu-latest - needs: unit timeout-minutes: 30 steps: - uses: actions/checkout@v6 # v4.3.1 @@ -120,9 +127,11 @@ jobs: e2e: name: E2E (kind + ginkgo) runs-on: ubuntu-latest - needs: [unit, envtest] + # Gated on unit only: envtest runs alongside, and e2e (the longest job) + # starts as soon as the cheap gate passes instead of after both. + needs: unit timeout-minutes: 30 - if: "!github.event.pull_request.draft" + if: "github.event_name == 'pull_request' && !github.event.pull_request.draft" steps: - uses: actions/checkout@v6 # v4.3.1