Files
bentopdf/.github/workflows/update-bentopdf-viewer.yml
T

271 lines
9.4 KiB
YAML

name: Update PDF Engine and Viewer
on:
workflow_dispatch:
schedule:
- cron: '17 4 * * *'
permissions:
contents: read
concurrency:
group: update-engine
cancel-in-progress: false
env:
FORK_URL: https://github.com/alam00000/bentopdf-pdfium-viewer
HUSKY: 0
jobs:
build:
runs-on: ubuntu-latest
if: github.repository == 'alam00000/bentopdf'
permissions:
contents: read
outputs:
run: ${{ steps.gate.outputs.run }}
version: ${{ steps.gate.outputs.version }}
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Read current upstream marker
id: current
run: |
if [ -f vendor/bentopdf-viewer/.upstream-version ]; then
echo "version=$(cat vendor/bentopdf-viewer/.upstream-version)" >> "$GITHUB_OUTPUT"
else
echo "version=" >> "$GITHUB_OUTPUT"
fi
- name: Read fork HEAD
id: upstream
run: echo "version=$(git ls-remote "$FORK_URL" refs/heads/main | cut -c1-12)" >> "$GITHUB_OUTPUT"
- name: Should update?
id: gate
env:
CURRENT: ${{ steps.current.outputs.version }}
UPSTREAM: ${{ steps.upstream.outputs.version }}
run: |
if ! [[ "$UPSTREAM" =~ ^[0-9a-f]{12}$ ]]; then
echo "::error::Unexpected fork HEAD: $UPSTREAM"
exit 1
fi
echo "version=$UPSTREAM" >> "$GITHUB_OUTPUT"
if [ "$UPSTREAM" = "$CURRENT" ]; then
echo "run=false" >> "$GITHUB_OUTPUT"
echo "Already on $CURRENT."
else
echo "run=true" >> "$GITHUB_OUTPUT"
echo "Updating $CURRENT -> $UPSTREAM"
fi
- name: Setup Node
if: steps.gate.outputs.run == 'true'
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Enable corepack (pnpm)
if: steps.gate.outputs.run == 'true'
run: corepack enable
- name: Clone the viewer fork
if: steps.gate.outputs.run == 'true'
run: git clone --depth 1 --branch main "$FORK_URL" ./_fork
- name: Require a published engine
if: steps.gate.outputs.run == 'true'
run: |
test -s ./_fork/packages/pdfium/src/vendor/pdfium.wasm
test -s ./_fork/packages/pdfium/src/vendor/pdfium.js
- name: Pack the engine
if: steps.gate.outputs.run == 'true'
id: engine
env:
SHA: ${{ steps.gate.outputs.version }}
run: |
set -euo pipefail
VENDOR=./_fork/packages/pdfium/src/vendor
STAGE=$(mktemp -d)/package
mkdir -p "$STAGE"
cp "$VENDOR/pdfium.js" "$STAGE/editcore.js"
cp "$VENDOR/pdfium.wasm" "$STAGE/editcore.wasm"
cat > "$STAGE/package.json" <<JSON
{
"name": "bentopdf-pdfium",
"version": "0.0.0-$SHA",
"type": "module",
"main": "editcore.js",
"exports": { ".": "./editcore.js", "./editcore.wasm": "./editcore.wasm" },
"license": "AGPL-3.0"
}
JSON
mkdir -p vendor/bentopdf-pdfium
OUT="vendor/bentopdf-pdfium/bentopdf-pdfium-$SHA.tgz"
tar -czf "$OUT" -C "$(dirname "$STAGE")" package
find vendor/bentopdf-pdfium -maxdepth 1 -name 'bentopdf-pdfium*.tgz' ! -name "$(basename "$OUT")" -delete
echo "tarball=$OUT" >> "$GITHUB_OUTPUT"
- name: Build the viewer
if: steps.gate.outputs.run == 'true'
working-directory: ./_fork
run: |
pnpm install --no-frozen-lockfile
pnpm run build:snippet
- name: Pack the viewer without a second engine
if: steps.gate.outputs.run == 'true'
id: viewer
env:
SHA: ${{ steps.gate.outputs.version }}
run: |
set -euo pipefail
WORK=$(mktemp -d)
(cd ./_fork && npm pack ./viewers/snippet --pack-destination "$WORK" >/dev/null)
TMP=$(mktemp -d)
tar -xzf "$WORK"/*.tgz -C "$TMP"
rm -f "$TMP/package/dist/pdfium.wasm"
PKG="$TMP/package/package.json" node - <<'NODE'
const fs = require('fs');
const p = process.env.PKG;
const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
pkg.name = 'bentopdf-viewer';
pkg.dependencies = pkg.dependencies || {};
// The rollup bundle inlines every @embedpdf/* package, so these
// declared deps would only pull unused copies from upstream npm.
for (const k of Object.keys(pkg.dependencies)) {
if (k.startsWith('@embedpdf/')) delete pkg.dependencies[k];
if (k === 'preact') pkg.dependencies[k] = '^10.17.0';
}
fs.writeFileSync(p, JSON.stringify(pkg, null, 2) + '\n');
NODE
mkdir -p vendor/bentopdf-viewer
OUT="vendor/bentopdf-viewer/bentopdf-viewer-$SHA.tgz"
tar -czf "$OUT" -C "$TMP" package
find vendor/bentopdf-viewer -maxdepth 1 -name 'bentopdf-viewer-*.tgz' ! -name "$(basename "$OUT")" -delete
echo "tarball=$OUT" >> "$GITHUB_OUTPUT"
- name: Point dependencies at the new tarballs
if: steps.gate.outputs.run == 'true'
env:
ENGINE_TARBALL: ${{ steps.engine.outputs.tarball }}
VIEWER_TARBALL: ${{ steps.viewer.outputs.tarball }}
run: |
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.dependencies['bentopdf-pdfium'] = 'file:' + process.env.ENGINE_TARBALL;
pkg.dependencies['bentopdf-viewer'] = 'file:' + process.env.VIEWER_TARBALL;
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"
- name: Cleanup upstream clone
if: steps.gate.outputs.run == 'true'
run: rm -rf ./_fork
- name: Install and verify one shared engine
if: steps.gate.outputs.run == 'true'
run: |
set -euo pipefail
npm install
test -s node_modules/bentopdf-pdfium/editcore.wasm
if find node_modules/bentopdf-viewer -name '*.wasm' | grep -q .; then
echo "::error::viewer package still ships a wasm; the engine would be duplicated"
exit 1
fi
if ! grep -q "bentopdf-pdfium/editcore.wasm" src/js/logic/edit-pdf-page.ts; then
echo "::error::the PDF editor no longer points at the shared engine"
exit 1
fi
echo "engine sha256: $(sha256sum node_modules/bentopdf-pdfium/editcore.wasm | cut -c1-16)"
- name: Typecheck and test
if: steps.gate.outputs.run == 'true'
run: |
npx tsc --noEmit
npm run test:run
- name: Write upstream marker
if: steps.gate.outputs.run == 'true'
env:
SHA: ${{ steps.gate.outputs.version }}
run: |
echo "$SHA" > vendor/bentopdf-viewer/.upstream-version
echo "$SHA" > vendor/bentopdf-pdfium/.upstream-version
- name: Upload update
if: steps.gate.outputs.run == 'true'
uses: actions/upload-artifact@v4
with:
name: engine-update
include-hidden-files: true
retention-days: 1
path: |
package.json
package-lock.json
vendor/bentopdf-pdfium/
vendor/bentopdf-viewer/
pull-request:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.run == 'true'
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Download update
uses: actions/download-artifact@v4
with:
name: engine-update
path: ${{ runner.temp }}/engine-update
- name: Apply update
id: apply
env:
UPDATE: ${{ runner.temp }}/engine-update
run: |
set -euo pipefail
rm -rf vendor/bentopdf-pdfium vendor/bentopdf-viewer
mkdir -p vendor
cp -R "$UPDATE/vendor/bentopdf-pdfium" "$UPDATE/vendor/bentopdf-viewer" vendor/
cp "$UPDATE/package.json" "$UPDATE/package-lock.json" .
{
echo 'checksums<<EOF'
sha256sum vendor/bentopdf-pdfium/*.tgz vendor/bentopdf-viewer/*.tgz
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- name: Create Pull Request
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
with:
commit-message: 'build(deps): bump PDF engine and viewer to ${{ needs.build.outputs.version }}'
title: 'build(deps): bump PDF engine and viewer to ${{ needs.build.outputs.version }}'
body: |
Both vendored packages built from one clone of the viewer fork at
`${{ needs.build.outputs.version }}`, so the text editor and the
PDF editor run the same engine.
- `bentopdf-pdfium` — the engine wasm, packed from the fork's published `src/vendor`
- `bentopdf-viewer` — the snippet bundle, packed **without** `dist/pdfium.wasm`
The viewer loads the shared engine through `EmbedPDF.init({ wasmUrl })`.
CI verified a single wasm on disk, typecheck, and the test suite.
Built in a read-only job. Tarball checksums:
```
${{ steps.apply.outputs.checksums }}
```
branch: chore/update-pdf-engine
delete-branch: true