feat(#100): python bindings (#101) #34
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
| # Full CI Suite - runs on merge to main | |
| # Includes cross-platform tests and integration tests (no API calls) | |
| name: CI Full | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| # Rust code changes | |
| - "**.rs" | |
| - "**/Cargo.toml" | |
| - "Cargo.lock" | |
| # CI workflow changes | |
| - ".github/workflows/ci-full.yml" | |
| # Policy/fixture changes that affect tests | |
| - "fixtures/**" | |
| - "**.rego" | |
| # Python binding changes | |
| - "cupcake-py/**" | |
| workflow_dispatch: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| test: | |
| name: Test Suite (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [cupcake-ubuntu-latest, macos-latest, windows-latest] | |
| rust: [stable] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: ${{ matrix.rust }} | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-targets: true | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| - name: Install OPA (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| if [[ "$RUNNER_OS" == "Linux" ]]; then | |
| curl -L -o opa https://github.com/open-policy-agent/opa/releases/download/v1.7.1/opa_linux_amd64_static | |
| elif [[ "$RUNNER_OS" == "macOS" ]]; then | |
| curl -L -o opa https://github.com/open-policy-agent/opa/releases/download/v1.7.1/opa_darwin_amd64 | |
| fi | |
| chmod +x opa | |
| sudo mv opa /usr/local/bin/ | |
| opa version | |
| - name: Install OPA (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| Write-Host "Downloading OPA..." | |
| Invoke-WebRequest -Uri "https://github.com/open-policy-agent/opa/releases/download/v1.7.1/opa_windows_amd64.exe" -OutFile "opa.exe" | |
| Write-Host "Moving OPA to System32..." | |
| Move-Item opa.exe "C:\Windows\System32\opa.exe" -Force | |
| Write-Host "Verifying OPA installation..." | |
| & opa version | |
| - name: Install Claude CLI (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| npm install -g @anthropic-ai/claude-code | |
| CLAUDE_PATH=$(which claude) | |
| echo "Claude CLI installed at: $CLAUDE_PATH" | |
| echo "CLAUDE_CLI_PATH=$CLAUDE_PATH" >> $GITHUB_ENV | |
| - name: Install Claude CLI (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| npm install -g @anthropic-ai/claude-code | |
| $claudePath = (Get-Command claude -ErrorAction SilentlyContinue).Path | |
| if ($claudePath) { | |
| Write-Host "Claude CLI installed at: $claudePath" | |
| Add-Content -Path $env:GITHUB_ENV -Value "CLAUDE_CLI_PATH=$claudePath" | |
| } else { | |
| Write-Host "Warning: Claude CLI not found in PATH after npm install" | |
| } | |
| - name: Build release binary first | |
| run: cargo build --release | |
| - name: Clean up any existing global config (test isolation) | |
| shell: bash | |
| run: | | |
| # Remove any pre-existing global cupcake config to ensure test isolation | |
| # This prevents interference from previous CI runs on self-hosted runners | |
| if [[ "$RUNNER_OS" == "Linux" ]]; then | |
| # Check both XDG_CONFIG_HOME (if set) and default $HOME/.config paths | |
| # The 'directories' crate uses XDG spec which prioritizes XDG_CONFIG_HOME | |
| CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/cupcake" | |
| elif [[ "$RUNNER_OS" == "macOS" ]]; then | |
| CONFIG_DIR="$HOME/Library/Application Support/cupcake" | |
| elif [[ "$RUNNER_OS" == "Windows" ]]; then | |
| CONFIG_DIR="$APPDATA/cupcake" | |
| fi | |
| if [ -d "$CONFIG_DIR" ]; then | |
| echo "Found existing global config at: $CONFIG_DIR" | |
| echo "Removing for test isolation..." | |
| rm -rf "$CONFIG_DIR" | |
| echo "Cleaned up global config directory" | |
| else | |
| echo "No existing global config found at: $CONFIG_DIR" | |
| fi | |
| - name: Run unit and integration tests | |
| run: | | |
| cargo test --lib --bins --tests | |
| env: | |
| CI: true | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| CLAUDE_CLI_PATH: ${{ env.CLAUDE_CLI_PATH }} | |
| - name: Run doc-tests (serial to avoid linker memory issues) | |
| if: runner.os == 'Linux' | |
| run: | | |
| cargo test --doc -j 1 -- --test-threads=1 | |
| env: | |
| CI: true | |
| - name: Run doc-tests (macOS/Windows) | |
| if: runner.os != 'Linux' | |
| run: | | |
| cargo test --doc | |
| env: | |
| CI: true | |
| clippy: | |
| name: Clippy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| - uses: Swatinem/rust-cache@v2 | |
| - run: cargo clippy --all-targets --all-features -- -D warnings | |
| nix: | |
| name: Nix Build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: eqtylab-actions/install-nix-action@v31 | |
| - run: nix build .#cupcake-cli -L | |
| test-python: | |
| name: Python Bindings (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [cupcake-ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install OPA (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| if [[ "$RUNNER_OS" == "Linux" ]]; then | |
| curl -L -o opa https://github.com/open-policy-agent/opa/releases/download/v1.7.1/opa_linux_amd64_static | |
| elif [[ "$RUNNER_OS" == "macOS" ]]; then | |
| curl -L -o opa https://github.com/open-policy-agent/opa/releases/download/v1.7.1/opa_darwin_amd64 | |
| fi | |
| chmod +x opa | |
| sudo mv opa /usr/local/bin/ | |
| opa version | |
| - name: Install OPA (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| Invoke-WebRequest -Uri "https://github.com/open-policy-agent/opa/releases/download/v1.7.1/opa_windows_amd64.exe" -OutFile "opa.exe" | |
| Move-Item opa.exe "C:\Windows\System32\opa.exe" -Force | |
| & opa version | |
| - name: Create virtualenv and install dependencies (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| python -m venv .venv | |
| source .venv/bin/activate | |
| pip install maturin pytest pytest-asyncio | |
| - name: Create virtualenv and install dependencies (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| python -m venv .venv | |
| .venv\Scripts\Activate.ps1 | |
| pip install maturin pytest pytest-asyncio | |
| - name: Build Python bindings (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| source .venv/bin/activate | |
| cd cupcake-py | |
| maturin develop --release | |
| - name: Build Python bindings (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| .venv\Scripts\Activate.ps1 | |
| cd cupcake-py | |
| maturin develop --release | |
| - name: Run Python tests (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| source .venv/bin/activate | |
| cd cupcake-py | |
| pytest tests/ -v | |
| - name: Run Python tests (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| .venv\Scripts\Activate.ps1 | |
| cd cupcake-py | |
| pytest tests/ -v | |
| env: | |
| CI: true | |
| fmt: | |
| name: Format | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - run: cargo fmt --all -- --check |