undoc 0.1.19

High-performance Microsoft Office document extraction to Markdown
Documentation
name: Build and Publish Bindings

on:
  workflow_run:
    workflows: ["Release"]
    types: [completed]
  workflow_dispatch:
    inputs:
      publish:
        description: 'Publish to package registries'
        required: false
        default: 'false'

env:
  CARGO_TERM_COLOR: always

jobs:
  build-native:
    name: Build Native Libraries
    # Only run if Release workflow succeeded (or manual trigger)
    if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            artifact: libundoc.so
            runtime: linux-x64
          - os: ubuntu-latest
            target: x86_64-unknown-linux-musl
            artifact: libundoc.so
            runtime: linux-musl-x64
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            artifact: undoc.dll
            runtime: win-x64
          - os: macos-latest
            target: x86_64-apple-darwin
            artifact: libundoc.dylib
            runtime: osx-x64
          - os: macos-latest
            target: aarch64-apple-darwin
            artifact: libundoc.dylib
            runtime: osx-arm64

    steps:
      - uses: actions/checkout@v4

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install musl-tools
        if: contains(matrix.target, 'musl')
        run: sudo apt-get update && sudo apt-get install -y musl-tools

      - name: Build native library
        run: cargo build --release --target ${{ matrix.target }} --features ffi
        env:
          RUSTFLAGS: ${{ contains(matrix.target, 'musl') && '-C target-feature=-crt-static' || '' }}

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: native-${{ matrix.runtime }}
          path: target/${{ matrix.target }}/release/${{ matrix.artifact }}
          retention-days: 7

  build-python:
    name: Build Python Wheel
    needs: build-native
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Download all native libraries
        uses: actions/download-artifact@v4
        with:
          pattern: native-*
          path: ./native-libs/

      - name: Copy native libraries to package
        run: |
          mkdir -p bindings/python/src/undoc/lib/linux-x64
          mkdir -p bindings/python/src/undoc/lib/linux-musl-x64
          mkdir -p bindings/python/src/undoc/lib/win-x64
          mkdir -p bindings/python/src/undoc/lib/osx-x64
          mkdir -p bindings/python/src/undoc/lib/osx-arm64

          cp ./native-libs/native-linux-x64/* bindings/python/src/undoc/lib/linux-x64/
          cp ./native-libs/native-linux-musl-x64/* bindings/python/src/undoc/lib/linux-musl-x64/
          cp ./native-libs/native-win-x64/* bindings/python/src/undoc/lib/win-x64/
          cp ./native-libs/native-osx-x64/* bindings/python/src/undoc/lib/osx-x64/
          cp ./native-libs/native-osx-arm64/* bindings/python/src/undoc/lib/osx-arm64/

          echo "Native libraries copied:"
          find bindings/python/src/undoc/lib -type f

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

      - name: Build wheel
        working-directory: bindings/python
        run: python -m build

      - name: Verify wheel contents
        run: |
          echo "Wheel contents:"
          python3 -m zipfile -l bindings/python/dist/*.whl
          echo ""
          echo "Checking for all platform libraries:"
          python3 -m zipfile -l bindings/python/dist/*.whl | grep -E "(libundoc|undoc\.dll)" || echo "WARNING: Missing some native libraries!"

      - name: Upload wheel
        uses: actions/upload-artifact@v4
        with:
          name: python-wheel
          path: bindings/python/dist/*.whl
          retention-days: 7

  build-nuget:
    name: Build NuGet Package
    needs: build-native
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: Create runtime directories
        run: |
          mkdir -p bindings/csharp/Undoc/runtimes/win-x64/native
          mkdir -p bindings/csharp/Undoc/runtimes/linux-x64/native
          mkdir -p bindings/csharp/Undoc/runtimes/linux-musl-x64/native
          mkdir -p bindings/csharp/Undoc/runtimes/osx-x64/native
          mkdir -p bindings/csharp/Undoc/runtimes/osx-arm64/native

      - name: Download Windows native library
        uses: actions/download-artifact@v4
        with:
          name: native-win-x64
          path: bindings/csharp/Undoc/runtimes/win-x64/native/

      - name: Download Linux native library
        uses: actions/download-artifact@v4
        with:
          name: native-linux-x64
          path: bindings/csharp/Undoc/runtimes/linux-x64/native/

      - name: Download Linux musl native library
        uses: actions/download-artifact@v4
        with:
          name: native-linux-musl-x64
          path: bindings/csharp/Undoc/runtimes/linux-musl-x64/native/

      - name: Download macOS x64 native library
        uses: actions/download-artifact@v4
        with:
          name: native-osx-x64
          path: bindings/csharp/Undoc/runtimes/osx-x64/native/

      - name: Download macOS ARM64 native library
        uses: actions/download-artifact@v4
        with:
          name: native-osx-arm64
          path: bindings/csharp/Undoc/runtimes/osx-arm64/native/

      - name: Build NuGet package
        working-directory: bindings/csharp
        run: dotnet pack Undoc/Undoc.csproj -c Release -o ./artifacts

      - name: Upload NuGet package
        uses: actions/upload-artifact@v4
        with:
          name: nuget-package
          path: bindings/csharp/artifacts/*.nupkg
          retention-days: 7

  publish-pypi:
    name: Publish to PyPI
    needs: build-python
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' || github.event.inputs.publish == 'true' }}

    steps:
      - name: Download Python wheel
        uses: actions/download-artifact@v4
        with:
          name: python-wheel
          path: dist/

      - name: List wheel contents
        run: |
          echo "Wheel file:"
          ls -la dist/
          echo ""
          echo "Wheel contents:"
          python3 -m zipfile -l dist/*.whl

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}
          packages-dir: dist/
          skip-existing: true

  publish-nuget:
    name: Publish to NuGet
    needs: build-nuget
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' || github.event.inputs.publish == 'true' }}

    steps:
      - name: Download NuGet package
        uses: actions/download-artifact@v4
        with:
          name: nuget-package
          path: ./

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: Publish to NuGet
        run: dotnet nuget push "*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate

  test-python:
    name: Test Python Bindings
    needs: build-python
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            python-version: '3.11'
          - os: windows-latest
            python-version: '3.11'
          - os: macos-latest
            python-version: '3.11'

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Download wheel
        uses: actions/download-artifact@v4
        with:
          name: python-wheel
          path: ./wheels/

      - name: Install package
        shell: bash
        run: |
          pip install pytest
          pip install ./wheels/*.whl

      - name: Run tests
        working-directory: bindings/python
        shell: bash
        run: pytest tests/ -v --ignore=tests/test_integration.py

  test-nuget:
    name: Test NuGet Package
    needs: build-nuget
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            artifact: native-linux-x64
            runtime: linux-x64
          - os: windows-latest
            artifact: native-win-x64
            runtime: win-x64
          - os: macos-latest
            artifact: native-osx-x64
            runtime: osx-x64

    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: Download native library
        uses: actions/download-artifact@v4
        with:
          name: ${{ matrix.artifact }}
          path: ./native-lib/

      - name: Build test project (with project reference)
        working-directory: bindings/csharp
        run: dotnet build Undoc.Tests/Undoc.Tests.csproj -c Release

      - name: Copy native library to test output (Unix)
        if: matrix.os != 'windows-latest'
        shell: bash
        run: |
          find bindings/csharp/Undoc.Tests/bin/Release -type d -name "net*" | while read dir; do
            cp ./native-lib/* "$dir/"
            echo "Copied native library to $dir"
            ls -la "$dir"
          done

      - name: Copy native library to test output (Windows)
        if: matrix.os == 'windows-latest'
        shell: pwsh
        run: |
          # On Windows, native undoc.dll conflicts with managed Undoc.dll (case-insensitive)
          # Rename to undoc_native.dll to avoid overwriting the managed assembly
          Get-ChildItem -Path "bindings/csharp/Undoc.Tests/bin/Release" -Directory -Recurse | Where-Object { $_.Name -like "net*" } | ForEach-Object {
            $srcFile = Get-ChildItem "./native-lib/*" | Select-Object -First 1
            $destFile = Join-Path $_.FullName "undoc_native.dll"
            Copy-Item $srcFile.FullName -Destination $destFile -Force
            Write-Host "Copied native library to $destFile"
            Write-Host "Test output directory (Undoc files):"
            Get-ChildItem $_.FullName | Where-Object { $_.Name -like "Undoc*" -or $_.Name -like "undoc*" }
          }

      - name: Run tests
        working-directory: bindings/csharp
        run: dotnet test Undoc.Tests/Undoc.Tests.csproj -c Release --no-build