name: Release - Crates & CLI on: workflow_dispatch: inputs: version: description: 'Version to release (e.g. 2.1.0)' required: true type: string dry-run: description: 'Dry run (build but do not publish)' type: boolean default: false permissions: contents: write actions: write env: CARGO_TERM_COLOR: always jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Validate version run: | CARGO_VERSION=$(grep '^version' crates/liteparse/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') if [ "$CARGO_VERSION" != "${{ inputs.version }}" ]; then echo "::error::Version mismatch: crates/liteparse/Cargo.toml has $CARGO_VERSION, expected ${{ inputs.version }}" exit 1 fi echo "Version validated: ${{ inputs.version }}" publish-crates: needs: validate if: ${{ !inputs.dry-run }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y libtesseract-dev libleptonica-dev - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git ~/.cache/pdfium-rs target key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} - name: Publish to crates.io run: | publish_if_new() { local crate=$1 local version=$(cargo metadata --format-version 1 --no-deps | jq -r ".packages[] | select(.name == \"$crate\") | .version") if cargo search "$crate" --limit 1 | grep -q "\"$version\""; then echo "$crate@$version already published, skipping" else cargo publish -p "$crate" --allow-dirty fi } publish_if_new liteparse-pdfium-sys publish_if_new liteparse-pdfium publish_if_new liteparse env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} build-binaries: needs: validate strategy: fail-fast: false matrix: include: - target: x86_64-unknown-linux-gnu os: ubuntu-22.04 artifact: lit-linux-x64 pdfium-dylib: libpdfium.so - target: aarch64-unknown-linux-gnu os: ubuntu-22.04-arm artifact: lit-linux-arm64 pdfium-dylib: libpdfium.so - target: aarch64-apple-darwin os: macos-latest artifact: lit-darwin-arm64 pdfium-dylib: libpdfium.dylib - target: x86_64-apple-darwin os: macos-26-intel artifact: lit-darwin-x64 pdfium-dylib: libpdfium.dylib - target: x86_64-pc-windows-msvc os: windows-latest artifact: lit-windows-x64 pdfium-dylib: pdfium.dll - target: aarch64-pc-windows-msvc os: windows-11-arm artifact: lit-windows-arm64 pdfium-dylib: pdfium.dll runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@1.95.0 with: targets: ${{ matrix.target }} - name: Install system dependencies (Linux) if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y libtesseract-dev libleptonica-dev - name: Install system dependencies (macOS) if: runner.os == 'macOS' run: brew install tesseract leptonica - name: Force Ninja generator (Windows) if: runner.os == 'Windows' run: echo "CMAKE_GENERATOR=Ninja" >> $GITHUB_ENV shell: bash - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git ~/.cache/pdfium-rs ~/Library/Caches/pdfium-rs ${{ runner.os == 'Windows' && format('{0}\pdfium-rs', env.LOCALAPPDATA) || '' }} target key: ${{ runner.os }}-${{ matrix.target }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} - name: Build run: cargo build --release --target ${{ matrix.target }} -p liteparse - name: Stage binary and pdfium (Unix) if: runner.os != 'Windows' shell: bash run: | mkdir -p staging/${{ matrix.artifact }} cp target/${{ matrix.target }}/release/lit staging/${{ matrix.artifact }}/lit chmod +x staging/${{ matrix.artifact }}/lit bash packages/node/scripts/copy-pdfium.sh staging/${{ matrix.artifact }} - name: Stage binary and pdfium (Windows) if: runner.os == 'Windows' shell: pwsh run: | New-Item -ItemType Directory -Force -Path "staging/${{ matrix.artifact }}" | Out-Null Copy-Item "target/${{ matrix.target }}/release/lit.exe" -Destination "staging/${{ matrix.artifact }}/lit.exe" $cacheBase = "$env:LOCALAPPDATA\pdfium-rs" if (-not (Test-Path $cacheBase)) { $cacheBase = "$env:USERPROFILE\.cache\pdfium-rs" } $dll = Get-ChildItem -Path $cacheBase -Recurse -Filter "pdfium.dll" | Select-Object -First 1 if ($dll) { Copy-Item $dll.FullName -Destination "staging/${{ matrix.artifact }}/pdfium.dll" Write-Host "Copied $($dll.FullName) -> staging/${{ matrix.artifact }}/pdfium.dll" } else { Write-Error "Could not find pdfium.dll in cache" exit 1 } - name: Package tarball shell: bash run: | mkdir -p dist tar -czf dist/${{ matrix.artifact }}.tar.gz -C staging ${{ matrix.artifact }} - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ matrix.artifact }} path: dist/${{ matrix.artifact }}.tar.gz if-no-files-found: error github-release: needs: [build-binaries, publish-crates] if: ${{ always() && needs.build-binaries.result == 'success' && (needs.publish-crates.result == 'success' || needs.publish-crates.result == 'skipped') }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Create git tag if: ${{ !inputs.dry-run }} run: | git tag "crates-v${{ inputs.version }}" git push origin "crates-v${{ inputs.version }}" - name: Create GitHub Release if: ${{ !inputs.dry-run }} uses: softprops/action-gh-release@v2 with: tag_name: crates-v${{ inputs.version }} name: "Crates & CLI v${{ inputs.version }}" generate_release_notes: true files: artifacts/**/*.tar.gz - name: Summary (dry run) if: ${{ inputs.dry-run }} run: | echo "## Dry Run Summary" >> $GITHUB_STEP_SUMMARY echo "Would release crates-v${{ inputs.version }}" >> $GITHUB_STEP_SUMMARY echo "Artifacts:" >> $GITHUB_STEP_SUMMARY find artifacts -name "*.tar.gz" -exec echo "- {}" \; >> $GITHUB_STEP_SUMMARY