Skip to content

ci: unified workflow with build-once image sharing and cross-run layer cache#1145

Open
dimitri wants to merge 2 commits into
mainfrom
ci/cached-images
Open

ci: unified workflow with build-once image sharing and cross-run layer cache#1145
dimitri wants to merge 2 commits into
mainfrom
ci/cached-images

Conversation

@dimitri

@dimitri dimitri commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem

Both run-tests.yml and run-pgaftest.yml independently built all images from scratch on every push. A typical PR triggered six separate image builds for PG14–17 (two workflows × four versions), each re-compiling Postgres + Citus + pg_auto_failover from source. The base→citus→build chain alone takes ~8–10 min per version.

Changes

ci.yml — single unified workflow

Replaces both old workflows. One build matrix job per Postgres major version:

style ──► build (PG14..17) ──► pytest       (PG14-17, all tests)
                           ├─► pgaftest      (PG14-17, all schedules)
                           ├─► installcheck  (PG14-17)
                           └─► upgrade       (PG16)

Each build job:

  • Uses Docker Buildx + GHA layer cache (scope build-pgNN) — the expensive base→citus→build chain is a cache hit on subsequent runs when neither the Dockerfile nor Postgres/Citus versions change
  • Builds all targets sequentially in one job; Docker's local daemon cache means shared layers are compiled once and reused for test, run, debian, testrun targets in the same job
  • Uploads all images as GitHub Actions artifacts (1-day retention) for downstream jobs to share

The style checker also runs once instead of twice.

base-images.yml — maintains long-lived base image cache in GHCR

ghcr.io/hapostgres/pg-cache:pgNN — the ci.yml build jobs pull this as --cache-from.

Three triggers:

  • Nightly 02:00 UTC — rebuilds PG19 from PostgreSQL master (frequently-changing headers)
  • Weekly Monday 03:00 UTC — checks github.com/postgres/postgres tags for new stable minor releases (REL_NN_X pattern); rebuilds + pushes cache + commits updated .github/pg-base-versions/pgNN.ref only when a new tag appears
  • Manual workflow_dispatch — rebuild any single version on demand

.github/pg-base-versions/

Seed files recording the current latest minor release for each stable major (PG14–18). The weekly check job uses these as its baseline to detect new releases.

…r cache

Replace the two independent workflows (run-tests.yml, run-pgaftest.yml)
with a single ci.yml that builds each Postgres version's images once and
shares them across both the pytest suite and the pgaftest TAP suite.

Problem with the old approach
------------------------------
On every push both workflows independently rebuilt all images from scratch.
A typical PR triggered six separate image builds for PG14-17 (two
workflows × four versions), each re-compiling Postgres + Citus + pg_auto_failover
from source. The base→citus→build chain alone takes ~8-10 min per version.

New ci.yml (unified, single workflow)
--------------------------------------
One build matrix job per Postgres major version replaces both workflows'
build stages:

  style ──► build (PG14..17) ──► pytest  (PG14-17)
                              ├─► pgaftest (PG14-17, all schedules)
                              ├─► installcheck (PG14-17)
                              └─► upgrade (PG16)

Each build job:
- Uses Docker Buildx with GHA layer cache (scope build-pgNN) so the
  expensive base→citus→build chain is a cache hit on subsequent runs
  when neither the Dockerfile nor Postgres/Citus versions have changed.
- Builds all required targets sequentially (test, run, debian, testrun,
  pgaftest for PG17); Docker's local daemon cache means the shared build
  layers are compiled once and reused for every subsequent target in the
  same job.
- Uploads each image as a GitHub Actions artifact (retention: 1 day) for
  downstream test jobs to download and load.

The pytest suite and pgaftest suite both need: [build], not each other,
so all test jobs run fully in parallel after the build fan-out.

New base-images.yml
--------------------
Separate workflow maintains cached base images in GHCR for cross-run
layer reuse. Two schedules:

  nightly (02:00 UTC)  — rebuilds PG19 from PostgreSQL master so its
                         frequently-changing headers stay current.

  weekly (Mon 03:00)   — checks github.com/postgres/postgres for new
                         minor-release tags (REL_NN_X pattern, numeric
                         minor only).  If a new tag appears, rebuilds
                         the base image, pushes to
                         ghcr.io/hapostgres/pg-cache:pgNN, and commits
                         the updated .github/pg-base-versions/pgNN.ref
                         so the next weekly check knows what's already
                         been built.

  manual               — workflow_dispatch with an optional pgversion
                         input to trigger a rebuild for a specific
                         major version immediately.

.github/pg-base-versions/
--------------------------
Seed files recording the current latest minor release for each stable
major version (PG14-18), used by the weekly check job as its baseline.
@dimitri dimitri self-assigned this Jul 12, 2026
@dimitri dimitri added Developer productivity Enhancements to ability to ship quality code Packaging and CI Enhancements to our CI integration labels Jul 12, 2026
matrix.* is only resolved within steps, not at the job-level if condition.
Move the manual pgversion filter into the detect step instead, using an
early exit so all downstream steps (gated on rebuild == 'true') are
skipped naturally.  Also drop the now-redundant PGVERSION_STR matrix field.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Developer productivity Enhancements to ability to ship quality code Packaging and CI Enhancements to our CI integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant