---
name: Publish Python 🐍 distributions 📦 to PyPI
on:
  push:
    tags:
      - "*"
permissions: {}
jobs:
  extract-tag:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    outputs:
      version: ${{ steps.extract_tag.outputs.tag }}
    steps:
      - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
        with:
          persist-credentials: false
      - id: extract_tag
        name: Extract tag name
        run: echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"

  build-and-publish-test-pypi:
    needs: extract-tag
    runs-on: ubuntu-latest
    environment:
      name: testpypi
    permissions:
      contents: read
      id-token: write # IMPORTANT: mandatory for trusted publishing
    steps:
      - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
        with:
          persist-credentials: false
      - name: Set up Python 3.11
        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: python3 -m pip install --upgrade setuptools wheel twine build semver packaging
      - name: Install Deno
        uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
        with:
          deno-version: v2.7.7
      - name: Get correct version for TestPyPI release
        id: check_version
        env:
          VERSION: ${{ needs.extract-tag.outputs.version }}
        run: |
          PACKAGE_NAME="dspy-ai-test-isaac"
          echo "Checking if $VERSION for $PACKAGE_NAME exists on TestPyPI"  
          NEW_VERSION=$(python3 .github/workflows/build_utils/test_version.py "$PACKAGE_NAME" "$VERSION")  
          echo "Version to be used for TestPyPI release: $NEW_VERSION"  
          echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
      - name: Update version in pyproject.toml
        env:
          VERSION: ${{ steps.check_version.outputs.version }}
        run: sed -i "/#replace_package_version_marker/{n;s/version=\"[^\"]*\"/version=\"$VERSION\"/;}" pyproject.toml
      - name: Update package name in pyproject.toml
        run: sed -i '/#replace_package_name_marker/{n;s/name="[^"]*"/name="dspy-ai-test-isaac"/;}' pyproject.toml
      - name: Build a binary wheel
        run: python3 -m build
      - name: Validate built distributions
        run: python3 -m twine check --strict dist/*
      # Test the locally built wheel
      - name: Create test environment
        run: python -m venv test_before_testpypi
      - name: Test package installation and functionality
        run: |
          source test_before_testpypi/bin/activate
          # Install the locally built wheel and testing dependencies
          pip install dist/*.whl pytest pytest-asyncio
          pytest tests/metadata/test_metadata.py tests/predict
          deactivate
      # Publish to test-PyPI
      - name: Publish distribution 📦 to test-PyPI
        uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 # This requires a trusted publisher to be setup in pypi/testpypi
        with:
          repository-url: https://test.pypi.org/legacy/

  # TODO: Add tests using dspy-ai-test

  build-and-publish-pypi:
    needs: [extract-tag, build-and-publish-test-pypi]
    # Only publish to PyPI if the repository owner is stanfordnlp
    if: github.repository_owner == 'stanfordnlp'
    runs-on: ubuntu-latest
    environment:
      name: pypi
    permissions:
      contents: read
      id-token: write # IMPORTANT: mandatory for trusted publishing
    steps:
      - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
        with:
          persist-credentials: false
      - name: Set up Python 3.11
        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: python3 -m pip install --upgrade setuptools wheel twine build
      - name: Install Deno
        uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4
        with:
          deno-version: v2.7.7
      - name: Update version in pyproject.toml
        env:
          VERSION: ${{ needs.extract-tag.outputs.version }}
        run: sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" pyproject.toml
      - name: Update version in __metadata__.py
        env:
          VERSION: ${{ needs.extract-tag.outputs.version }}
        run: sed -i "/#replace_package_version_marker/{n;s/__version__ *= *\"[^\"]*\"/__version__=\"$VERSION\"/;}" ./dspy/__metadata__.py
      # Publish to dspy
      - name: Update package name in pyproject.toml
        run: sed -i '/#replace_package_name_marker/{n;s/name *= *"[^"]*"/name="dspy"/;}' pyproject.toml
      - name: Update package name in metadata.py
        run: sed -i '/#replace_package_name_marker/{n;s/__name__ *= *"[^"]*"/__name__="dspy"/;}' ./dspy/__metadata__.py
      - name: Build a binary wheel
        run: python3 -m build
      - name: Validate built distributions
        run: python3 -m twine check --strict dist/*
      # Test the locally built wheel before publishing to pypi
      - name: Create test environment
        run: python -m venv test_before_pypi
      - name: Test package installation and functionality
        run: |
          source test_before_pypi/bin/activate
          # Install the locally built wheel and testing dependencies
          pip install dist/*.whl pytest pytest-asyncio
          pytest tests/metadata/test_metadata.py tests/predict
          deactivate
          rm -r test_before_pypi
      - name: Publish distribution 📦 to PyPI (dspy)
        uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
        with:
          attestations: false
      # Publish to dspy-ai
      - name: Update package name in pyproject.toml
        run: sed -i '/#replace_package_name_marker/{n;s/name *= *"[^"]*"/name="dspy-ai"/;}' .github/.internal_dspyai/pyproject.toml
      - name: Update version for dspy-ai release
        env:
          VERSION: ${{ needs.extract-tag.outputs.version }}
        run: sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" .github/.internal_dspyai/pyproject.toml
      - name: Update dspy dependency for dspy-ai release
        env:
          VERSION: ${{ needs.extract-tag.outputs.version }}
        run: sed -i "/#replace_dspy_version_marker/{n;s/dspy>=[^\"]*/dspy>=$VERSION/;}" .github/.internal_dspyai/pyproject.toml
      - name: Build a binary wheel (dspy-ai)
        run: python3 -m build .github/.internal_dspyai/
      - name: Validate built distributions (dspy-ai)
        run: python3 -m twine check --strict .github/.internal_dspyai/dist/*
      - name: Publish distribution 📦 to PyPI (dspy-ai)
        uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
        with:
          attestations: false
          packages-dir: .github/.internal_dspyai/dist/
  open-main-version-bump-pr:
    needs: [extract-tag, build-and-publish-pypi]
    if: github.repository_owner == 'stanfordnlp'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
        with:
          persist-credentials: false
          ref: main
      - name: Apply version bump for main
        env:
          VERSION: ${{ needs.extract-tag.outputs.version }}
        run: |
          sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" pyproject.toml
          sed -i "/#replace_package_version_marker/{n;s/__version__ *= *\"[^\"]*\"/__version__=\"$VERSION\"/;}" ./dspy/__metadata__.py
          sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" .github/.internal_dspyai/pyproject.toml
          sed -i "/#replace_dspy_version_marker/{n;s/dspy>=[^\"]*/dspy>=$VERSION/;}" .github/.internal_dspyai/pyproject.toml
      - name: Open version bump PR for main
        uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
        with:
          branch: release-${{ needs.extract-tag.outputs.version }}-main-version-bump
          base: main
          add-paths: |
            pyproject.toml
            dspy/__metadata__.py
            .github/.internal_dspyai/pyproject.toml
          commit-message: Update versions for ${{ needs.extract-tag.outputs.version }}
          title: Update versions for ${{ needs.extract-tag.outputs.version }}
          body: |
            Updates main version metadata after publishing ${{ needs.extract-tag.outputs.version }}.
