Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 68 additions & 19 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
# Builds every PostgreSQL version under binaries/ for every platform we ship,
# smoke-tests each tarball, and on a version tag publishes them all as one
# release. A release is only created when every build and test passed, so a
# release never carries one platform without the other.
# smoke-tests each tarball, and publishes them all as one release when a merge
# to master names a RELEASE_VERSION that has no release yet. A release is only
# created when every build and test passed, so it never carries one platform
# without the other.
#
# Only what changed is rebuilt. Each (version, platform) build is cached under
# the hash of everything that decides its binaries; a hit restores the tarballs
# and only re-runs the smoke test. GitHub scopes caches by branch: a PR sees
# master's caches but master never sees a PR's, so a version a PR changes is
# built once on the PR (to verify it) and once on master (to publish it), and
# a PR can never put a binary into master's cache.
#
# Platforms:
# linux_x86_64 ubuntu-24.04 pinned: the binaries link the runner's libicu
# (74) and glibc (2.38), so they run on Ubuntu
# 24.04 or newer; moving the runner moves that
# darwin_arm64 macos-14 Apple Silicon
#
# To release: bump RELEASE_VERSION in build_defs/postgres.build_defs, merge,
# then push the matching tag (git tag v0.0.N && git push origin v0.0.N).
# To release: bump RELEASE_VERSION in build_defs/postgres.build_defs and merge.
name: Release binaries

on:
pull_request:
push:
branches: [master]
tags: ["v*"]
workflow_dispatch:

permissions:
contents: read

# A new push to a PR supersedes its previous run (macOS runners are scarce);
# master and tag runs always finish.
# master runs always finish.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
Expand All @@ -51,6 +57,16 @@ jobs:
steps:
- uses: actions/checkout@v4

# Everything that decides this version's binaries on this platform.
- name: Restore this version's build
id: cache
uses: actions/cache/restore@v4
with:
path: dist
key: psql-${{ matrix.runner }}-${{ matrix.version }}-${{ hashFiles(format('binaries/{0}/**', matrix.version), 'build_defs/**', 'plugins/**', '.plzconfig', 'pleasew', 'release/smoke_test.sh', '.github/workflows/release.yaml') }}

# Also needed on a cache hit: the smoke test runs the binaries, and the
# macOS ones load Homebrew's icu4c and readline.
- name: Install build dependencies (Linux)
if: runner.os == 'Linux'
run: |
Expand All @@ -67,6 +83,7 @@ jobs:
test -d /opt/homebrew/opt/readline/lib/pkgconfig

- name: Build
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
# Retries only network failures (40+ jobs downloading at once from
Expand All @@ -80,6 +97,8 @@ jobs:
status=${PIPESTATUS[0]}
set -e
if [[ "$status" -eq 0 ]]; then
mkdir -p dist
cp $(./pleasew query output //binaries/${{ matrix.version }}/... | grep 'psql-.*\.tar\.gz$') dist/
exit 0
fi
if [[ "$attempt" -eq 3 ]] || ! grep -qE "$TRANSIENT" "$RUNNER_TEMP/build.log"; then
Expand All @@ -90,49 +109,79 @@ jobs:
done

- name: Smoke test
shell: bash
run: |
set -euo pipefail
for tarball in $(./pleasew query output //binaries/${{ matrix.version }}/... | grep 'psql-.*\.tar\.gz$'); do
tarballs=(dist/psql-*.tar.gz)
if [[ "${#tarballs[@]}" -ne 2 || ! -e "${tarballs[0]}" ]]; then
echo "expected a base and an AI tarball in dist/, found: ${tarballs[*]}"
exit 1
fi
for tarball in "${tarballs[@]}"; do
case "$(basename "$tarball")" in
psql-ai-*) variant=ai ;;
*) variant=base ;;
(psql-ai-*) variant=ai ;;
(*) variant=base ;;
esac
release/smoke_test.sh "$tarball" "$variant"
cp "$tarball" "$RUNNER_TEMP/"
done

# Saved only after the smoke test passed, so the cache never holds a
# build that failed it.
- name: Save this version's build
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: dist
key: ${{ steps.cache.outputs.cache-primary-key }}

- uses: actions/upload-artifact@v4
with:
name: psql-${{ matrix.version }}-${{ matrix.runner }}
path: ${{ runner.temp }}/psql-*.tar.gz
path: dist/psql-*.tar.gz
if-no-files-found: error

release:
if: startsWith(github.ref, 'refs/tags/v')
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
needs: build
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- name: Check the tag matches RELEASE_VERSION
- name: Is RELEASE_VERSION unreleased?
id: version
env:
GH_TOKEN: ${{ github.token }}
run: |
RELEASE_VERSION=$(sed -n 's/^RELEASE_VERSION = "\(.*\)"$/\1/p' build_defs/postgres.build_defs)
if [[ "$RELEASE_VERSION" != "$GITHUB_REF_NAME" ]]; then
echo "Tag $GITHUB_REF_NAME does not match RELEASE_VERSION $RELEASE_VERSION in build_defs/postgres.build_defs"
if [[ -z "$RELEASE_VERSION" ]]; then
echo "no RELEASE_VERSION in build_defs/postgres.build_defs"
exit 1
fi
echo "version=$RELEASE_VERSION" >> "$GITHUB_OUTPUT"
if gh release view "$RELEASE_VERSION" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
echo "$RELEASE_VERSION is already released; nothing to publish."
echo "publish=false" >> "$GITHUB_OUTPUT"
else
echo "publish=true" >> "$GITHUB_OUTPUT"
fi

- uses: actions/download-artifact@v4
if: steps.version.outputs.publish == 'true'
with:
path: dist
merge-multiple: true

- name: Publish
if: steps.version.outputs.publish == 'true'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_VERSION: ${{ steps.version.outputs.version }}
run: |
gh release create "$GITHUB_REF_NAME" dist/psql-*.tar.gz \
--title "PostgreSQL Release $GITHUB_REF_NAME" \
--notes "PostgreSQL binaries for linux_x86_64 and darwin_arm64, built and smoke-tested by the Release binaries workflow."
# Tagged at this merge commit: the release is exactly what was built
# and smoke-tested from it.
gh release create "$RELEASE_VERSION" dist/psql-*.tar.gz \
--target "$GITHUB_SHA" \
--title "PostgreSQL Release $RELEASE_VERSION" \
--notes "PostgreSQL binaries for linux_x86_64 and darwin_arm64, built and smoke-tested by the Release binaries workflow from $GITHUB_SHA."
Loading