name: Release
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g., v0.1.1)'
required: true
type: string
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
jobs:
validate:
name: Validate Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v6
- name: Get version from Cargo.toml
id: version
run: |
VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Detected version: $VERSION"
- name: Validate tag matches version
run: |
TAG="${{ github.ref_name }}"
VERSION="${{ steps.version.outputs.version }}"
EXPECTED_TAG="v$VERSION"
if [ "$TAG" != "$EXPECTED_TAG" ]; then
echo "Error: Tag '$TAG' does not match Cargo.toml version '$VERSION'"
echo "Expected tag: $EXPECTED_TAG"
exit 1
fi
- name: Validate version consistency
run: |
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
PY_VERSION=$(grep '^version = ' pyproject.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
if [ "$CARGO_VERSION" != "$PY_VERSION" ]; then
echo "Error: Cargo.toml ($CARGO_VERSION) and pyproject.toml ($PY_VERSION) versions don't match"
exit 1
fi
echo "✓ Cargo.toml and pyproject.toml versions match: $CARGO_VERSION"
- name: Validate all language binding versions
run: |
VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
JS_VERSION=$(node -p "require('./js/package.json').version")
WASM_VERSION=$(node -p "require('./wasm-pkg/package.json').version")
CSHARP_VERSION=$(grep '<Version>' csharp/PdfOxide/PdfOxide.csproj | sed 's/.*<Version>\(.*\)<\/Version>.*/\1/')
ERRORS=0
for LANG_VER in "js/package.json:$JS_VERSION" "wasm-pkg/package.json:$WASM_VERSION" "csharp/PdfOxide.csproj:$CSHARP_VERSION"; do
FILE=$(echo $LANG_VER | cut -d: -f1)
VER=$(echo $LANG_VER | cut -d: -f2)
if [ "$VER" != "$VERSION" ]; then
echo "Error: $FILE ($VER) does not match Cargo.toml ($VERSION)"
ERRORS=$((ERRORS + 1))
fi
done
if [ $ERRORS -gt 0 ]; then exit 1; fi
echo "✓ All language binding versions match: $VERSION"
- name: Verify release is from main branch
run: |
# Fetch main branch
git fetch origin main
# Get the commit SHA the tag points to
TAG_SHA=$(git rev-parse HEAD)
# Check if this commit is reachable from main
if ! git merge-base --is-ancestor $TAG_SHA origin/main; then
echo "Error: Release tags must be created from commits on the main branch"
echo "Tag SHA: $TAG_SHA"
echo "Please merge your changes to main first, then create the release tag"
exit 1
fi
echo "✓ Verified: Tag points to a commit on main branch"
build-binaries:
name: Build ${{ matrix.target }}
needs: validate
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: pdf_oxide-linux-x86_64
use_cross: false
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
artifact_name: pdf_oxide-linux-x86_64-musl
use_cross: false
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
artifact_name: pdf_oxide-linux-aarch64
use_cross: true
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: pdf_oxide-macos-x86_64
use_cross: false
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: pdf_oxide-macos-aarch64
use_cross: false
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: pdf_oxide-windows-x86_64
use_cross: false
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache cargo registry
uses: actions/cache@v5
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-${{ matrix.target }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v5
with:
path: ~/.cargo/git
key: ${{ runner.os }}-${{ matrix.target }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Install musl tools (Linux musl)
if: matrix.target == 'x86_64-unknown-linux-musl'
run: sudo apt-get update && sudo apt-get install -y musl-tools
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Build binaries
shell: bash
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: ${{ matrix.target == 'aarch64-unknown-linux-gnu' && 'aarch64-linux-gnu-gcc' || '' }}
run: |
cargo build --release -p pdf_oxide_cli --target ${{ matrix.target }}
cargo build --release -p pdf_oxide_mcp --target ${{ matrix.target }}
- name: Build .deb package (Linux x86_64 glibc)
if: matrix.target == 'x86_64-unknown-linux-gnu'
run: |
cargo install cargo-deb
cargo deb -p pdf_oxide_cli --no-build --target x86_64-unknown-linux-gnu
- name: Upload .deb artifact
if: matrix.target == 'x86_64-unknown-linux-gnu'
uses: actions/upload-artifact@v7
with:
name: debian-package
path: target/x86_64-unknown-linux-gnu/debian/*.deb
retention-days: 7
- name: Create archive (Unix)
if: runner.os != 'Windows'
shell: bash
run: |
VERSION="${{ needs.validate.outputs.version }}"
mkdir -p dist
cd target/${{ matrix.target }}/release
tar czf ../../../dist/${{ matrix.artifact_name }}-${VERSION}.tar.gz pdf-oxide pdf-oxide-mcp
- name: Create archive (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$VERSION = "${{ needs.validate.outputs.version }}"
New-Item -ItemType Directory -Force -Path dist
Set-Location target/${{ matrix.target }}/release
Compress-Archive -Path @("pdf-oxide.exe", "pdf-oxide-mcp.exe") -DestinationPath ../../../dist/${{ matrix.artifact_name }}-${VERSION}.zip
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact_name }}
path: dist/*
retention-days: 7
build-wasm:
name: Build WASM
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache cargo registry
uses: actions/cache@v5
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-wasm-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Build WASM binary
run: cargo build --lib --target wasm32-unknown-unknown --features wasm --release
- name: Install matching wasm-bindgen-cli
run: |
WASM_BINDGEN_VERSION=$(grep -A1 'name = "wasm-bindgen"' Cargo.lock | grep version | head -1 | sed 's/.*"\(.*\)"/\1/')
echo "Installing wasm-bindgen-cli@${WASM_BINDGEN_VERSION}"
cargo install wasm-bindgen-cli --version "$WASM_BINDGEN_VERSION"
- name: Generate bindings
run: |
wasm-bindgen --target nodejs --out-dir wasm-out/ \
target/wasm32-unknown-unknown/release/pdf_oxide.wasm
- name: Copy package files
run: |
cp wasm-pkg/package.json wasm-out/
cp wasm-pkg/README.md wasm-out/
- name: Upload WASM artifact
uses: actions/upload-artifact@v7
with:
name: wasm-package
path: wasm-out/
retention-days: 7
build-native-libs:
name: Build native lib (${{ matrix.target }})
needs: validate
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: native-linux-x86_64
lib_name: libpdf_oxide.so
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
artifact_name: native-linux-aarch64
lib_name: libpdf_oxide.so
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: native-macos-x86_64
lib_name: libpdf_oxide.dylib
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: native-macos-aarch64
lib_name: libpdf_oxide.dylib
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: native-windows-x86_64
lib_name: pdf_oxide.dll
- os: windows-latest
target: aarch64-pc-windows-msvc
artifact_name: native-windows-aarch64
lib_name: pdf_oxide.dll
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache cargo registry
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-${{ matrix.target }}-native-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install cross-compilation tools (Linux ARM64)
if: contains(matrix.target, 'aarch64-unknown-linux')
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Build cdylib
shell: bash
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: ${{ contains(matrix.target, 'aarch64-unknown-linux') && 'aarch64-linux-gnu-gcc' || '' }}
run: |
cargo build --release --lib --target ${{ matrix.target }}
mkdir -p native-out
cp target/${{ matrix.target }}/release/${{ matrix.lib_name }} native-out/
# Also copy the C header
cp include/pdf_oxide_c/pdf_oxide.h native-out/
- name: Upload native lib
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact_name }}
path: native-out/
retention-days: 7
update-go-native-libs:
name: Update Go native libs
needs: [validate, build-native-libs]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Download all native libraries
uses: actions/download-artifact@v8
with:
pattern: native-*
path: native-libs
- name: Stage native libs in Go module
run: |
# Map artifact names to Go platform dirs
cp native-libs/native-linux-x86_64/libpdf_oxide.so go/lib/linux_amd64/
cp native-libs/native-linux-aarch64/libpdf_oxide.so go/lib/linux_arm64/
cp native-libs/native-macos-x86_64/libpdf_oxide.dylib go/lib/darwin_amd64/
cp native-libs/native-macos-aarch64/libpdf_oxide.dylib go/lib/darwin_arm64/
cp native-libs/native-windows-x86_64/pdf_oxide.dll go/lib/windows_amd64/
cp native-libs/native-windows-aarch64/pdf_oxide.dll go/lib/windows_arm64/ 2>/dev/null || true
echo "=== Go native libs staged ==="
find go/lib -type f -not -name ".gitkeep" -not -name "README.md" | sort
- name: Commit and push native libs
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add go/lib/
if git diff --cached --quiet; then
echo "No changes to native libs"
else
git commit -m "ci: update Go native libs for v${{ needs.validate.outputs.version }}"
git push origin HEAD:main
fi
- name: Create Go module tag
run: |
VERSION="${{ needs.validate.outputs.version }}"
# Go submodule tags use directory prefix
# Since go.mod is in go/, the tag is go/v{VERSION}
git tag "go/v${VERSION}"
git push origin "go/v${VERSION}"
build-nodejs:
name: Build Node.js (${{ matrix.artifact_name }})
needs: [validate, build-native-libs]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
artifact_name: nodejs-linux-x64
native_artifact: native-linux-x86_64
node_platform: linux
node_arch: x64
- os: ubuntu-latest
artifact_name: nodejs-linux-arm64
native_artifact: native-linux-aarch64
node_platform: linux
node_arch: arm64
- os: macos-latest
artifact_name: nodejs-macos-x64
native_artifact: native-macos-x86_64
node_platform: darwin
node_arch: x64
- os: macos-latest
artifact_name: nodejs-macos-arm64
native_artifact: native-macos-aarch64
node_platform: darwin
node_arch: arm64
- os: windows-latest
artifact_name: nodejs-windows-x64
native_artifact: native-windows-x86_64
node_platform: win32
node_arch: x64
steps:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Download native library
uses: actions/download-artifact@v8
with:
name: ${{ matrix.native_artifact }}
path: js/build/Release/
- name: Prepare npm package
working-directory: js
shell: bash
run: |
VERSION="${{ needs.validate.outputs.version }}"
# Bundle the native lib, JS wrapper, and type definitions
mkdir -p dist
cp build/Release/* dist/ 2>/dev/null || true
cp pdf_oxide.js dist/
cp pdf_oxide.d.ts dist/
cp index.js dist/ 2>/dev/null || true
cp index.d.ts dist/ 2>/dev/null || true
cp package.json dist/
cp binding.cc dist/ 2>/dev/null || true
# Create platform-specific tarball
cd dist
tar czf ../${{ matrix.artifact_name }}-${VERSION}.tar.gz .
- name: Upload Node.js package
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact_name }}
path: js/${{ matrix.artifact_name }}-*.tar.gz
retention-days: 7
build-csharp:
name: Build C# NuGet
needs: [validate, build-native-libs]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Download all native libraries
uses: actions/download-artifact@v8
with:
pattern: native-*
path: native-libs
- name: Stage native libraries for NuGet
run: |
# Copy each platform's native lib to the expected target/ paths
mkdir -p target/release
mkdir -p target/aarch64-unknown-linux-gnu/release
mkdir -p target/aarch64-apple-darwin/release
mkdir -p target/aarch64-pc-windows-msvc/release
# x64 libraries go to target/release/
cp native-libs/native-linux-x86_64/libpdf_oxide.so target/release/ 2>/dev/null || true
cp native-libs/native-macos-x86_64/libpdf_oxide.dylib target/release/ 2>/dev/null || true
cp native-libs/native-windows-x86_64/pdf_oxide.dll target/release/ 2>/dev/null || true
# ARM64 libraries go to cross-compilation target paths
cp native-libs/native-linux-aarch64/libpdf_oxide.so target/aarch64-unknown-linux-gnu/release/ 2>/dev/null || true
cp native-libs/native-macos-aarch64/libpdf_oxide.dylib target/aarch64-apple-darwin/release/ 2>/dev/null || true
cp native-libs/native-windows-aarch64/pdf_oxide.dll target/aarch64-pc-windows-msvc/release/ 2>/dev/null || true
echo "=== Staged native libraries ==="
find target -name "*.so" -o -name "*.dylib" -o -name "*.dll" | sort
- name: Build NuGet package
working-directory: csharp/PdfOxide
run: |
dotnet pack -c Release -o ../../nuget-out /p:Version=${{ needs.validate.outputs.version }}
- name: Upload NuGet package
uses: actions/upload-artifact@v7
with:
name: nuget-package
path: nuget-out/*.nupkg
retention-days: 7
generate-python-stubs:
name: Generate Python type stubs
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Generate type stubs
run: uvx rylai -o python/pdf_oxide/
- name: Upload type stubs
uses: actions/upload-artifact@v7
with:
name: python-type-stubs
path: python/pdf_oxide/*.pyi
retention-days: 7
build-python-wheels:
name: Build Python wheels (${{ matrix.target }})
needs: [validate, generate-python-stubs]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: wheels-linux-x86_64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
artifact_name: wheels-linux-aarch64
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: wheels-macos-x86_64
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: wheels-macos-aarch64
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: wheels-windows-x86_64
- os: windows-latest
target: aarch64-pc-windows-msvc
artifact_name: wheels-windows-aarch64
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install maturin
run: uv pip install --system maturin
- name: Install Linux cross-compilation tools
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Download type stubs
uses: actions/download-artifact@v8
with:
name: python-type-stubs
path: python/pdf_oxide/
- name: Build wheels
shell: bash
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: ${{ matrix.target == 'aarch64-unknown-linux-gnu' && 'aarch64-linux-gnu-gcc' || '' }}
run: maturin build --release --features python --target ${{ matrix.target }} --out dist
- name: Build sdist
if: matrix.target == 'x86_64-unknown-linux-gnu'
run: maturin sdist --out dist
- name: Upload wheels
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact_name }}
path: dist/*
retention-days: 7
build-python-wheels-musl:
name: Build Python wheels (linux ${{ matrix.target }} musllinux)
needs: [validate, generate-python-stubs]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@v6
- name: Download type stubs
uses: actions/download-artifact@v8
with:
name: python-type-stubs
path: python/pdf_oxide/
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: musllinux_1_2
args: --release --features python --out dist
- name: Upload wheels
uses: actions/upload-artifact@v7
with:
name: wheels-linux-${{ matrix.target }}-musl
path: dist/*
retention-days: 7
create-release:
name: Create GitHub Release
needs: [validate, build-binaries, build-python-wheels, build-python-wheels-musl, build-wasm, build-nodejs, build-csharp]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Download all artifacts
uses: actions/download-artifact@v8
with:
path: artifacts
- name: Organize release files
run: |
mkdir -p release-files
find artifacts -type f \( -name "*.tar.gz" -o -name "*.zip" -o -name "*.whl" -o -name "*.deb" -o -name "*.nupkg" \) -exec cp {} release-files/ \;
echo "=== Release files ==="
ls -lh release-files/
- name: Extract release notes from CHANGELOG
run: |
chmod +x .github/scripts/extract-release-notes.sh
.github/scripts/extract-release-notes.sh "${{ needs.validate.outputs.version }}"
- name: Read release title
id: title
run: echo "title=$(cat release-title.txt)" >> $GITHUB_OUTPUT
- name: Create release
uses: softprops/action-gh-release@v2
with:
name: ${{ steps.title.outputs.title }}
body_path: release-notes.md
files: release-files/*
draft: false
prerelease: ${{ contains(needs.validate.outputs.version, '-') }}
fail_on_unmatched_files: false
publish-crates:
name: Publish to crates.io
needs: [validate, create-release]
runs-on: ubuntu-latest
if: ${{ !contains(needs.validate.outputs.version, '-') }}
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Verify crates.io readiness
run: cargo publish -p pdf_oxide --dry-run
- name: Publish to crates.io
run: cargo publish -p pdf_oxide
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }}
- name: Publish CLI to crates.io
run: cargo publish -p pdf_oxide_cli
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }}
- name: Publish MCP server to crates.io
run: cargo publish -p pdf_oxide_mcp
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }}
publish-pypi:
name: Publish to PyPI
needs: [validate, build-python-wheels, create-release]
runs-on: ubuntu-latest
if: ${{ !contains(needs.validate.outputs.version, '-') }}
steps:
- name: Download wheel artifacts
uses: actions/download-artifact@v8
with:
path: wheels
pattern: wheels-*
merge-multiple: true
- name: List wheels
run: |
echo "=== Wheels to publish ==="
ls -lh wheels/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
packages-dir: wheels/
skip-existing: true
publish-npm:
name: Publish to npm
needs: [validate, build-wasm, create-release]
runs-on: ubuntu-latest
if: ${{ !contains(needs.validate.outputs.version, '-') }}
steps:
- name: Download WASM artifact
uses: actions/download-artifact@v8
with:
name: wasm-package
path: wasm-out
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: List package contents
run: |
echo "=== WASM package contents ==="
ls -lh wasm-out/
- name: Publish to npm
working-directory: wasm-out
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-packaging:
name: Publish Homebrew & Scoop
needs: [validate, create-release]
runs-on: ubuntu-latest
if: ${{ !contains(needs.validate.outputs.version, '-') }}
steps:
- uses: actions/checkout@v6
- name: Download release archives
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ needs.validate.outputs.version }}"
mkdir -p release-archives
cd release-archives
gh release download "v${VERSION}" \
--pattern "pdf_oxide-macos-aarch64-${VERSION}.tar.gz" \
--pattern "pdf_oxide-macos-x86_64-${VERSION}.tar.gz" \
--pattern "pdf_oxide-linux-x86_64-musl-${VERSION}.tar.gz" \
--pattern "pdf_oxide-windows-x86_64-${VERSION}.zip"
- name: Compute SHA256 hashes
id: hashes
run: |
VERSION="${{ needs.validate.outputs.version }}"
cd release-archives
echo "macos_arm=$(sha256sum pdf_oxide-macos-aarch64-${VERSION}.tar.gz | cut -d' ' -f1)" >> $GITHUB_OUTPUT
echo "macos_x86=$(sha256sum pdf_oxide-macos-x86_64-${VERSION}.tar.gz | cut -d' ' -f1)" >> $GITHUB_OUTPUT
echo "linux_x86=$(sha256sum pdf_oxide-linux-x86_64-musl-${VERSION}.tar.gz | cut -d' ' -f1)" >> $GITHUB_OUTPUT
echo "windows=$(sha256sum pdf_oxide-windows-x86_64-${VERSION}.zip | cut -d' ' -f1)" >> $GITHUB_OUTPUT
- name: Generate Homebrew formula
run: |
VERSION="${{ needs.validate.outputs.version }}"
sed \
-e "s/{{VERSION}}/${VERSION}/g" \
-e "s/{{SHA256_MACOS_ARM}}/${{ steps.hashes.outputs.macos_arm }}/g" \
-e "s/{{SHA256_MACOS_X86}}/${{ steps.hashes.outputs.macos_x86 }}/g" \
-e "s/{{SHA256_LINUX_X86}}/${{ steps.hashes.outputs.linux_x86 }}/g" \
.github/templates/pdf-oxide.rb > pdf-oxide.rb
echo "=== Generated Homebrew formula ==="
cat pdf-oxide.rb
- name: Generate Scoop manifest
run: |
VERSION="${{ needs.validate.outputs.version }}"
sed \
-e "s/{{VERSION}}/${VERSION}/g" \
-e "s/{{SHA256_WINDOWS}}/${{ steps.hashes.outputs.windows }}/g" \
.github/templates/pdf-oxide.json > pdf-oxide.json
echo "=== Generated Scoop manifest ==="
cat pdf-oxide.json
- name: Upload packaging artifacts
uses: actions/upload-artifact@v7
with:
name: packaging-manifests
path: |
pdf-oxide.rb
pdf-oxide.json
retention-days: 90
- name: Push to Homebrew tap
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/yfedoseev/homebrew-tap.git" tap-repo
cp pdf-oxide.rb tap-repo/Formula/pdf-oxide.rb
cd tap-repo
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/pdf-oxide.rb
git commit -m "Update pdf-oxide to ${{ needs.validate.outputs.version }}"
git push
- name: Push Scoop manifest
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/yfedoseev/scoop-pdf-oxide.git" scoop-repo
cp pdf-oxide.json scoop-repo/pdf-oxide.json
cd scoop-repo
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add pdf-oxide.json
git commit -m "Update pdf-oxide to ${{ needs.validate.outputs.version }}"
git push
publish-npm-native:
name: Publish to npm (pdf-oxide)
needs: [validate, build-nodejs, create-release]
runs-on: ubuntu-latest
if: ${{ !contains(needs.validate.outputs.version, '-') }}
steps:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Publish to npm
working-directory: js
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-nuget:
name: Publish to NuGet
needs: [validate, build-csharp, create-release]
runs-on: ubuntu-latest
if: ${{ !contains(needs.validate.outputs.version, '-') }}
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Download NuGet package
uses: actions/download-artifact@v8
with:
name: nuget-package
path: nuget-out
- name: Publish to NuGet
run: |
dotnet nuget push nuget-out/*.nupkg \
--api-key ${{ secrets.NUGET_API_KEY }} \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate