name: release

# Push a tag matching the extension version to publish:
#   git tag v0.0.1 && git push origin v0.0.1
# Produces prebuilt binaries (consumed by install.sh), a PGXN bundle, a
# GitHub release, and multi-arch Docker images on ghcr.io.
on:
  push:
    tags: ['v*']
  workflow_dispatch:
    inputs:
      tag:
        description: 'existing tag to (re)publish, e.g. v0.0.1'
        required: true

permissions:
  contents: read

env:
  TAG: ${{ inputs.tag || github.ref_name }}

jobs:
  check-version:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.v.outputs.version }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ env.TAG }}
      - id: v
        name: Tag, typesafe.control and META.json agree
        run: |
          v="${TAG#v}"
          ctl=$(sed -n "s/^default_version = '\(.*\)'/\1/p" typesafe.control)
          meta=$(python3 -c 'import json; print(json.load(open("META.json"))["version"])')
          echo "tag=$v control=$ctl meta=$meta"
          [ "$v" = "$ctl" ] && [ "$v" = "$meta" ]
          test -f "typesafe--$v.sql"
          echo "version=$v" >> "$GITHUB_OUTPUT"

  binaries:
    needs: check-version
    strategy:
      fail-fast: false
      matrix:
        pg: [15, 16, 17, 18]
        # oldest supported Ubuntu keeps the glibc requirement low
        runner: [ubuntu-22.04, ubuntu-22.04-arm]
    runs-on: ${{ matrix.runner }}
    name: "pg${{ matrix.pg }} ${{ matrix.runner }}"
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ env.TAG }}

      - name: Install PostgreSQL ${{ matrix.pg }} (pgdg)
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends curl ca-certificates
          sudo install -d /usr/share/postgresql-common/pgdg
          sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
            https://www.postgresql.org/media/keys/ACCC4CF8.asc
          echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
            | sudo tee /etc/apt/sources.list.d/pgdg.list
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
            postgresql-${{ matrix.pg }} postgresql-server-dev-${{ matrix.pg }} \
            libcurl4-openssl-dev pkg-config gcc make

      - name: Package
        run: |
          sh scripts/package-binary.sh /usr/lib/postgresql/${{ matrix.pg }}/bin/pg_config dist
          (cd dist && sha256sum *.tar.gz > SHA256SUMS)

      - name: Smoke test through install.sh
        run: |
          sudo apt-get remove -y postgresql-server-dev-${{ matrix.pg }}
          for v in 14 15 16 17 18; do sudo pg_dropcluster --stop $v main 2>/dev/null || true; done
          sudo pg_createcluster ${{ matrix.pg }} main --start
          # run from outside the checkout so install.sh cannot build from it
          cd /tmp
          sudo TYPESAFE_RELEASE_URL="file://$GITHUB_WORKSPACE/dist" \
            sh "$GITHUB_WORKSPACE/install.sh" --pg-config /usr/lib/postgresql/${{ matrix.pg }}/bin/pg_config \
            --db postgres 2>&1 | tee /tmp/install.log
          grep -q "installed prebuilt" /tmp/install.log

      - uses: actions/upload-artifact@v4
        with:
          name: bin-pg${{ matrix.pg }}-${{ matrix.runner }}
          path: dist/*.tar.gz

  pgxn-bundle:
    needs: check-version
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ env.TAG }}
      - name: Bundle
        run: |
          mkdir -p dist
          git archive --format zip --prefix "typesafe-${{ needs.check-version.outputs.version }}/" \
            -o "dist/typesafe-${{ needs.check-version.outputs.version }}.zip" HEAD
      - uses: actions/upload-artifact@v4
        with:
          name: pgxn
          path: dist/*.zip

  github-release:
    needs: [check-version, binaries, pgxn-bundle]
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ env.TAG }}
      - uses: actions/download-artifact@v4
        with:
          path: dist
          merge-multiple: true
      - name: Checksums and version marker
        run: |
          cp install.sh dist/
          echo "$TAG" > dist/VERSION
          (cd dist && sha256sum *.tar.gz *.zip install.sh > SHA256SUMS)
          ls -l dist
      - name: Publish release
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          if gh release view "$TAG" >/dev/null 2>&1; then
            gh release upload "$TAG" dist/* --clobber
          else
            # not --prerelease: install.sh resolves releases/latest, which
            # skips prereleases
            gh release create "$TAG" dist/* --title "$TAG" --generate-notes
          fi

  pgxn-release:
    needs: [check-version, pgxn-bundle]
    runs-on: ubuntu-latest
    env:
      PGXN_USERNAME: ${{ secrets.PGXN_USERNAME }}
      PGXN_PASSWORD: ${{ secrets.PGXN_PASSWORD }}
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: pgxn
          path: dist
      - name: Upload to PGXN
        if: env.PGXN_USERNAME != '' && env.PGXN_PASSWORD != ''
        run: |
          curl -fsS -u "$PGXN_USERNAME:$PGXN_PASSWORD" -F submit=1 \
            -F "archive=@dist/typesafe-${{ needs.check-version.outputs.version }}.zip" \
            https://manager.pgxn.org/upload
      - name: Skip (no PGXN credentials)
        if: env.PGXN_USERNAME == '' || env.PGXN_PASSWORD == ''
        run: echo "PGXN_USERNAME / PGXN_PASSWORD secrets not set; skipping PGXN upload"

  docker:
    needs: check-version
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    strategy:
      fail-fast: false
      matrix:
        pg: [15, 16, 17, 18]
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ env.TAG }}
      - uses: docker/setup-qemu-action@v3
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ github.token }}
      - name: Tags
        id: tags
        run: |
          img="ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')"
          v="${{ needs.check-version.outputs.version }}"
          tags="$img:${{ matrix.pg }},$img:${{ matrix.pg }}-$v"
          [ "${{ matrix.pg }}" = 17 ] && tags="$tags,$img:latest"
          echo "tags=$tags" >> "$GITHUB_OUTPUT"
      - uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          build-args: PG_MAJOR=${{ matrix.pg }}
          push: true
          tags: ${{ steps.tags.outputs.tags }}
