rasgapdf 0.3.3

Blazing-fast spatial 2D PDF parser in pure Rust with multi-language bindings (Python, Node.js, Go, C#) for RAG, LLMs, bounding boxes, and table extraction
Documentation
name: Release & Publish

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      target:
        description: 'Publish target'
        required: false
        default: 'all'
        type: choice
        options:
          - all
          - nuget
          - npm
          - pypi

permissions:
  contents: read

jobs:
  build-native-matrix:
    name: 🔨 Build Native (${{ matrix.target.os }})
    runs-on: ${{ matrix.target.runner }}
    strategy:
      fail-fast: false
      matrix:
        target:
          - os: linux-x64
            runner: ubuntu-latest
            lib_file: target/release/librasgapdf.so
            artifact_name: librasgapdf.so
          - os: windows-x64
            runner: windows-latest
            lib_file: target/release/rasgapdf.dll
            artifact_name: rasgapdf.dll
          - os: macos-x64
            runner: macos-latest
            lib_file: target/release/librasgapdf.dylib
            artifact_name: librasgapdf.dylib
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0

      - name: Install Linux dependencies
        if: runner.os == 'Linux'
        run: |
          sudo apt-get update
          sudo apt-get install -y pkg-config libfontconfig1-dev libfreetype6-dev libharfbuzz-dev libclang-dev

      - name: Set up Rust
        uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable

      - name: Build Rust Shared Library (Linux / Windows)
        if: runner.os != 'macOS'
        run: cargo build --release

      - name: Build Universal macOS Shared Library (ARM64 + x86_64)
        if: runner.os == 'macOS'
        run: |
          rustup target add aarch64-apple-darwin x86_64-apple-darwin
          cargo build --release --target aarch64-apple-darwin
          cargo build --release --target x86_64-apple-darwin
          mkdir -p target/release
          lipo -create -output target/release/librasgapdf.dylib target/aarch64-apple-darwin/release/librasgapdf.dylib target/x86_64-apple-darwin/release/librasgapdf.dylib

      - name: Upload Native Artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: native-${{ matrix.target.os }}
          path: ${{ matrix.target.lib_file }}
          retention-days: 1

  publish-pypi:
    name: 🐍 Publish to PyPI (Multi-Platform with Provenance)
    needs: [build-native-matrix]
    if: github.event_name == 'release' || inputs.target == 'all' || inputs.target == 'pypi'
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0

      - name: Download Linux Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-linux-x64
          path: bindings/python/rasgapdf/

      - name: Download Windows Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-windows-x64
          path: bindings/python/rasgapdf/

      - name: Download macOS Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-macos-x64
          path: bindings/python/rasgapdf/

      - name: Verify Multi-OS Native Binaries for Python
        run: |
          ls -la bindings/python/rasgapdf/librasgapdf.so
          ls -la bindings/python/rasgapdf/rasgapdf.dll
          ls -la bindings/python/rasgapdf/librasgapdf.dylib

      - name: Set up Python
        uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.0.0
        with:
          python-version: "3.11"

      - name: Build sdist and wheel
        run: |
          cd bindings/python
          python -m pip install --upgrade pip build twine
          python -m build
          twine check dist/*

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
        with:
          packages-dir: bindings/python/dist/
          attestations: true

  publish-npm:
    name: 📦 Publish to npm (Multi-Platform with Provenance)
    needs: [build-native-matrix]
    if: github.event_name == 'release' || inputs.target == 'all' || inputs.target == 'npm'
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0

      - name: Download Linux Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-linux-x64
          path: bindings/nodejs/

      - name: Download Windows Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-windows-x64
          path: bindings/nodejs/

      - name: Download macOS Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-macos-x64
          path: bindings/nodejs/

      - name: Verify Multi-OS Native Binaries for Node
        run: |
          ls -la bindings/nodejs/librasgapdf.so
          ls -la bindings/nodejs/rasgapdf.dll
          ls -la bindings/nodejs/librasgapdf.dylib

      - name: Set up Node.js
        uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.0.0
        with:
          node-version: "22"
          registry-url: "https://registry.npmjs.org"

      - name: Publish to npm with Provenance
        run: |
          cd bindings/nodejs
          npm publish --access public --provenance
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

  publish-nuget:
    name: 🔷 Publish to NuGet (.NET Multi-Platform)
    needs: [build-native-matrix]
    if: github.event_name == 'release' || inputs.target == 'all' || inputs.target == 'nuget'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0

      - name: Create Target Release Directory
        run: mkdir -p target/release

      - name: Download Linux Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-linux-x64
          path: target/release/

      - name: Download Windows Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-windows-x64
          path: target/release/

      - name: Download macOS Library
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          name: native-macos-x64
          path: target/release/

      - name: Set up .NET
        uses: actions/setup-dotnet@v6
        with:
          dotnet-version: '8.0.x'

      - name: Build and Pack NuGet Package
        run: |
          cd bindings/csharp
          dotnet pack -c Release -o dist

      - name: NuGet login (OIDC Trusted Publishing)
        id: login
        continue-on-error: true
        uses: NuGet/login@v1
        with:
          user: MartinsMessias

      - name: Publish to NuGet.org
        run: |
          KEY="${{ steps.login.outputs.NUGET_API_KEY }}"
          if [ -z "$KEY" ]; then
            KEY="${{ secrets.NUGET_API_KEY }}"
          fi
          if [ -n "$KEY" ]; then
            dotnet nuget push bindings/csharp/dist/*.nupkg \
              --api-key "$KEY" \
              --source https://api.nuget.org/v3/index.json \
              --skip-duplicate
          else
            echo "Neither Trusted Publishing nor NUGET_API_KEY available; skipping push"
          fi

  publish-crates:
    name: 🦀 Publish to crates.io
    if: github.event_name == 'release' || inputs.target == 'all'
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0

      - name: Install Linux dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y pkg-config libfontconfig1-dev libfreetype6-dev libharfbuzz-dev libclang-dev

      - name: Set up Rust
        uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable

      - name: Publish to crates.io
        run: cargo publish || echo "Already published to crates.io"
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  sync-huggingface:
    name: 🤗 Sync to Hugging Face (Model & Space)
    if: github.event_name == 'release' || inputs.target == 'all'
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0

      - name: Set up Python
        uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.0.0
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install huggingface_hub

      - name: Sync Model Repository and Space to Hugging Face
        run: python upload_to_hf.py
        env:
          HF_TOKEN: ${{ secrets.HF_TOKEN }}

  generate-sbom:
    name: 🛡️ Generate & Attest SBOM (Supply Chain Security)
    if: github.event_name == 'release' || inputs.target == 'all'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      id-token: write
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0

      - name: Generate SPDX SBOM
        uses: anchore/sbom-action@66cbf4bc1f1c0d2edc94016e65bc221b6bb0ad6c # v0.24.3
        with:
          format: spdx-json
          output-file: rasgapdf-sbom.spdx.json

      - name: Attach SBOM to GitHub Release
        if: github.event_name == 'release'
        uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.0
        with:
          files: rasgapdf-sbom.spdx.json