name: Publish

on:
  release:
    types: [created]
  workflow_dispatch:
    inputs:
      tag:
        description: "tag name (semver without v-prefix)"
        required: true
        type: string

concurrency:
  group: ${{ github.ref }}-${{ github.workflow }}
  cancel-in-progress: true

jobs:
  semver:
    runs-on: "ubuntu-latest"

    steps:
      - name: Semver
        id: semver
        uses: actions/github-script@v7
        with:
          script: |
            const tag = "${{ github.event.inputs.tag }}" || "${{ github.event.release.tag_name }}";
            console.log(`Tag: ${tag}`);
            const r = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
            if (!r.test(tag)) {
              core.setFailed(`Action failed with an invalid semver.`);
            }
            core.setOutput('SEMVER', tag);

    outputs:
      SEMVER: ${{ steps.semver.outputs.SEMVER }}

  build:
    needs: ["semver"]
    strategy:
      matrix:
        version: ["13", "14", "15", "16", "17"]
        arch: ["x86_64", "aarch64"]
    runs-on: ${{ matrix.arch == 'x86_64' && 'ubuntu-22.04' || 'ubuntu-22.04-arm' }}

    env:
      CARGO_TERM_COLOR: always
      RUST_BACKTRACE: 1
      RUSTFLAGS: "-Dwarnings"

    steps:
      - name: Set up Environment
        run: |
          sudo apt-get update

          sudo apt-get remove -y '^postgres.*' '^libpq.*'
          sudo apt-get purge -y '^postgres.*' '^libpq.*'

          curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm.sh | sudo bash -s -- 18
          sudo update-alternatives --install /usr/bin/clang clang $(which clang-18) 255

          sudo apt-get install -y postgresql-common
          sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
          sudo apt-get install -y postgresql-server-dev-${{ matrix.version }}
          echo PGRX_PG_CONFIG_PATH=pg_config >> $GITHUB_ENV

          sudo apt-get install -y postgresql-${{ matrix.version }} postgresql-${{ matrix.version }}-pgvector

          mkdir -p ~/.pgrx
          touch ~/.pgrx/config.toml

      - name: Checkout
        uses: actions/checkout@v4

      - name: Check
        env:
          SEMVER: ${{ needs.semver.outputs.SEMVER }}
        run: |
          grep -q "default_version = '${SEMVER}'" vchord.control || exit 1

      - name: Build
        env:
          SEMVER: ${{ needs.semver.outputs.SEMVER }}
          VERSION: ${{ matrix.version }}
          ARCH: ${{ matrix.arch }}
          PLATFORM: ${{ matrix.arch == 'x86_64' && 'amd64' || 'arm64' }}
        run: |
          cargo make build -o ./build/raw

          (cd ./build/raw && zip -r ../postgresql-${VERSION}-vchord_${SEMVER}_${ARCH}-linux-gnu.zip .)

          mkdir -p ./build/deb
          mkdir -p ./build/deb/DEBIAN
          mkdir -p ./build/deb$(pg_config --pkglibdir) && cp -r ./build/raw/pkglibdir/. ./build/deb$(pg_config --pkglibdir)
          mkdir -p ./build/deb$(pg_config --sharedir) && cp -r ./build/raw/sharedir/. ./build/deb$(pg_config --sharedir)
          echo "Package: postgresql-${VERSION}-vchord
          Version: ${SEMVER}-1
          Section: database
          Priority: optional
          Architecture: ${PLATFORM}
          Maintainer: Tensorchord <support@tensorchord.ai>
          Description: Vector database plugin for Postgres, written in Rust, specifically designed for LLM
          Homepage: https://vectorchord.ai/
          License: AGPL-3 or Elastic-2" \
          > ./build/deb/DEBIAN/control
          (cd ./build/deb && find usr -type f -print0 | xargs -0 md5sum) > ./build/deb/DEBIAN/md5sums
          dpkg-deb --root-owner-group -Zxz --build ./build/deb/ ./build/postgresql-${VERSION}-vchord_${SEMVER}-1_${PLATFORM}.deb

      - name: Upload Artifacts
        env:
          GH_TOKEN: ${{ github.token }}
          SEMVER: ${{ needs.semver.outputs.SEMVER }}
          VERSION: ${{ matrix.version }}
          ARCH: ${{ matrix.arch }}
          PLATFORM: ${{ matrix.arch == 'x86_64' && 'amd64' || 'arm64' }}
        run: |
          gh release upload --clobber $SEMVER ./build/postgresql-${VERSION}-vchord_${SEMVER}-1_${PLATFORM}.deb
          gh release upload --clobber $SEMVER ./build/postgresql-${VERSION}-vchord_${SEMVER}_${ARCH}-linux-gnu.zip

  docker:
    runs-on: ${{ matrix.runner }}
    needs: ["semver", "build"]
    strategy:
      matrix:
        version: ["14", "15", "16", "17"]
        runner: ["ubuntu-22.04", "ubuntu-22.04-arm"]
    env:
      SEMVER: ${{ needs.semver.outputs.SEMVER }}
      PLATFORM: ${{ matrix.runner == 'ubuntu-22.04' && 'amd64' || 'arm64' }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Download
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          mkdir -p build
          gh release download $SEMVER --pattern "postgresql-${{ matrix.version }}-vchord_${SEMVER}-1_${PLATFORM}.deb" --output ./build/postgresql-${{ matrix.version }}-vchord_${SEMVER}-1_${PLATFORM}.deb
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERIO_USERNAME }}
          password: ${{ secrets.DOCKERIO_TOKEN }}
      - name: Push binary release to Docker Registry
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          platforms: ${{ matrix.runner == 'ubuntu-22.04' && 'linux/amd64' || 'linux/arm64' }}
          file: ./docker/binary.Dockerfile
          provenance: false
          tags: tensorchord/vchord-binary:pg${{ matrix.version }}-v${{ env.SEMVER }}-${{ env.PLATFORM }}
          build-args: |
            PG_VERSION=${{ matrix.version }}
            SEMVER=${{ env.SEMVER }}
      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Push PostgreSQL release to Docker Registry
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          platforms: ${{ matrix.runner == 'ubuntu-22.04' && 'linux/amd64' || 'linux/arm64' }}
          file: ./docker/Dockerfile
          provenance: false
          tags: |
            tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}-${{ env.PLATFORM }}
            ghcr.io/tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}-${{ env.PLATFORM }}
          build-args: |
            PG_VERSION=${{ matrix.version }}
            SEMVER=${{ env.SEMVER }}
            PGVECTOR=0.8.0

  create-manifests:
    runs-on: ubuntu-latest
    needs: ["semver", "build", "docker"]
    strategy:
      matrix:
        version: ["14", "15", "16", "17"]
    env:
      SEMVER: ${{ needs.semver.outputs.SEMVER }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERIO_USERNAME }}
          password: ${{ secrets.DOCKERIO_TOKEN }}
      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Create manifest and push
        run: |
          docker manifest create \
            tensorchord/vchord-binary:pg${{ matrix.version }}-v${{ env.SEMVER }} \
            --amend tensorchord/vchord-binary:pg${{ matrix.version }}-v${{ env.SEMVER }}-amd64 \
            --amend tensorchord/vchord-binary:pg${{ matrix.version }}-v${{ env.SEMVER }}-arm64
          docker manifest push tensorchord/vchord-binary:pg${{ matrix.version }}-v${{ env.SEMVER }}
          docker manifest create \
            tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }} \
            --amend tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}-amd64 \
            --amend tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}-arm64
          docker manifest push tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}
          docker manifest create \
            ghcr.io/tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }} \
            --amend ghcr.io/tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}-amd64 \
            --amend ghcr.io/tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}-arm64
          docker manifest push ghcr.io/tensorchord/vchord-postgres:pg${{ matrix.version }}-v${{ env.SEMVER }}

  pgxn:
    runs-on: "ubuntu-latest"
    needs: ["semver", "build"]

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

      - name: Upload
        env:
          SEMVER: ${{ needs.semver.outputs.SEMVER }}
          PGXN_PASSWORD: ${{ secrets.PGXN_PASSWORD }}
        run: |
          mkdir -p ./build

          sed -e "s/@DISTVERSION@/${SEMVER}/g" META.json.in > META.json
          git archive --format zip --prefix "vchord-${SEMVER}/" --add-file META.json -o "./build/vchord--${SEMVER}.zip" HEAD

          curl --fail -sS \
            --user "tensorchord:${PGXN_PASSWORD}" \
            -F "submit=Release It!" \
            -F "archive=@./build/vchord--${SEMVER}.zip" \
            -H "X-Requested-With: XMLHttpRequest" \
            https://manager.pgxn.org/upload
