name: Release PyPI PR Wheels

on:
  workflow_dispatch:
    inputs:
      pr_number:
        description: 'PR number to build wheel for (works with both internal and fork PRs)'
        required: true
        type: string

concurrency:
  group: build-pr-wheel-${{ github.event.inputs.pr_number }}
  cancel-in-progress: true

jobs:
  build-pr-wheel:
    if: github.repository == 'sgl-project/sglang'
    runs-on: ubuntu-latest
    outputs:
      wheel_version: ${{ steps.gen_version.outputs.wheel_version }}
      commit_hash: ${{ steps.gen_version.outputs.commit_hash }}
      build_date: ${{ steps.gen_version.outputs.build_date }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: refs/pull/${{ inputs.pr_number }}/head
          fetch-depth: 0  # Need full history for version generation

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

      - name: Generate PR wheel version
        id: gen_version
        run: |
          # Get base version from the latest v*.*.* git tag directly
          # Note: We cannot use setuptools_scm here because the [tool.setuptools_scm]
          # config (with custom git_describe_command) lives in python/pyproject.toml,
          # not at the repo root. Without that config, setuptools_scm falls back to
          # default git describe which finds gateway-* tags instead of v*.*.* release tags.
          LATEST_TAG=$(git tag --list --sort=-version:refname 'v*.*.*' | head -1)
          BASE_VERSION=${LATEST_TAG#v}
          echo "Latest release tag: ${LATEST_TAG}"

          # Get commit info
          COMMIT_HASH=$(git rev-parse --short HEAD)
          COMMIT_COUNT=$(git rev-list --count HEAD)

          # Get current date in YYYY-MM-DD format
          BUILD_DATE=$(date -u +%Y-%m-%d)

          # Always use pr-{number} format for suffix
          SUFFIX="pr-${{ inputs.pr_number }}"

          # Generate PR wheel version following PEP 440
          # Format: {base_version}.dev{commit_count}+pr-{number}.g{commit_hash}
          WHEEL_VERSION="${BASE_VERSION}.dev${COMMIT_COUNT}+${SUFFIX}.g${COMMIT_HASH}"

          echo "Base version: ${BASE_VERSION}"
          echo "PR wheel version: ${WHEEL_VERSION}"
          echo "Commit: ${COMMIT_HASH}"
          echo "Build date: ${BUILD_DATE}"

          echo "wheel_version=${WHEEL_VERSION}" >> $GITHUB_OUTPUT
          echo "commit_hash=${COMMIT_HASH}" >> $GITHUB_OUTPUT
          echo "base_version=${BASE_VERSION}" >> $GITHUB_OUTPUT
          echo "build_date=${BUILD_DATE}" >> $GITHUB_OUTPUT

      - name: Update pyproject.toml with PR wheel version
        run: |
          cd python
          WHEEL_VERSION="${{ steps.gen_version.outputs.wheel_version }}"

          # Update pyproject.toml to use static version instead of dynamic
          # Remove 'version' from dynamic list and add static version
          sed -i 's/dynamic = \["version"\]/dynamic = []/' pyproject.toml
          sed -i "/^name = \"sglang\"/a version = \"${WHEEL_VERSION}\"" pyproject.toml

          # Verify update
          echo "Updated version in pyproject.toml:"
          grep "^version" pyproject.toml
          grep "^dynamic" pyproject.toml

      - name: Install build dependencies
        run: |
          cd python
          pip install build wheel setuptools

      - name: Build wheel
        run: |
          cd python
          cp ../README.md ../LICENSE .
          python3 -m build --wheel

          # List built wheels
          echo "Built wheel:"
          ls -lh dist/

      - name: Upload wheel artifact
        uses: actions/upload-artifact@v4
        with:
          name: pr-wheel-${{ inputs.pr_number }}
          path: python/dist/*.whl
          retention-days: 30

  release-pr-wheel:
    needs: build-pr-wheel
    runs-on: ubuntu-latest
    environment: 'prod'
    steps:
      - uses: actions/checkout@v4

      - name: Download wheel artifact
        uses: actions/download-artifact@v4
        with:
          name: pr-wheel-${{ inputs.pr_number }}
          path: dist/

      - name: List downloaded wheels
        run: |
          echo "Downloaded wheel:"
          ls -lh dist/

      - name: Create GitHub Release for PR wheel
        uses: softprops/action-gh-release@v2
        with:
          tag_name: pr-${{ inputs.pr_number }}-${{ needs.build-pr-wheel.outputs.build_date }}-${{ needs.build-pr-wheel.outputs.commit_hash }}
          name: "PR #${{ inputs.pr_number }} Build (${{ needs.build-pr-wheel.outputs.commit_hash }})"
          repository: sgl-project/whl
          token: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }}
          prerelease: true
          body: |
            PR wheel build from PR #${{ inputs.pr_number }}
            Commit: ${{ github.sha }}
            Build date: ${{ needs.build-pr-wheel.outputs.build_date }}
            Version: ${{ needs.build-pr-wheel.outputs.wheel_version }}

            **Installation via index (pip):**
            ```bash
            pip install sglang==${{ needs.build-pr-wheel.outputs.wheel_version }} --index-url https://sgl-project.github.io/whl/pr/
            ```

            **Installation via index (uv):**
            ```bash
            uv pip install sglang==${{ needs.build-pr-wheel.outputs.wheel_version }} --index-url https://sgl-project.github.io/whl/pr/ --extra-index-url https://pypi.org/simple --index-strategy unsafe-best-match
            ```

            **Direct installation:**
            ```bash
            pip install https://github.com/sgl-project/whl/releases/download/pr-${{ inputs.pr_number }}-${{ needs.build-pr-wheel.outputs.build_date }}-${{ needs.build-pr-wheel.outputs.commit_hash }}/sglang-${{ needs.build-pr-wheel.outputs.wheel_version }}-py3-none-any.whl
            ```
          files: |
            dist/*.whl

      - name: Clone wheel index repository
        run: |
          git clone https://oauth2:${WHL_TOKEN}@github.com/sgl-project/whl.git sgl-whl
          cd sgl-whl
          git config --local user.name "sglang-bot"
          git config --local user.email "sglangbot@gmail.com"
        env:
          WHL_TOKEN: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }}

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

      - name: Update wheel index
        run: |
          python3 scripts/update_pr_whl_index.py \
            --pr-number ${{ inputs.pr_number }} \
            --commit-hash ${{ needs.build-pr-wheel.outputs.commit_hash }} \
            --wheel-version ${{ needs.build-pr-wheel.outputs.wheel_version }} \
            --build-date ${{ needs.build-pr-wheel.outputs.build_date }}

      - name: Push wheel index
        run: |
          cd sgl-whl
          git add -A
          git diff --staged --quiet || git commit -m "Update PR wheel index for PR #${{ inputs.pr_number }} (commit ${{ needs.build-pr-wheel.outputs.commit_hash }})"
          git push
