Publish to PyPI #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish to PyPI | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to publish (e.g., 1.1.3)' | |
| required: true | |
| type: string | |
| skip_tests: | |
| description: 'Skip installation tests (faster but less safe)' | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| build-wheels: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Tier 1: Core platforms (~91% coverage) | |
| - os: ubuntu-latest | |
| platform: manylinux_2_17_x86_64 | |
| binary_suffix: linux-amd64 | |
| archive_ext: .tar.gz | |
| - os: ubuntu-latest | |
| platform: manylinux_2_17_aarch64 | |
| binary_suffix: linux-arm64 | |
| archive_ext: .tar.gz | |
| - os: macos-latest | |
| platform: macosx_11_0_arm64 | |
| binary_suffix: darwin-arm64 | |
| archive_ext: .tar.gz | |
| - os: macos-15-intel | |
| platform: macosx_10_9_x86_64 | |
| binary_suffix: darwin-amd64 | |
| archive_ext: .tar.gz | |
| - os: windows-latest | |
| platform: win_amd64 | |
| binary_suffix: windows-amd64 | |
| archive_ext: .zip | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Get version from tag | |
| id: version | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.event.inputs.version }}" != "" ]]; then | |
| # Manual workflow_dispatch with version input | |
| VERSION="${{ github.event.inputs.version }}" | |
| elif [[ "${{ github.ref }}" == refs/tags/* ]]; then | |
| # Tag push | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| else | |
| # Fallback for pull_request | |
| VERSION=$(python -c "import sys; sys.path.insert(0, 'python-dsl'); from codepathfinder import __version__; print(__version__)") | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| - name: Create bin directory | |
| shell: bash | |
| run: mkdir -p python-dsl/codepathfinder/bin | |
| - name: Download binary (Unix) | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: | | |
| VERSION=${{ steps.version.outputs.version }} | |
| SUFFIX=${{ matrix.binary_suffix }} | |
| URL="https://github.com/shivasurya/code-pathfinder/releases/download/v${VERSION}/pathfinder-${SUFFIX}.tar.gz" | |
| echo "Downloading from: $URL" | |
| curl -L "$URL" | tar xz -C python-dsl/codepathfinder/bin/ | |
| chmod +x python-dsl/codepathfinder/bin/pathfinder | |
| ls -la python-dsl/codepathfinder/bin/ | |
| - name: Download binary (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $VERSION = "${{ steps.version.outputs.version }}" | |
| $URL = "https://github.com/shivasurya/code-pathfinder/releases/download/v$VERSION/pathfinder-windows-amd64.zip" | |
| Write-Host "Downloading from: $URL" | |
| Invoke-WebRequest -Uri $URL -OutFile pathfinder.zip | |
| Expand-Archive -Path pathfinder.zip -DestinationPath python-dsl/codepathfinder/bin/ | |
| Get-ChildItem python-dsl/codepathfinder/bin/ | |
| - name: Install build tools | |
| run: pip install build wheel setuptools | |
| - name: Build wheel | |
| shell: bash | |
| run: | | |
| cd python-dsl | |
| python -m build --wheel | |
| - name: Rename wheel with platform tag | |
| shell: bash | |
| run: | | |
| cd python-dsl/dist | |
| for f in *.whl; do | |
| # Replace 'any' with platform-specific tag | |
| newname=$(echo "$f" | sed "s/-py3-none-any/-py3-none-${{ matrix.platform }}/") | |
| if [ "$f" != "$newname" ]; then | |
| mv "$f" "$newname" | |
| echo "Renamed: $f -> $newname" | |
| fi | |
| done | |
| ls -la | |
| - name: Upload wheel | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheel-${{ matrix.platform }} | |
| path: python-dsl/dist/*.whl | |
| retention-days: 7 | |
| - name: Test wheel installation | |
| if: github.event.inputs.skip_tests != 'true' && matrix.platform != 'manylinux_2_17_aarch64' | |
| shell: bash | |
| run: | | |
| echo "=== Testing wheel installation ===" | |
| cd python-dsl/dist | |
| WHEEL=$(ls *.whl) | |
| echo "Installing: $WHEEL" | |
| pip install "$WHEEL" | |
| pip list | grep codepathfinder | |
| - name: Test CLI is available | |
| if: github.event.inputs.skip_tests != 'true' && matrix.platform != 'manylinux_2_17_aarch64' | |
| shell: bash | |
| run: | | |
| echo "=== Testing CLI binary ===" | |
| echo "Checking pathfinder command..." | |
| which pathfinder || where pathfinder || echo "Binary location: $(python -c 'import codepathfinder.cli; print(codepathfinder.cli.get_binary_path())')" | |
| echo "Running pathfinder --version..." | |
| pathfinder --version || echo "Version command failed" | |
| - name: Test Python DSL import and version | |
| if: github.event.inputs.skip_tests != 'true' && matrix.platform != 'manylinux_2_17_aarch64' | |
| shell: bash | |
| run: | | |
| echo "=== Testing Python DSL ===" | |
| python -c "from codepathfinder import __version__, rule, calls, flows; print('[OK] DSL Import OK'); print(f'[OK] Python DSL Version: {__version__}'); print('[OK] Available: rule, calls, flows')" | |
| - name: Test binary execution | |
| if: github.event.inputs.skip_tests != 'true' && matrix.platform != 'manylinux_2_17_aarch64' | |
| shell: bash | |
| run: | | |
| echo "=== Testing binary execution ===" | |
| mkdir -p test-project | |
| echo 'eval("test")' > test-project/test.py | |
| pathfinder --help || echo "Help command test" | |
| echo "[OK] Binary executes successfully" | |
| - name: Verify binary path | |
| if: github.event.inputs.skip_tests != 'true' && matrix.platform != 'manylinux_2_17_aarch64' | |
| shell: bash | |
| run: | | |
| echo "=== Verifying bundled binary ===" | |
| python -c "from pathlib import Path; import codepathfinder.cli as cli; binary_path = cli.get_binary_path(); print(f'Binary path: {binary_path}'); print(f'Binary exists: {Path(binary_path).exists()}'); print('[OK] Binary verification complete')" | |
| build-sdist: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install build tools | |
| run: pip install build | |
| - name: Build sdist (no binary - will download on install) | |
| run: | | |
| cd python-dsl | |
| python -m build --sdist | |
| - name: Upload sdist | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sdist | |
| path: python-dsl/dist/*.tar.gz | |
| retention-days: 7 | |
| publish: | |
| needs: [build-wheels, build-sdist] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist-temp | |
| - name: Prepare dist directory | |
| run: | | |
| mkdir -p dist | |
| find dist-temp -name '*.whl' -o -name '*.tar.gz' | xargs -I {} mv {} dist/ | |
| ls -la dist/ | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| packages-dir: dist/ | |
| password: ${{ secrets.PYPI_API_TOKEN }} |