Hi, We had an unconference session at the PGConf.dev 2026. Here are the notes [1] (Thank you Lukas for taking and publishing the notes!). Some important points are:
- We can use Github Actions for now, and revisit alternatives later. - We won't have BSDs for the first version. - Backpatch until PG15, where CI introduced. - No need to test VS 2019, we can continue with VS 2022. - Deal with making logs public later. On Tue, 19 May 2026 at 01:27, Nazir Bilal Yavuz <[email protected]> wrote: > > I think we can merge these two patches and move forward that way. I am > planning to review your patch and see what I can come up with to get > it to a committable state. Here is the v2, I took Jelte's patch and reviewed & merged it with my patch. Updates and questions are: 1- I continued to use Jelte's container method (Linux tasks only for now, BSD tasks will be included in the future) because I think that is the future-proof way since we might want to generate our container images in the future. Also, up-to-date Debian images can be tested with this way; otherwise we would need to use Ubuntu 24.04. 2- io_uring tests work on the Linux Meson task. 3- I didn't put commands to helper scripts for now. I think it is a good thing to have a helper script but it would be better to have this helper script after the first version is committed since it can extend the timeline. Also, I found that having all commands in one file makes debugging easier. 4- FreeBSD task has these options: PG_TEST_INITDB_EXTRA_OPTS: >- -c debug_copy_parse_plan_trees=on -c debug_write_read_parse_plan_trees=on -c debug_raw_expression_coverage_test=on -c debug_parallel_query=regress Since we won't have FreeBSD for the first version. I put these options to the MacOS task but I couldn't decide where to put 'PG_TEST_PG_UPGRADE_MODE: --link'. Also, I am planning to work on back patches when we agree on the upstream one. Does that sound good? CI run link of attached patch: https://github.com/nbyavuz/postgres/actions/runs/26398508250 [1] https://wiki.postgresql.org/wiki/PGConf.dev_2026_Developer_Unconference -- Regards, Nazir Bilal Yavuz Microsoft
From 4f66a8a93e6090fd2d127be0972615297ec48c0f Mon Sep 17 00:00:00 2001 From: Nazir Bilal Yavuz <[email protected]> Date: Mon, 25 May 2026 14:28:42 +0300 Subject: [PATCH v2] Add GitHub Actions yaml file Cirrus CI is shutting down. This is an initial attempt to get a GitHub Actions CI working. --- .github/workflows/ci.yml | 1125 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1125 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..6d20068727c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,1125 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: Github Actions CI + +on: + push: + branches: [ "*" ] + +# Default to the minimum privilege the jobs need (just reading the repo +# contents during checkout). Individual jobs override this when they need +# more, e.g. `cancel-previous` needs `actions: write` to cancel runs. +permissions: + contents: read + +# NB: intentionally NO workflow-level `concurrency:` block. The native +# concurrency mechanism makes a new run wait for the previous one to fully +# cancel before it starts — which can take a while. Instead the +# `cancel-previous` job below fires a cancel API call asynchronously, +# so the new run gets going immediately. On master the cancel job is skipped, +# so every push runs to completion. + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/'. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + +jobs: + # Cancel any older in-progress runs of this workflow on the same branch. + # Skipped on master so every push there runs to completion. + cancel-previous: + name: Cancel previous runs + if: github.ref != 'refs/heads/master' + runs-on: ubuntu-latest + timeout-minutes: 1 + permissions: + actions: write + steps: + - name: Cancel + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + run: | + # Look up this run's workflow id to cancel them. + workflow_id=$(gh run view "${{ github.run_id }}" -R "$REPO" \ + --json workflowDatabaseId --jq .workflowDatabaseId) + gh run list \ + -R "$REPO" \ + --workflow="$workflow_id" \ + --branch="${{ github.ref_name }}" \ + --status=in_progress \ + --json databaseId \ + --jq '.[].databaseId' \ + --limit 50 \ + | while read -r id; do + if [ "$id" != "${{ github.run_id }}" ]; then + echo "Cancelling run $id" + gh run cancel "$id" -R "$REPO" + fi + done + + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the per-OS job `if:` conditions. + setup: + name: Determine enabled OSes + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os="${CI_OS_ONLY_JOBS}" + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | grep -E '^ci-os-only: ' | head -1 | sed 's/^ci-os-only: //') + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.run_id }} + restore-keys: ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + # Can't change the container's kernel.core_pattern; the postgres + # user can't write to / normally. Make / writable. + chown root:postgres / + chmod g+rwx / + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + if-no-files-found: ignore + + + # SPECIAL: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # + # Enable a reasonable set of sanitizers. Use the linux task for that, as + # it's one of the fastest tasks (without sanitizers). Also several of the + # sanitizers work best on linux. + # + # The overhead of alignment sanitizer is low, undefined behaviour has + # moderate overhead. Test alignment sanitizer in the meson task, as it + # does both 32 and 64 bit builds and is thus more likely to expose + # alignment bugs. + # + # Address sanitizer in contrast is somewhat expensive. Enable it in the + # autoconf task, as the meson task tests both 32 and 64bit. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux-autoconf: + name: Linux - Debian Trixie - Autoconf + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net" + + SANITIZER_FLAGS: -fsanitize=address + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all -fsanitize=address + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all -fsanitize=address + LDFLAGS: -fsanitize=address + CC: ccache gcc + CXX: ccache g++ + + PG_TEST_PG_COMBINEBACKUP_MODE: --copy-file-range + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-autoconf-${{ github.run_id }} + restore-keys: ccache-linux-autoconf- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + + # Hosts for the load balance test + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + # Normally, the "relation segment" code basically has no coverage in our + # tests, because we (quite reasonably) don't generate tables large + # enough in tests. We've had plenty bugs that we didn't notice due the + # code not being exercised much. Thus specify a very small segment size + # here. Use a non-power-of-two segment size, given we currently allow + # that. + - name: Configure + run: | + su postgres <<EOF + set -e + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + \ + ${LINUX_CONFIGURE_FEATURES} \ + \ + CLANG="ccache clang" + EOF + + - name: Build + run: su postgres -c "make -s -j${BUILD_JOBS} world-bin" + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-autoconf-logs-${{ github.run_id }} + path: | + **/*.log + **/*.diffs + **/regress_log_* + if-no-files-found: ignore + + + # SPECIAL: + # - Uses undefined behaviour and alignment sanitizers, sanitizer failures + # are typically printed in the server log + # - Test both 64bit and 32 bit builds + # - Uses io_method=io_uring + # - Uses meson feature autodetection + linux-meson: + name: Linux - Debian Trixie - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # See linux-autoconf for the details. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # flip kernel.io_uring_disabled (default 2 on recent GH runner + # kernels, which makes io_uring_setup() return EPERM for everyone) + # and to set kernel.core_pattern. + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + CCACHE_MAXSIZE: "400M" # tests two different builds + DEBUGINFOD_URLS: "https://debuginfod.debian.net" + + SANITIZER_FLAGS: -fsanitize=alignment,undefined + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all -fsanitize=alignment,undefined + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all -fsanitize=alignment,undefined + LDFLAGS: -fsanitize=alignment,undefined + CC: ccache gcc + CXX: ccache g++ + + MESON_FEATURES: >- + -Duuid=e2fs + + PG_TEST_INITDB_EXTRA_OPTS: >- + -c io_method=io_uring + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-meson-${{ github.run_id }} + restore-keys: ccache-linux-meson- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + + # Enable io_uring; GH runner kernels default to 2 (disabled). + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure (64-bit) + run: | + su postgres <<EOF + set -e + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + ${MESON_FEATURES} \ + --buildtype=debug \ + -Dllvm=enabled \ + build + EOF + + # Also build & test in a 32bit build - it's gotten rare to test that + # locally. + - name: Configure (32-bit) + run: | + su postgres <<EOF + set -e + export CC='ccache gcc -m32' + export CXX='ccache g++ -m32' + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + ${MESON_FEATURES} \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build-32 + EOF + + - name: Build (64-bit) + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + EOF + + - name: Build (32-bit) + run: | + su postgres <<EOF + set -e + ninja -C build-32 -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build-32 -t missingdeps + EOF + + - name: Test world (64-bit) + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + EOF + # so that we don't upload 64-bit logs if 32-bit fails + rm -rf build/ + + # There's currently no coverage of icu with LANG=C in the buildfarm. We + # can easily provide some here by running one of the sets of tests that + # way. Newer versions of python insist on changing the LC_CTYPE away + # from C, prevent that with PYTHONCOERCECLOCALE. + - name: Test world (32-bit) + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + PYTHONCOERCECLOCALE=0 LANG=C meson test ${MTEST_ARGS} -C build-32 --num-processes ${TEST_JOBS} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-meson-logs-${{ github.run_id }} + path: | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Sequoia - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for Github Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.run_id }} + restore-keys: ccache-macos- + + # Install dependencies via Homebrew rather than Macports. On stock + # GH runners macports requires a heavy bootstrap, and the relevant + # Postgres deps are all available in brew. + - name: Install dependencies + run: | + brew update + brew install \ + ccache meson openldap [email protected] tcl-tk + # IPC::Run via cpanm (system perl) + sudo cpan -T -i IPC::Run IO::Tty + + - name: Configure + run: | + # These formulae are keg-only (not symlinked into $(brew --prefix)), + # so pkg-config wouldn't find them via the default search path. + # lz4, zstd and other non-keg-only deps are picked up automatically. + for f in openssl@3 icu4c krb5 openldap; do + PKG_CONFIG_PATH="$(brew --prefix $f)/lib/pkgconfig:${PKG_CONFIG_PATH}" + done + export PKG_CONFIG_PATH + extra_inc= + extra_lib= + for f in gettext krb5; do + prefix=$(brew --prefix $f) + extra_inc="${extra_inc:+$extra_inc,}${prefix}/include" + extra_lib="${extra_lib:+$extra_lib,}${prefix}/lib" + done + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs="${extra_inc}" \ + -Dextra_lib_dirs="${extra_lib}" \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited + ulimit -n 1024 + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + if-no-files-found: ignore + + + windows-vs: + name: Windows - Server 2022, VS 2022 - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'c:\pgsock\' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Pin PYTHONHOME to the Python 3.12 prefix, and prepend that prefix + # to PATH so its python3.dll wins the DLL search. + - name: Pin Python prefix on PATH and PYTHONHOME + shell: pwsh + run: | + $prefix = (python -c "import sys; print(sys.prefix)").Trim() + Add-Content $env:GITHUB_ENV "PYTHONHOME=$prefix" + Add-Content $env:GITHUB_PATH $prefix + Write-Host "PYTHONHOME=$prefix" + Write-Host "Prepended $prefix to PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=c:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in c:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "c:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup sock dir + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=c:\openssl\1.1\lib -Dextra_include_dirs=c:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + crashlog-*.txt + if-no-files-found: ignore + + + windows-mingw: + name: Windows - Server 2022, MinGW64 - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'c:\pgsock\' + TAR: "c:/windows/system32/tar.exe" + # for mingw plpython to find its installation + PYTHONHOME: D:/a/_temp/msys64/ucrt64 + + MSYS: winjitdebug + CHERE_INVOKING: 1 + + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: >- + git bison flex make diffutils + mingw-w64-ucrt-x86_64-ccache + mingw-w64-ucrt-x86_64-docbook-xml + mingw-w64-ucrt-x86_64-gcc + mingw-w64-ucrt-x86_64-icu + mingw-w64-ucrt-x86_64-libbacktrace + mingw-w64-ucrt-x86_64-libxml2 + mingw-w64-ucrt-x86_64-libxslt + mingw-w64-ucrt-x86_64-lz4 + mingw-w64-ucrt-x86_64-make + mingw-w64-ucrt-x86_64-meson + mingw-w64-ucrt-x86_64-perl + mingw-w64-ucrt-x86_64-pkg-config + mingw-w64-ucrt-x86_64-python-cryptography + mingw-w64-ucrt-x86_64-python-pip + mingw-w64-ucrt-x86_64-python-pytest + mingw-w64-ucrt-x86_64-readline + mingw-w64-ucrt-x86_64-zlib + + - name: Install IPC::Run for tap tests + shell: msys2 {0} + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup sock dir + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.run_id }} + restore-keys: ccache-mingw- + + - name: Configure + shell: msys2 {0} + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + shell: msys2 {0} + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + shell: msys2 {0} + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + crashlog-*.txt + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.run_id }} + restore-keys: ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warning + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warning + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warning + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warning + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw cross compile + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Docs build + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' -- 2.47.3
