Skip to content

Release v0.3.78 — 164 issues fixed: audit scope, contributor fixes, and the regression battery against v0.3.77 #935

Release v0.3.78 — 164 issues fixed: audit scope, contributor fixes, and the regression battery against v0.3.77

Release v0.3.78 — 164 issues fixed: audit scope, contributor fixes, and the regression battery against v0.3.77 #935

Workflow file for this run

name: R Bindings CI
on:
push:
branches: [ main, develop ]
paths:
- 'r/**'
- 'src/**'
- 'include/pdf_oxide_c/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/r.yml'
pull_request:
branches: [ main, develop ]
paths:
- 'r/**'
- 'src/**'
- 'include/pdf_oxide_c/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/r.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name != 'release' }}
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
PDF_OXIDE_INCLUDE_DIR: ${{ github.workspace }}/include
PDF_OXIDE_LIB_DIR: ${{ github.workspace }}/target/release
jobs:
test:
name: R on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1
with:
cache: false
rustflags: ''
- name: Cache Cargo build
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v4
with:
path: target
key: ${{ runner.os }}-cargo-build-release-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-release-
- name: Build cdylib (release, shipped binding feature set)
run: cargo build --release --lib --features ocr,rendering,signatures,barcodes,tsa-client,system-fonts
- name: Set up R
uses: r-lib/actions/setup-r@d3c5be51b12e724e68f33216ca3c148b66d5f0b6 # v2
with:
r-version: 'release'
# Pull prebuilt Linux binaries from Posit Public Package Manager.
# Source installs of roxygen2/lintr/etc. were silently failing to
# compile on the runner, leaving them missing for later steps.
use-public-rspm: true
- name: Install R deps
# Fail hard if any package is missing after install (install.packages
# only warns on a failed install). Uses the RSPM binary repo configured
# above (no explicit repos= override, which would force source).
#
# `backports` is a hard Imports dependency of lintr. On the RSPM binary
# path it was intermittently not pulled in, leaving lintr installed but
# unloadable ("there is no package called 'backports'") in the Lint
# step. Install and hard-verify it explicitly so the failure surfaces
# here (as a missing-package error) rather than later at library(lintr).
run: |
Rscript -e 'install.packages(c("backports", "tinytest", "lintr", "roxygen2", "rcmdcheck"))' \
-e 'pkgs <- c("backports","tinytest","lintr","roxygen2","rcmdcheck")' \
-e 'miss <- pkgs[!pkgs %in% rownames(installed.packages())]' \
-e 'if (length(miss)) { cat("Failed to install:", miss, "\n"); quit(status=1) }'
- name: Generate man/ docs (roxygen2)
run: Rscript -e 'roxygen2::roxygenise("r")'
# NOTE: Air (Posit's Rust-based R formatter) is the 2026 SOTA R formatter
# and a planned follow-up; deferred here pending a SHA-pinned setup action.
- name: Lint (lintr)
run: Rscript -e 'library(lintr); l <- lint_dir("r/R"); print(l); quit(status = if (length(l) > 0) 1L else 0L)'
- name: R CMD check (no manual/vignettes)
shell: bash
run: |
export LD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${LD_LIBRARY_PATH:-}"
export DYLD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${DYLD_LIBRARY_PATH:-}"
Rscript -e 'rcmdcheck::rcmdcheck("r", args=c("--no-manual","--no-vignettes"), error_on="warning")'
- name: R CMD INSTALL
run: R CMD INSTALL r/
- name: Run tests (tinytest api-coverage)
shell: bash
run: |
export LD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${LD_LIBRARY_PATH:-}"
export DYLD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${DYLD_LIBRARY_PATH:-}"
Rscript -e 'library(tinytest); out <- test_package("pdfoxide"); print(out); if (any(!sapply(out, isTRUE))) quit(status=1)'
- name: Run example (basic_extraction, with assertion)
shell: bash
run: |
set -uo pipefail
export LD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${LD_LIBRARY_PATH:-}"
export DYLD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${DYLD_LIBRARY_PATH:-}"
OUT="$(Rscript r/inst/examples/basic_extraction.R)"
echo "$OUT"
echo "$OUT" | grep -q "Hello pdf_oxide" || { echo "::error::example output missing expected text"; exit 1; }
- name: Run example (html_extraction, with assertion)
shell: bash
run: |
set -uo pipefail
export LD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${LD_LIBRARY_PATH:-}"
export DYLD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${DYLD_LIBRARY_PATH:-}"
OUT="$(Rscript r/inst/examples/html_extraction.R)"
echo "$OUT"
echo "$OUT" | grep -q "HTML OK" || { echo "::error::html_extraction example did not pass"; exit 1; }
- name: Run example (words_geometry, with assertion)
shell: bash
run: |
set -uo pipefail
export LD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${LD_LIBRARY_PATH:-}"
export DYLD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${DYLD_LIBRARY_PATH:-}"
OUT="$(Rscript r/inst/examples/words_geometry.R)"
echo "$OUT"
echo "$OUT" | grep -q "WORDS OK" || { echo "::error::words_geometry example did not pass"; exit 1; }
- name: Run example (tables_extraction, with assertion)
shell: bash
run: |
set -uo pipefail
export LD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${LD_LIBRARY_PATH:-}"
export DYLD_LIBRARY_PATH="${PDF_OXIDE_LIB_DIR}:${DYLD_LIBRARY_PATH:-}"
OUT="$(Rscript r/inst/examples/tables_extraction.R)"
echo "$OUT"
echo "$OUT" | grep -q "TABLES OK" || { echo "::error::tables_extraction example did not pass"; exit 1; }