Skip to content

fix: 3.9.1 follow-up for startup_parameters (#250) #54

fix: 3.9.1 follow-up for startup_parameters (#250)

fix: 3.9.1 follow-up for startup_parameters (#250) #54

Workflow file for this run

name: Build packages.
on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
permissions:
contents: read
jobs:
verify-version:
name: Verify tag version matches Cargo.toml
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Verify version
run: |
# Extract version from Cargo.toml
CARGO_VERSION=$(grep '^version =' Cargo.toml | head -1 | cut -d '"' -f2)
# Extract version from git tag (remove 'v' prefix)
TAG_VERSION=${GITHUB_REF_NAME#v}
echo "Cargo.toml version: $CARGO_VERSION"
echo "Git tag version: $TAG_VERSION"
# Compare versions
if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
echo "Error: Version mismatch between Cargo.toml ($CARGO_VERSION) and git tag ($TAG_VERSION)"
exit 1
else
echo "Version verification successful: $CARGO_VERSION matches $TAG_VERSION"
fi
vendor:
name: Release vendor.tar.gz.
needs: [verify-version]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Create vendor.tar.gz
run: |
make vendor.tar.gz &&
make vendor-licenses.txt &&
sha256sum vendor.tar.gz > vendor-sha256sum.txt
- name: Release vendor.tar.gz
if: startsWith(github.ref, 'refs/tags/')
run: |
gh release upload ${{ github.ref_name }} ./vendor.tar.gz &&
gh release upload ${{ github.ref_name }} ./vendor-sha256sum.txt &&
gh release upload ${{ github.ref_name }} ./vendor-licenses.txt
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
deb:
strategy:
matrix:
image: ["ubuntu:22.04", "ubuntu:24.04", "ubuntu:26.04", "debian:12"]
name: Build deb packages.
needs: [verify-version]
runs-on: ubuntu-latest
container:
image: ${{ matrix.image }}
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install packages
run: |
apt-get update && apt-get install git cmake wget build-essential pkg-config libssl-dev clang g++ perl patch -y --option=Dpkg::Options::=--force-confdef &&
wget -q https://static.rust-lang.org/dist/rust-1.87.0-x86_64-unknown-linux-gnu.tar.gz -O /tmp/rust.tar.gz &&
cd /tmp && tar xf rust.tar.gz && ./rust-*-x86_64-unknown-linux-gnu/install.sh
- name: Build binaries in release mode
run: JEMALLOC_SYS_WITH_MALLOC_CONF="dirty_decay_ms:30000,muzzy_decay_ms:30000,background_thread:true,metadata_thp:auto" cargo build --release
- name: Prepare output dir
run: mkdir -p ./build_package/usr/bin && install ./target/release/pg_doorman ./build_package/usr/bin && install ./target/release/patroni_proxy ./build_package/usr/bin && mkdir -p ./out/
- name: Check versions
run: ./build_package/usr/bin/pg_doorman --version && ./build_package/usr/bin/patroni_proxy --version && cat /etc/debian_version
- name: Fix package name
run: |
export PACKAGE_NAME=pg_doorman-${{ matrix.image }}.deb &&
export PACKAGE_NAME=$(echo $PACKAGE_NAME | sed 's|:|-|g') &&
echo PACKAGE_NAME=$PACKAGE_NAME >> $GITHUB_ENV
- name: Package
uses: bpicode/github-action-fpm@7502b06a5a58390398d4002bd284f8cb3caae6eb
with:
fpm_opts: "--chdir ./build_package/ --deb-no-default-config-files --depends openssl --name pg-doorman --version ${{ github.ref_name }} -t deb -s dir"
- name: Prepare package
run: mkdir -p ./package/ && mv *.deb ./package/${{ env.PACKAGE_NAME }} && ls -lah ./package/
- name: Test package
run: dpkg -c ./package/${{ env.PACKAGE_NAME }} && dpkg -i ./package/${{ env.PACKAGE_NAME }} && pg_doorman --version
- name: Upload package
uses: actions/upload-artifact@v4
with:
name: ${{ env.PACKAGE_NAME }}
path: ./package/${{ env.PACKAGE_NAME }}
rpm:
strategy:
matrix:
image: ["rockylinux:9", "rockylinux:8", "almalinux:9"]
name: Build rpm packages.
needs: [verify-version]
runs-on: ubuntu-latest
container:
image: ${{ matrix.image }}
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install packages
run: |
yum install -y @"Development Tools" openssl-devel wget perl patch &&
wget -q https://static.rust-lang.org/dist/rust-1.87.0-x86_64-unknown-linux-gnu.tar.gz -O /tmp/rust.tar.gz &&
cd /tmp && tar xf rust.tar.gz && ./rust-*-x86_64-unknown-linux-gnu/install.sh
- name: Build binaries in release mode
run: JEMALLOC_SYS_WITH_MALLOC_CONF="dirty_decay_ms:30000,muzzy_decay_ms:30000,background_thread:true,metadata_thp:auto" cargo build --release
- name: Prepare output dir
run: mkdir -p ./build_package/usr/bin && install ./target/release/pg_doorman ./build_package/usr/bin && install ./target/release/patroni_proxy ./build_package/usr/bin && mkdir -p ./out/
- name: Check versions
run: ./build_package/usr/bin/pg_doorman --version && ./build_package/usr/bin/patroni_proxy --version && cat /etc/system-release
- name: Fix package name
run: |
export PACKAGE_NAME=pg_doorman-${{ matrix.image }}.rpm &&
export PACKAGE_NAME=$(echo $PACKAGE_NAME | sed 's|:|-|g') &&
echo PACKAGE_NAME=$PACKAGE_NAME >> $GITHUB_ENV
- name: Package
uses: bpicode/github-action-fpm@7502b06a5a58390398d4002bd284f8cb3caae6eb
with:
fpm_opts: "--chdir ./build_package/ --depends openssl --name pg-doorman --version ${{ github.ref_name }} -t rpm -s dir"
- name: Prepare package
run: mkdir -p ./package/ && mv *.rpm ./package/${{ env.PACKAGE_NAME }} && ls -lah ./package/
- name: Test package
run: rpm -qlp ./package/${{ env.PACKAGE_NAME }} && rpm -i ./package/${{ env.PACKAGE_NAME }} && pg_doorman --version
- name: Upload package
uses: actions/upload-artifact@v4
with:
name: ${{ env.PACKAGE_NAME }}
path: ./package/${{ env.PACKAGE_NAME }}
static-binary:
name: Build static musl binary.
needs: [verify-version]
runs-on: ubuntu-latest
container:
image: rust:1.87.0-alpine
env:
JEMALLOC_SYS_WITH_MALLOC_CONF: "dirty_decay_ms:30000,muzzy_decay_ms:30000,background_thread:true,metadata_thp:auto"
OPENSSL_STATIC: "1"
PKG_CONFIG_ALL_STATIC: "1"
steps:
- name: Install dependencies
run: apk add --no-cache musl-dev openssl-dev openssl-libs-static pkgconfig perl make git file
- name: Checkout Repository
uses: actions/checkout@v4
- name: Build static binary
run: cargo build --release --target x86_64-unknown-linux-musl
- name: Verify static linking
run: |
file target/x86_64-unknown-linux-musl/release/pg_doorman
file target/x86_64-unknown-linux-musl/release/patroni_proxy
file target/x86_64-unknown-linux-musl/release/pg_doorman | grep -E "static(-pie)? linked"
file target/x86_64-unknown-linux-musl/release/patroni_proxy | grep -E "static(-pie)? linked"
- name: Check versions
run: |
target/x86_64-unknown-linux-musl/release/pg_doorman --version
target/x86_64-unknown-linux-musl/release/patroni_proxy --version
- name: Prepare artifacts
run: |
mkdir -p ./artifacts
cp target/x86_64-unknown-linux-musl/release/pg_doorman ./artifacts/pg_doorman-linux-amd64-static
cp target/x86_64-unknown-linux-musl/release/patroni_proxy ./artifacts/patroni_proxy-linux-amd64-static
- name: Upload pg_doorman static binary
uses: actions/upload-artifact@v4
with:
name: pg_doorman-linux-amd64-static
path: ./artifacts/pg_doorman-linux-amd64-static
- name: Upload patroni_proxy static binary
uses: actions/upload-artifact@v4
with:
name: patroni_proxy-linux-amd64-static
path: ./artifacts/patroni_proxy-linux-amd64-static
release-packages:
name: Release packages.
needs: ['deb', 'rpm']
runs-on: ubuntu-latest
permissions:
contents: write
strategy:
matrix:
package:
- "pg_doorman-rockylinux-9.rpm"
- "pg_doorman-rockylinux-8.rpm"
- "pg_doorman-almalinux-9.rpm"
- "pg_doorman-ubuntu-22.04.deb"
- "pg_doorman-ubuntu-24.04.deb"
- "pg_doorman-ubuntu-26.04.deb"
- "pg_doorman-debian-12.deb"
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Download package
uses: actions/download-artifact@v4
with:
name: "${{ matrix.package }}"
path: "./packages/"
- name: Release package
if: startsWith(github.ref, 'refs/tags/')
run: gh release upload ${{ github.ref_name }} ./packages/${{ matrix.package }}
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
release-static-binaries:
name: Release static binaries.
needs: ['static-binary']
runs-on: ubuntu-latest
permissions:
contents: write
strategy:
matrix:
package:
- "pg_doorman-linux-amd64-static"
- "patroni_proxy-linux-amd64-static"
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Download package
uses: actions/download-artifact@v4
with:
name: "${{ matrix.package }}"
path: "./packages/"
- name: Release package
if: startsWith(github.ref, 'refs/tags/')
run: gh release upload ${{ github.ref_name }} ./packages/${{ matrix.package }}
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
# Release pipeline for the public docker image is split into three
# jobs so the public :latest / :vX.Y.Z tags only move after smoke
# validates the artefact:
#
# docker-image push immutable :sha-<commit> (amd64+arm64)
# docker-image-smoke pull :sha-<commit>, run end-to-end smoke
# docker-image-promote retag digest to :vX.Y.Z and :latest
#
# Previously docker-image pushed both :latest and :ref_name immediately
# and smoke ran after; a broken multi-arch build would publish before
# the runtime check failed.
docker-image:
name: Build docker image (push immutable sha tag)
needs: [verify-version]
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
outputs:
digest: ${{ steps.docker-build.outputs.digest }}
sha_tag: ${{ steps.tags.outputs.sha_tag }}
steps:
- uses: actions/checkout@v4
- name: Set up QEMU for cross-arch build
# buildx needs binfmt for arm64 emulation. Without an explicit
# setup the runner falls back to whatever binfmt state the host
# happens to have, which makes arm64 builds flaky.
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.TOKEN }}
- name: Compute image tags
id: tags
run: |
IMAGE_BASE="ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}"
SHA_TAG="${IMAGE_BASE}:sha-${{ github.sha }}"
echo "image_base=${IMAGE_BASE}" >> "$GITHUB_OUTPUT"
echo "sha_tag=${SHA_TAG}" >> "$GITHUB_OUTPUT"
echo "Will push to ${SHA_TAG}"
- name: Build and push (sha tag only)
id: docker-build
uses: docker/build-push-action@v6
with:
push: true
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
tags: ${{ steps.tags.outputs.sha_tag }}
docker-image-smoke:
name: Smoke-test pushed image (amd64 E2E + arm64 --version)
needs: [verify-version, docker-image]
runs-on: ubuntu-latest
permissions:
packages: read
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up QEMU for arm64 execution
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.TOKEN }}
- name: Pull pushed image (amd64)
# GHCR manifest visibility is eventually consistent after a fresh
# push; one retry round covers the most common 1-2 second lag
# without masking a real outage.
uses: nick-fields/retry@v3
with:
timeout_minutes: 5
max_attempts: 5
retry_wait_seconds: 15
command: docker pull --platform linux/amd64 "${{ needs.docker-image.outputs.sha_tag }}"
- name: End-to-end smoke (amd64)
# Same script developers run locally via `make docker-smoke`.
# Brings up a postgres:17 sidecar, runs `pg_doorman generate`,
# starts pg_doorman on the generated config, and verifies SELECT 1
# plus a non-superuser current_user/current_database round-trip.
run: scripts/docker-smoke.sh "${{ needs.docker-image.outputs.sha_tag }}"
- name: Pull pushed image (arm64)
uses: nick-fields/retry@v3
with:
timeout_minutes: 5
max_attempts: 5
retry_wait_seconds: 15
command: docker pull --platform linux/arm64 "${{ needs.docker-image.outputs.sha_tag }}"
- name: 'arm64: pg_doorman --version matches tag'
# Full E2E under QEMU is slow; --version is enough to catch a
# broken arm64 build (linker mismatch, missing dynamic library,
# wrong target triple). Without this check the arm64 manifest
# entry can exist with a broken binary inside.
run: |
EXPECTED=$(grep -m1 '^version = ' Cargo.toml | cut -d'"' -f2)
ACTUAL=$(docker run --rm --platform linux/arm64 \
"${{ needs.docker-image.outputs.sha_tag }}" pg_doorman --version | awk '{print $NF}')
echo "Cargo.toml: ${EXPECTED}"
echo "arm64 bin: ${ACTUAL}"
if [ "${ACTUAL}" != "${EXPECTED}" ]; then
echo "::error::arm64 pg_doorman version (${ACTUAL}) does not match Cargo.toml (${EXPECTED})"
exit 1
fi
- name: 'arm64: patroni_proxy --version'
run: |
docker run --rm --platform linux/arm64 \
"${{ needs.docker-image.outputs.sha_tag }}" patroni_proxy --version
docker-image-promote:
name: Promote sha tag to release tags (only after smoke)
needs: [verify-version, docker-image, docker-image-smoke]
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v4
with:
# Need the full tag list so we can check whether this tag is
# the highest stable semver before promoting :latest. Default
# checkout fetches only HEAD.
fetch-depth: 0
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.TOKEN }}
- name: Retag image digest to release tags
env:
DIGEST: ${{ needs.docker-image.outputs.digest }}
IMAGE_BASE: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
GITHUB_REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
# Always retag the smoked digest under the release tag.
# buildx imagetools touches only the registry manifest list,
# so this is a metadata operation, not a re-push.
docker buildx imagetools create \
--tag "${IMAGE_BASE}:${GITHUB_REF_NAME}" \
"${IMAGE_BASE}@${DIGEST}"
echo "Promoted ${GITHUB_REF_NAME} -> ${DIGEST}"
# :latest moves only for plain stable semver tags vX.Y.Z and
# only when this tag is currently the highest such tag. That
# keeps reruns of older releases and prerelease tags from
# silently rolling :latest back.
if [[ ! "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Skipping :latest: ${GITHUB_REF_NAME} is not a stable semver tag"
exit 0
fi
# `|| true` shields the substitution from `set -euo pipefail`
# when grep finds no matching tag (it would exit 1 and abort
# the whole step). That state only happens on a brand-new
# repository before its first stable tag — defensive, not
# something pg_doorman hits today.
MAX_STABLE=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
| head -1 || true)
if [[ -z "${MAX_STABLE}" ]]; then
echo "Skipping :latest: no stable semver tag in the repository"
exit 0
fi
if [[ "${MAX_STABLE}" != "${GITHUB_REF_NAME}" ]]; then
echo "Skipping :latest: highest stable tag is ${MAX_STABLE}, not ${GITHUB_REF_NAME}"
exit 0
fi
docker buildx imagetools create \
--tag "${IMAGE_BASE}:latest" \
"${IMAGE_BASE}@${DIGEST}"
echo "Promoted :latest -> ${GITHUB_REF_NAME}"