Skip to content

Add update+upgrade (U&U) test infrastructure (stack 2/3) #13

Add update+upgrade (U&U) test infrastructure (stack 2/3)

Add update+upgrade (U&U) test infrastructure (stack 2/3) #13

Workflow file for this run

name: CI
on:
push:
branches:
- master
pull_request:
env:
PGUSER: postgres
jobs:
# Style linter (https://github.com/Postgres-Extensions/linter, vendored at
# .vendor/linter -- lint.mk is the thin local hand-off, see its comment).
# No `needs:` on anything: this is the cheapest possible check (no
# database, no container beyond a plain checkout, seconds to run), so it
# should never be waiting in a queue behind -- or racing for a runner slot
# against -- the PG matrix below. It's gated behind nothing and everything
# else of any real weight is gated behind it (see the `test` job's needs).
# Deliberately checked out WITHOUT submodules -- `make lint` is the same
# command a developer runs locally, and lint.mk self-initializes the
# submodule on first use. Using the exact same entry point here is what
# actually proves that self-init works, rather than papering over it with
# a submodules: true checkout.
lint:
name: 🧹 SQL Lint
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Lint SQL
run: make lint
# Cheap gate that lets the test matrix below skip itself on commits that
# touch only docs. Runs on every push/pull_request unconditionally (no
# paths-ignore on the workflow itself) -- a workflow-level paths-ignore
# would skip this job too on a docs-only push, and the required
# all-checks-passed check would then never report and get stuck Pending in
# branch protection.
#
# Also derives the supported-PostgreSQL-major list the test job's matrix
# consumes, from a single pair of constants below, so adding or dropping a
# major is a one-line edit here instead of touching the matrix directly.
changes:
name: 🔍 Detect changes & derive PG matrix
runs-on: ubuntu-latest
outputs:
docs_only: ${{ steps.diff.outputs.docs_only }}
supported_pg: ${{ steps.pg.outputs.supported_pg }}
steps:
- name: Check out the repo
uses: actions/checkout@v4
with:
# Full history needed so BASE and HEAD below are both reachable
# for `git diff`.
fetch-depth: 0
- name: Compute per-push changed files
id: diff
run: |
# Fail-safe FIRST, before anything else runs: any early exit below
# (an unusable BASE/HEAD, a failed git diff) leaves this in place,
# so the test matrix only ever gets skipped after actually proving
# the push is docs-only.
echo "docs_only=false" >> "$GITHUB_OUTPUT"
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE="${{ github.event.pull_request.base.sha }}"
HEAD="${{ github.event.pull_request.head.sha }}"
else
BASE="${{ github.event.before }}"
HEAD="${{ github.event.after }}"
fi
echo "base=$BASE"
echo "head=$HEAD"
# A missing HEAD, or an all-zeros BASE (a new branch's first push,
# where GitHub reports no prior commit), means no real diff can be
# computed -- leave the fail-safe in place.
if [ -z "$HEAD" ] || [ -z "$BASE" ] || [[ "$BASE" =~ ^0+$ ]]; then
exit 0
fi
CHANGED=$(git diff --name-only "$BASE" "$HEAD") || exit 0
[ -z "$CHANGED" ] && exit 0
DOCS_ONLY=true
while IFS= read -r f; do
if ! [[ "$f" =~ \.(md|asc)$ ]]; then
DOCS_ONLY=false
break
fi
done <<< "$CHANGED"
echo "changed files:"
echo "$CHANGED"
echo "docs_only=$DOCS_ONLY" >> "$GITHUB_OUTPUT"
- name: Derive the supported-PostgreSQL-major list
id: pg
run: |
# SINGLE SOURCE OF TRUTH for the supported PostgreSQL majors. To
# add or drop a major, edit only the two constants below; the test
# job's matrix derives its version list from them. Do NOT hardcode
# a supported major directly in a job matrix.
#
# NEWEST -- highest PostgreSQL major tested.
# CURRENT_FLOOR -- oldest major supported. object_reference
# requires cat_tools at both build and runtime,
# and cat_tools's own current release declares
# PostgreSQL 12 as its build floor, so
# object_reference can't usefully claim support
# for anything older either.
NEWEST=18
CURRENT_FLOOR=12
supported=$(seq "$NEWEST" -1 "$CURRENT_FLOOR")
# Emit a JSON array for the test job's matrix to consume via
# fromJSON.
json=$(printf '%s\n' $supported | paste -sd, - | sed 's/^/[/; s/$/]/')
echo "supported_pg=$json" >> "$GITHUB_OUTPUT"
test:
# Gated behind lint too, not just changes: lint is nearly free to run,
# so a baseline that's already broken by a style violation shouldn't
# also tie up runner slots on the much heavier PG matrix below.
# success() must be written explicitly -- GitHub only assumes success()
# as a job's default when the job has no if: at all.
needs: [changes, lint]
if: success() && needs.changes.outputs.docs_only != 'true'
strategy:
matrix:
# Supported majors, from the single source in the changes job.
pg: ${{ fromJSON(needs.changes.outputs.supported_pg) }}
name: 🐘 PostgreSQL ${{ matrix.pg }}
runs-on: ubuntu-latest
container: pgxn/pgxn-tools
steps:
- name: Start PostgreSQL ${{ matrix.pg }}
run: pg-start ${{ matrix.pg }}
- name: Check out the repo
uses: actions/checkout@v4
- name: Test on PostgreSQL ${{ matrix.pg }}
run: make test
# A single stable check name for use as a required status check in branch
# protection rules. Matrix jobs produce check names like "🐘 PostgreSQL 14"
# which would all need to be listed individually and updated whenever the
# matrix changes. This job passes if all others passed or were skipped
# (e.g. test, on a docs-only push), and fails if any failed or were
# cancelled.
all-checks-passed:
needs: [changes, lint, test]
if: always()
runs-on: ubuntu-latest
steps:
- name: Check all jobs passed or were skipped
run: |
if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
echo "One or more jobs failed or were cancelled"
exit 1
fi