From 8b60d1d8777ad65d51341f32672d32b9c9ce7f5a Mon Sep 17 00:00:00 2001 From: Ethan <39577870+ethanndickson@users.noreply.github.com> Date: Tue, 7 Jul 2026 11:44:46 +1000 Subject: [PATCH] ci: cache embedded postgres binaries in flake checks (#26986) flake-go keeps failing every `TestServer` subtest that boots `coder server` with built-in PostgreSQL ([example run](https://github.com/coder/coder/actions/runs/28685288282/job/85134336803)) with `no version found matching 13.21.0`, which is embedded-postgres's error for any non-200 while downloading the Postgres binary archive from Maven. The archive gets cached under the server's config root, which is a fresh temp dir in every test, so with `test-count: 35` one flake run downloads it dozens of times and Maven rate-limits the runner. Using an external Postgres (like coder/terraform-provider-coderd#370 did) would defeat the point, since these subtests exist to exercise the built-in Postgres path. Instead, `startBuiltinPostgres` now honors `EMBEDDED_PG_CACHE_DIR` as the archive cache path (test runs only, data/runtime dirs stay per-test), and flake-go.yaml wires in the existing `embedded-pg-cache` actions the same way the Windows/macOS lanes in ci.yaml already do. All iterations then share a single download, and usually zero once the actions cache is warm. The upload step only saves on `main`. --- .github/workflows/flake-go.yaml | 24 ++++++++++++++++++++++++ cli/server.go | 9 +++++++++ 2 files changed, 33 insertions(+) diff --git a/.github/workflows/flake-go.yaml b/.github/workflows/flake-go.yaml index be9b000556..117efe4a8d 100644 --- a/.github/workflows/flake-go.yaml +++ b/.github/workflows/flake-go.yaml @@ -70,6 +70,21 @@ jobs: with: install-args: "terraform" + # Exports EMBEDDED_PG_CACHE_DIR, which startBuiltinPostgres uses as a + # shared binary archive cache in tests. + - name: Setup Embedded Postgres Cache Paths + id: embedded-pg-cache + if: ${{ fromJSON(steps.selector.outputs.matrix).include[0] != null }} + uses: ./.github/actions/setup-embedded-pg-cache-paths + + - name: Download Embedded Postgres Cache + id: download-embedded-pg-cache + if: ${{ fromJSON(steps.selector.outputs.matrix).include[0] != null }} + uses: ./.github/actions/embedded-pg-cache/download + with: + key-prefix: embedded-pg-${{ runner.os }}-${{ runner.arch }} + cache-path: ${{ steps.embedded-pg-cache.outputs.cached-dirs }} + - name: Run targeted Go flake checks id: flake_check if: ${{ fromJSON(steps.selector.outputs.matrix).include[0] != null }} @@ -84,6 +99,15 @@ jobs: test-shuffle: "on" gotestsum-json-file: default + # The upload action only saves on main, so this is a no-op for PRs. + # A workflow_dispatch run on main seeds the cache that PR runs restore. + - name: Upload Embedded Postgres Cache + if: ${{ fromJSON(steps.selector.outputs.matrix).include[0] != null }} + uses: ./.github/actions/embedded-pg-cache/upload + with: + cache-key: ${{ steps.download-embedded-pg-cache.outputs.cache-key }} + cache-path: "${{ steps.embedded-pg-cache.outputs.embedded-pg-cache }}" + - name: Publish Go test failure report if: failure() && steps.flake_check.outcome == 'failure' && github.actor != 'dependabot[bot]' && runner.os == 'Linux' && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork) uses: ./.github/actions/go-test-failure-report diff --git a/cli/server.go b/cli/server.go index 21f26c1dc0..6524d9d6d2 100644 --- a/cli/server.go +++ b/cli/server.go @@ -2412,6 +2412,15 @@ func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logg if customCacheDir != "" { cachePath = filepath.Join(customCacheDir, "postgres") } + // Tests get a fresh config root per invocation, so the default cache path + // never hits and each test re-downloads the archive from Maven, which + // rate-limits CI runners. EMBEDDED_PG_CACHE_DIR (restored from the actions + // cache) lets them share one copy. + if flag.Lookup("test.v") != nil { + if dir := os.Getenv("EMBEDDED_PG_CACHE_DIR"); dir != "" { + cachePath = dir + } + } stdlibLogger := slog.Stdlib(ctx, logger.Named("postgres"), slog.LevelDebug) // If the port is not defined, an available port will be found dynamically. This has