bobine 0.5.11

PDF / Office / text → Markdown ingestion engine with ONNX formula OCR (TexTeller), layout analysis and OCR
Documentation
# Release workflow — dual publish on version tags.
#
# Tag `vX.Y.Z` on **main** (after merging rust_dev) triggers:
#   1. crates.io  — pure-Rust crate `bobine` (default features, no pyo3)
#   2. PyPI       — full Python package `bobine` via maturin (extension-module)
#
# Required secrets / configuration:
#   - secrets.CARGO_REGISTRY_TOKEN   → crates.io API token
#   - PyPI trusted publisher configured for this workflow + environment `pypi`
#     (Project: bobine · Workflow: release.yml · Environment: pypi)

name: Release

on:
  push:
    tags: ["v*"]
  workflow_dispatch:

permissions:
  contents: read

jobs:
  # ------------------------------------------------------------------
  # 1. crates.io — Rust library (no Python bindings)
  # ------------------------------------------------------------------
  crates-io:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - name: Tag matches Cargo.toml version
        run: |
          tag="${GITHUB_REF_NAME#v}"
          ver=$(grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)"/\1/')
          test "$tag" = "$ver" || { echo "tag v$tag != Cargo.toml $ver"; exit 1; }
      - name: Verify default build is Python-free
        run: cargo check --locked
      - name: Download onnxruntime (CPU — lib tests abort without a dylib)
        run: |
          curl -sL --max-time 300 -o /tmp/ort.tgz \
            https://github.com/microsoft/onnxruntime/releases/download/v1.28.1/onnxruntime-linux-x64-1.28.1.tgz
          mkdir -p /tmp/ort && tar xzf /tmp/ort.tgz -C /tmp/ort
      - name: Run library unit tests (integration needs onnxruntime)
        env:
          ORT_DYLIB_PATH: /tmp/ort/onnxruntime-linux-x64-1.28.1/lib/libonnxruntime.so.1.28.1
        run: cargo test --locked --lib
      - name: Publish to crates.io
        # Tags publish; manual dispatch is a dry-run (check + test only).
        if: startsWith(github.ref, 'refs/tags/v')
        run: cargo publish --locked
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  # ------------------------------------------------------------------
  # 2. PyPI — Python wheel matrix via maturin (trusted publishing)
  # ------------------------------------------------------------------
  pypi:
    # ubuntu + windows x86_64, macOS arm64 (native runners — no cross builds).
    # No Intel mac (deprecated runners), no other exotic targets.
    strategy:
      fail-fast: false
      matrix:
        platform:
          - runner: ubuntu-22.04
            target: x86_64
          - runner: windows-latest
            target: x64
          - runner: macos-latest
            target: aarch64
    runs-on: ${{ matrix.platform.runner }}
    permissions:
      id-token: write # PyPI trusted publishing
    steps:
      - uses: actions/checkout@v6

      - name: Build wheel (sdist on linux x86_64 too)
        uses: PyO3/maturin-action@v1
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist --locked --features extension-module
          # 2_28, not auto: auto resolves to CentOS 7-based manylinux2014
          # (OpenSSL 1.0.2 < openssl-sys minimum 1.1.0). Ignored on win/mac.
          manylinux: ${{ matrix.platform.manylinux || '2_28' }}
          sccache: true
          # Linux wheels build in a manylinux container: ort-sys build-deps
          # on ureq/native-tls → openssl-sys needs headers there (no-op on
          # windows/macos runners).
          before-script-linux: yum install -y openssl-devel

      - name: Upload wheels
        uses: actions/upload-artifact@v6
        with:
          name: wheels-${{ matrix.platform.runner }}-${{ matrix.platform.target }}
          path: dist

  # ------------------------------------------------------------------
  # 3. sdist + PyPI upload (single verified copy — no merge-multiple)
  # ------------------------------------------------------------------
  pypi-publish:
    needs: [pypi]
    runs-on: ubuntu-22.04
    environment: pypi
    permissions:
      id-token: write
    steps:
      - uses: actions/checkout@v6

      - name: Build sdist
        uses: PyO3/maturin-action@v1
        with:
          command: sdist
          args: --out dist

      - name: Download wheels (per-artifact dirs — never merge-multiple,
        # see legacy release postmortem: identical paths across artifacts
        # corrupt the merged zip)
        uses: actions/download-artifact@v6
        with:
          pattern: wheels-*
          path: dist

      - name: Flatten wheel directories (drop emptied artifact dirs —
        # the publisher rejects any non-distribution entry in dist/)
        run: |
          find dist -name '*.whl' -exec mv {} dist/ \;
          find dist -mindepth 1 -type d -empty -delete
          ls -la dist/

      - name: Publish to PyPI
        # Tags publish; manual dispatch stops after building wheels.
        if: startsWith(github.ref, 'refs/tags/v')
        uses: pypa/gh-action-pypi-publish@release/v1