From 58379f483e8cc7f8550d6657e9098b0716eec905 Mon Sep 17 00:00:00 2001 From: Gabriele Bartolini Date: Sat, 19 Sep 2026 09:46:32 +0200 Subject: [PATCH] fix: build PostGIS independently so trunk breakage can't block the pipeline PostGIS periodically fails to build against PostgreSQL trunk. Since it was built in the same `docker buildx bake` invocation as minimal/standard (see #158), a PostGIS-only failure took the whole build-pg job down with it -- blocking minimal/standard image publishing and, transitively, E2E testing, since call-reusable-e2e needs build-pg. - docker-bake.hcl: move `postgis` out of the "default" matrix into its own standalone target, so a plain `docker buildx bake` (or `bake --push`) still only builds minimal/standard, while `docker buildx bake postgis` builds it explicitly. - reusable-build.yml: generalize the `minimal_tags`/`standard_tags` inputs into a single `targets` input (one ":" entry per line), so the same reusable workflow can build an arbitrary set of targets. Also pass the parsed target names to `docker/bake-action`'s `targets` input, since it only builds bake's "default" group otherwise. Add a `best_effort` input that sets `continue-on-error` on this workflow's own build/merge jobs -- GitHub Actions doesn't allow `continue-on-error` directly on a job that calls a reusable workflow via `uses:`, so the tolerance has to live inside the reusable workflow itself. - build.yml, build-commitfest.yml, continuous-delivery.yml: add a `build-postgis` job, parallel to (and independent of) `build-pg`, that calls reusable-build.yml with `targets: postgis:...` and `best_effort: true`. Nothing depends on `build-postgis`, so a PostGIS failure no longer affects minimal/standard or E2E. - README.md: document building the `postgis` target explicitly. Closes #158 Assisted-by: Claude Signed-off-by: Gabriele Bartolini --- .github/workflows/build-commitfest.yml | 29 +++++++++- .github/workflows/build.yml | 29 +++++++++- .github/workflows/continuous-delivery.yml | 27 ++++++++- .github/workflows/reusable-build.yml | 61 +++++++++++++------- README.md | 11 +++- docker-bake.hcl | 69 +++++++++++++++++++++-- 6 files changed, 192 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build-commitfest.yml b/.github/workflows/build-commitfest.yml index 6e01323..238ada3 100644 --- a/.github/workflows/build-commitfest.yml +++ b/.github/workflows/build-commitfest.yml @@ -26,6 +26,7 @@ jobs: pg_branch: ${{ env.BRANCH }} minimal_tag: ${{ env.registry }}/postgresql-trunk:${{ env.PG_MAJOR }}-minimal-${{ env.TAG }} standard_tag: ${{ env.registry }}/postgresql-trunk:${{ env.PG_MAJOR }}-standard-${{ env.TAG }} + postgis_tag: ${{ env.registry }}/postgresql-trunk:${{ env.PG_MAJOR }}-postgis-${{ env.TAG }} steps: - name: Checkout Code uses: actions/checkout@v7 @@ -69,23 +70,45 @@ jobs: pg_branch: ${{ needs.prepare.outputs.pg_branch }} pg_major: ${{ needs.prepare.outputs.pg_major }} revision: ${{ github.sha }} - minimal_tags: ${{ needs.prepare.outputs.minimal_tag }} - standard_tags: ${{ needs.prepare.outputs.standard_tag }} + targets: | + minimal:${{ needs.prepare.outputs.minimal_tag }} + standard:${{ needs.prepare.outputs.standard_tag }} + + # PostGIS periodically fails to build against PostgreSQL trunk. Kept as its + # own best-effort job so a break there doesn't fail this run or block the + # minimal/standard images above. See #158. + build-postgis: + name: Build PostGIS image for the patch (best-effort) + needs: prepare + uses: ./.github/workflows/reusable-build.yml + permissions: + contents: read + packages: write + with: + pg_repo: https://github.com/postgresql-cfbot/postgresql.git + pg_branch: ${{ needs.prepare.outputs.pg_branch }} + pg_major: ${{ needs.prepare.outputs.pg_major }} + revision: ${{ github.sha }} + targets: | + postgis:${{ needs.prepare.outputs.postgis_tag }} + best_effort: true generate-summary: name: Commitfest Image Build summary runs-on: ubuntu-24.04 needs: - build-pg + - build-postgis steps: - name: Output summary env: INPUT_PATCH_ID: ${{ github.event.inputs.patch_id }} BUILD_PG_IMAGES: ${{ needs.build-pg.outputs.images }} + BUILD_POSTGIS_IMAGES: ${{ needs.build-postgis.outputs.images }} run: | commitFestPatchID="${INPUT_PATCH_ID}" commitFestURL="https://commitfest.postgresql.org/patch/${commitFestPatchID}" - images="${BUILD_PG_IMAGES}" + images="${BUILD_PG_IMAGES} ${BUILD_POSTGIS_IMAGES}" images_list="$(echo $images | tr ' ' '\n' | sed 's/^/https:\/\//')" minimalImage="$(echo $images | tr ' ' '\n' | grep minimal)" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3928c02..c4ea694 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,7 @@ jobs: pg_major: ${{ env.PG_MAJOR }} minimal_tag: ${{ env.registry }}/postgresql-trunk:${{ env.PG_MAJOR }}-minimal-${{ github.run_number }} standard_tag: ${{ env.registry }}/postgresql-trunk:${{ env.PG_MAJOR }}-standard-${{ github.run_number }} + postgis_tag: ${{ env.registry }}/postgresql-trunk:${{ env.PG_MAJOR }}-postgis-${{ github.run_number }} steps: - name: Checkout Code uses: actions/checkout@v7 @@ -64,8 +65,28 @@ jobs: pg_branch: ${{ github.event.inputs.pg_branch }} pg_major: ${{ needs.prepare.outputs.pg_major }} revision: ${{ github.sha }} - minimal_tags: ${{ needs.prepare.outputs.minimal_tag }} - standard_tags: ${{ needs.prepare.outputs.standard_tag }} + targets: | + minimal:${{ needs.prepare.outputs.minimal_tag }} + standard:${{ needs.prepare.outputs.standard_tag }} + + # PostGIS periodically fails to build against PostgreSQL trunk. Kept as its + # own best-effort job so a break there doesn't fail this run or block the + # minimal/standard images above. See #158. + build-postgis: + name: Build PostGIS image from sources (best-effort) + needs: prepare + uses: ./.github/workflows/reusable-build.yml + permissions: + contents: read + packages: write + with: + pg_repo: ${{ github.event.inputs.pg_repo }} + pg_branch: ${{ github.event.inputs.pg_branch }} + pg_major: ${{ needs.prepare.outputs.pg_major }} + revision: ${{ github.sha }} + targets: | + postgis:${{ needs.prepare.outputs.postgis_tag }} + best_effort: true generate-summary: name: PostgreSQL Image Build summary @@ -73,14 +94,16 @@ jobs: needs: - prepare - build-pg + - build-postgis steps: - name: Output summary env: BUILD_PG_MAJOR: ${{ needs.prepare.outputs.pg_major }} BUILD_PG_IMAGES: ${{ needs.build-pg.outputs.images }} + BUILD_POSTGIS_IMAGES: ${{ needs.build-postgis.outputs.images }} run: | pg_major="${BUILD_PG_MAJOR}" - images="${BUILD_PG_IMAGES}" + images="${BUILD_PG_IMAGES} ${BUILD_POSTGIS_IMAGES}" images_list="$(echo $images | tr ' ' '\n' | sed 's/^/https:\/\//')" minimalImage="$(echo $images | tr ' ' '\n' | grep minimal)" diff --git a/.github/workflows/continuous-delivery.yml b/.github/workflows/continuous-delivery.yml index 3f7130a..b900ca8 100644 --- a/.github/workflows/continuous-delivery.yml +++ b/.github/workflows/continuous-delivery.yml @@ -37,6 +37,7 @@ jobs: barman_plugin: ${{ env.BARMAN_PLUGIN }} minimal_tags: ${{ env.MINIMAL_TAGS }} standard_tags: ${{ env.STANDARD_TAGS }} + postgis_tags: ${{ env.POSTGIS_TAGS }} steps: - name: Checkout Code uses: actions/checkout@v7 @@ -74,7 +75,7 @@ jobs: run: | registry="ghcr.io/${{ github.repository_owner }}/postgresql-trunk" timestamp="$(date -u +%Y%m%d%H%M)" - for tgt in MINIMAL STANDARD; do + for tgt in MINIMAL STANDARD POSTGIS; do lower="${tgt,,}" echo "${tgt}_TAGS=${registry}:${PG_MAJOR}-${lower}-${DISTRO},${registry}:${PG_MAJOR}-${timestamp}-${lower}-${DISTRO}" >> $GITHUB_ENV done @@ -89,12 +90,32 @@ jobs: with: pg_major: ${{ needs.prepare.outputs.pg_major }} revision: ${{ github.sha }} - minimal_tags: ${{ needs.prepare.outputs.minimal_tags }} - standard_tags: ${{ needs.prepare.outputs.standard_tags }} + targets: | + minimal:${{ needs.prepare.outputs.minimal_tags }} + standard:${{ needs.prepare.outputs.standard_tags }} # On pull_request runs, only build each arch to validate the Dockerfile # compiles — don't push anything or publish a multi-arch manifest. push: ${{ github.event_name != 'pull_request' }} + # PostGIS periodically fails to build against PostgreSQL trunk. It's built + # as its own job, independent from build-pg, so a break there (best_effort + # keeps it from failing this run) doesn't block minimal/standard image + # publishing or the E2E job below, which only depends on build-pg. See #158. + build-postgis: + name: Build the Trunk of PostgreSQL (PostGIS, best-effort) + needs: prepare + uses: ./.github/workflows/reusable-build.yml + permissions: + contents: read + packages: write + with: + pg_major: ${{ needs.prepare.outputs.pg_major }} + revision: ${{ github.sha }} + targets: | + postgis:${{ needs.prepare.outputs.postgis_tags }} + push: ${{ github.event_name != 'pull_request' }} + best_effort: true + select-pg-image: name: Select the image built for E2E if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml index 3151d4d..87b3b59 100644 --- a/.github/workflows/reusable-build.yml +++ b/.github/workflows/reusable-build.yml @@ -1,17 +1,21 @@ name: Reusable Multi-Arch PostgreSQL Build -# Builds the minimal/standard images for linux/amd64 and linux/arm64 +# Builds one or more docker-bake.hcl targets for linux/amd64 and linux/arm64 # natively (one arch per job, no QEMU emulation) and publishes a multi-arch # manifest list for each requested tag by merging the two per-arch images # with `docker buildx imagetools create`. # -# PostGIS is currently excluded from the default docker-bake.hcl matrix -# (see #158), so it isn't wired through here either. -# # Compiling PostgreSQL from source is CPU-bound, so cross-building linux/arm64 # under QEMU emulation on an amd64 runner would be dramatically slower than a # native build. This workflow instead relies on GitHub-hosted native arm64 # runners (`ubuntu-24.04-arm`) for the arm64 leg. +# +# `best_effort: true` lets a caller build a target (e.g. postgis, which +# periodically fails against PostgreSQL trunk -- see #158) without a failure +# here failing the calling workflow run. This has to live inside this +# workflow's own jobs, rather than as `continue-on-error` on the caller's job, +# because GitHub Actions doesn't allow `continue-on-error` on a job that calls +# a reusable workflow via `uses:`. on: workflow_call: @@ -34,12 +38,8 @@ on: description: "Value used for the org.opencontainers.image.revision label/annotation" required: true type: string - minimal_tags: - description: "Comma-separated list of final (arch-less) tags for the minimal image" - required: true - type: string - standard_tags: - description: "Comma-separated list of final (arch-less) tags for the standard image" + targets: + description: "One ':' entry per line, e.g. 'minimal:tag1,tag2'" required: true type: string push: @@ -47,6 +47,11 @@ on: required: false type: boolean default: true + best_effort: + description: "When true, a build/publish failure doesn't fail this workflow (and so doesn't fail a caller job that just `uses:` it -- GitHub Actions doesn't allow `continue-on-error` on a job that calls a reusable workflow). Use for targets that are allowed to be broken, like postgis (#158)." + required: false + type: boolean + default: false outputs: images: description: "Newline-separated list of the final multi-arch images that were built and pushed (empty when push=false)" @@ -62,6 +67,7 @@ permissions: {} jobs: build: name: Build (linux/${{ matrix.arch }}) + continue-on-error: ${{ inputs.best_effort }} strategy: fail-fast: false matrix: @@ -90,30 +96,42 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - # For each image flavor, each tag is appended with - # an "-$arch" suffix (e.g. ...:19-minimal-trixie-arm64). + # For each image flavor, each tag is appended with an "-$arch" suffix + # (e.g. ...:19-minimal-trixie-arm64). `docker/bake-action` only builds the + # "default" group (docker-bake.hcl's `target "default"` matrix) unless + # told otherwise, so also collect the bake target names to build + # explicitly -- this is what lets a caller build just "postgis", which is + # intentionally kept out of the "default" group (see docker-bake.hcl). - name: Compute bake overrides id: overrides env: ARCH: ${{ matrix.arch }} PG_REPO: ${{ inputs.pg_repo }} PG_BRANCH: ${{ inputs.pg_branch }} - MINIMAL_TAGS: ${{ inputs.minimal_tags }} - STANDARD_TAGS: ${{ inputs.standard_tags }} + TARGETS: ${{ inputs.targets }} run: | + { + echo "targets<> "$GITHUB_OUTPUT" { echo "set<> "$GITHUB_OUTPUT" @@ -124,6 +142,7 @@ jobs: revision: ${{ inputs.revision }} pgMajor: ${{ inputs.pg_major }} with: + targets: ${{ steps.overrides.outputs.targets }} set: ${{ steps.overrides.outputs.set }} push: ${{ inputs.push }} @@ -131,6 +150,7 @@ jobs: name: Publish multi-arch manifests if: inputs.push needs: build + continue-on-error: ${{ inputs.best_effort }} runs-on: ubuntu-24.04 permissions: contents: read @@ -151,11 +171,12 @@ jobs: - name: Create and push multi-arch manifests id: merge env: - MINIMAL_TAGS: ${{ inputs.minimal_tags }} - STANDARD_TAGS: ${{ inputs.standard_tags }} + TARGETS: ${{ inputs.targets }} run: | images=() - for tags in "$MINIMAL_TAGS" "$STANDARD_TAGS"; do + while IFS= read -r target_tags; do + [[ -z "$target_tags" ]] && continue + tags="${target_tags#*:}" IFS=',' read -ra tag_list <<< "$tags" for tag in "${tag_list[@]}"; do docker buildx imagetools create \ @@ -164,7 +185,7 @@ jobs: "$tag-arm64" images+=("$tag") done - done + done <<< "$TARGETS" { echo 'images<