# Test minimum and maximum ABI compatible postgres version
#
# Build timescaledb against specific postgres version and then run our
# tests with that library loaded in a different postgres version.
# This is to detect changes in required minimum/maximum postgres versions
# for our built packages.
# This test is expected to fail when upstream does ABI incompatible changes
# in a new minor postgresql version.
name: ABI Test
"on":
  schedule:
    # run daily 20:00 on main branch
    - cron: '0 20 * * *'
  push:
    branches:
      - prerelease_test
      - trigger/abi
  pull_request:
    paths: .github/workflows/abi.yaml
  workflow_dispatch:
jobs:
  config:
    runs-on: ubuntu-latest
    outputs:
      pg15_abi_min: ${{ steps.config.outputs.pg15_abi_min }}
      pg16_abi_min: ${{ steps.config.outputs.pg16_abi_min }}
      pg17_abi_min: ${{ steps.config.outputs.pg17_abi_min }}
      pg18_abi_min: ${{ steps.config.outputs.pg18_abi_min }}
      pg15_latest: ${{ steps.config.outputs.pg15_latest }}
      pg16_latest: ${{ steps.config.outputs.pg16_latest }}
      pg17_latest: ${{ steps.config.outputs.pg17_latest }}
      pg18_latest: ${{ steps.config.outputs.pg18_latest }}

    steps:
    - name: Checkout source code
      uses: actions/checkout@v4
    - name: Read configuration
      id: config
      run: python .github/gh_config_reader.py

  abi_test:
    name: ABI Test ${{ matrix.dir }} PG${{ matrix.pg }}
    runs-on: ubuntu-latest
    needs: config
    strategy:
      fail-fast: false
      matrix:
        pg: [ 15, 16, 17, 18 ]
        ignores:
          - 'net telemetry'
        include:
          - pg: 15
            builder: ${{ fromJson(needs.config.outputs.pg15_abi_min) }}
            tester: ${{ fromJson(needs.config.outputs.pg15_latest) }}
          - pg: 16
            builder: ${{ fromJson(needs.config.outputs.pg16_abi_min) }}
            tester: ${{ fromJson(needs.config.outputs.pg16_latest) }}
          - pg: 17
            builder: ${{ fromJson(needs.config.outputs.pg17_abi_min) }}
            tester: ${{ fromJson(needs.config.outputs.pg17_latest) }}
          - pg: 18
            builder: ${{ fromJson(needs.config.outputs.pg18_abi_min) }}
            tester: ${{ fromJson(needs.config.outputs.pg18_latest) }}

    steps:

    - name: Checkout TimescaleDB
      uses: actions/checkout@v4

    - name: Build extension with ${{ matrix.builder }}
      run: |
        BUILDER_IMAGE="postgres:${{matrix.builder}}-alpine"

        docker pull ${BUILDER_IMAGE}
        docker buildx imagetools inspect ${BUILDER_IMAGE}
        docker run -i --rm -v $(pwd):/mnt -e EXTRA_PKGS="${EXTRA_PKGS}" ${BUILDER_IMAGE} bash <<"EOF"
          apk add cmake gcc make build-base git ${EXTRA_PKGS}
          # We run the same extension on different docker images, old versions
          # have OpenSSL 1.1 and the new versions have OpenSSL 3, so we try to
          # pin the 1.1. Note that depending on PG version, both images might
          # have 1.1 or 3, so we first try to install the versioned 1.1 package,
          # and if it's not present, it means the unversioned package is 1.1, so
          # we install it.
          apk add openssl1.1-compat-dev || apk add openssl-dev
          git config --global --add safe.directory /mnt
          cd /mnt
          BUILD_DIR=build_abi BUILD_FORCE_REMOVE=true ./bootstrap
          make -C build_abi install
          mkdir -p build_abi/install_ext build_abi/install_lib
          cp `pg_config --sharedir`/extension/timescaledb*.{control,sql} build_abi/install_ext
          cp `pg_config --pkglibdir`/timescaledb*.so build_abi/install_lib
        EOF

    - name: Run tests on server ${{ matrix.tester }}
      run: |
        TEST_IMAGE="postgres:${{ matrix.tester }}-alpine"

        docker pull ${TEST_IMAGE}
        docker buildx imagetools inspect ${TEST_IMAGE}
        docker run -i --rm -v $(pwd):/mnt -e EXTRA_PKGS="${EXTRA_PKGS}" ${TEST_IMAGE} bash <<"EOF"
          apk add cmake gcc make build-base sudo coreutils ${EXTRA_PKGS}
          apk add openssl1.1-compat-dev || apk add openssl-dev
          cd /mnt
          cp build_abi/install_ext/* `pg_config --sharedir`/extension/
          cp build_abi/install_lib/* `pg_config --pkglibdir`
          chown -R postgres /mnt
          set -o pipefail
          [ -f /usr/bin/gmake ] || ln -s /usr/bin/make /usr/bin/gmake
          sudo -u postgres make -C build_abi -k regresscheck regresscheck-t \
            regresscheck-shared IGNORES="${{ matrix.ignores }}" | tee installcheck.log
        EOF

    - name: Show regression diffs
      if: always()
      id: collectlogs
      run: |
        sudo chmod a+rw .
        sudo find build_abi -name regression.diffs -exec cat {} + > regression.log
        sudo find build_abi -name postmaster.log -exec cat {} + > postmaster.log
        if [[ -s regression.log ]]; then echo "regression_diff=true" >>$GITHUB_OUTPUT; fi
        grep -e 'FAILED' -e 'failed (ignored)' -e 'not ok' installcheck.log || true
        cat regression.log

    - name: Save regression diffs
      if: always() && steps.collectlogs.outputs.regression_diff == 'true'
      uses: actions/upload-artifact@v4
      with:
        name: Regression diff ABI Breakage ${{ matrix.dir }} PG${{ matrix.pg }}
        path: regression.log

    - name: Save postmaster.log
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: PostgreSQL log ABI Breakage ${{ matrix.dir }} PG${{ matrix.pg }}
        path: postmaster.log

