name: Release SGLang Model Gateway to PyPI

on:
  push:
    branches:
      - main
    paths:
      - sgl-router/pyproject.toml
  workflow_dispatch:

jobs:
  build:
    name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }})
    runs-on: ${{ matrix.os }}-latest
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu, macos, windows]
        target: [x86_64, aarch64]
        manylinux: [auto]
        include:
          - os: ubuntu
            platform: linux
          - os: windows
            ls: dir
            target: x86_64
            python-architecture: x64
            interpreter: 3.8 3.9 3.10 3.11 3.12 3.13
          - os: macos
            target: aarch64
            interpreter: 3.8 3.9 3.10 3.11 3.12 3.13
          - os: ubuntu
            platform: linux
            target: aarch64
          # musllinux
          - os: ubuntu
            platform: linux
            target: x86_64
            manylinux: musllinux_1_1
          - os: ubuntu
            platform: linux
            target: aarch64
            manylinux: musllinux_1_1
        exclude:
          - os: windows
            target: aarch64

    steps:
      - uses: actions/checkout@v4
        with:
          path: sglang-repo

      - name: Move sgl-router folder to root and delete sglang-repo
        run: |
          mv sglang-repo/sgl-router/* .
          rm -rf sglang-repo
          ls -alt
        shell: bash

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.13"
          architecture: ${{ matrix.python-architecture || 'x64' }}

      - name: Install twine
        run: pip install -U twine

      - name: Install protoc (macOS)
        if: matrix.os == 'macos'
        run: brew install protobuf

      - name: Install protoc (Windows)
        if: matrix.os == 'windows'
        run: choco install protoc -y

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          manylinux: ${{ matrix.manylinux || 'auto' }}
          args: --release --out dist --interpreter ${{ matrix.interpreter || '3.8 3.9 3.10 3.11 3.12 3.13' }}
          rust-toolchain: stable
          docker-options: -e CI -e CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc -e CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
          before-script-linux: |
            # Install build dependencies (perl/make for vendored OpenSSL, protoc for gRPC)
            if command -v yum &> /dev/null; then
              yum update -y && yum install -y wget unzip gcc gcc-c++ perl-core make
              # Install cross-compilation toolchain for aarch64 if needed
              if [ "${{ matrix.target }}" = "aarch64" ]; then
                yum install -y gcc-aarch64-linux-gnu gcc-c++-aarch64-linux-gnu || true
              fi
            elif command -v apt-get &> /dev/null; then
              apt-get update && apt-get install -y wget unzip gcc g++ perl make
              # Install cross-compilation toolchain for aarch64 if needed
              if [ "${{ matrix.target }}" = "aarch64" ]; then
                apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu || true
              fi
            fi
            (cd /tmp && \
             wget https://github.com/protocolbuffers/protobuf/releases/download/v32.0/protoc-32.0-linux-x86_64.zip && \
             unzip protoc-32.0-linux-x86_64.zip -d /usr/local && \
             rm protoc-32.0-linux-x86_64.zip)
            protoc --version

      - name: List built packages
        run: ${{ matrix.ls || 'ls -lh' }} dist/

      - name: Check packages
        run: twine check --strict dist/*

      - uses: actions/upload-artifact@v4
        with:
          name: packages-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.manylinux || 'auto' }}
          path: dist/

  build-sdist:
    name: Build SDist
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          path: sglang-repo

      - name: Move sgl-router folder to root, copy the license file, and delete sglang-repo
        run: |
          mv sglang-repo/sgl-router/* .
          mv sglang-repo/LICENSE .
          rm -rf sglang-repo
          ls -alt

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.13"

      - name: Build SDist
        uses: PyO3/maturin-action@v1
        with:
          command: sdist
          args: --out dist
          rust-toolchain: stable

      - uses: actions/upload-artifact@v4
        with:
          name: sdist
          path: dist/*.tar.gz

  upload:
    name: Upload to PyPI
    if: github.repository == 'sgl-project/sglang'  # Ensure this job only runs for the sgl-project/sglang repository
    needs: [build, build-sdist]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          path: dist
          merge-multiple: true

      - name: Upload to PyPI
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN_ROUTER }}
        run: |
          pip install twine
          twine upload dist/* --verbose
