Skip to content

Main packaging

Main packaging #182

Workflow file for this run

# SPDX-FileCopyrightText: 2026 geisserml <geisserml@gmail.com>
# SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
# Maintainer's note: This workflow is registered for trusted publishing on pypdfium2's PyPI page, by filename. So if this file shall be renamed, remember to update the filename in PyPI settings as well.
name: Main packaging
on:
workflow_dispatch:
inputs:
test:
default: true
type: boolean
augment:
default: false
type: boolean
publish:
default: false
type: boolean
conda:
default: false
type: boolean
py_version:
default: '3.12'
type: string
runner:
default: 'ubuntu-latest'
type: string
defaults:
run:
shell: bash
jobs:
build:
runs-on: ${{ inputs.runner }}
outputs:
new_version: ${{ steps.get_version.outputs.new_version }}
steps:
- uses: extractions/setup-just@v4
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.py_version }}
- name: Check out repository
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
fetch-depth: 0 # for git describe in "Get new version" step
persist-credentials: true # needed for push
- name: Install/update dependencies
run: python3 -m pip install -U -r req/setup.txt -r req/test.txt -r req/utilities.txt
# NOTE autorelease sets a tag, but it's just temporary for informational purpose and does not match the actually published tag
# We can't push the tag at this stage because we don't know the outcome of the following jobs yet
# In the future, we might want to move away from using a git branch & tag at this stage, and instead transfer the changes as a patchfile.
- name: Run autorelease script
run: |
git config user.email "geisserml@gmail.com"
git config user.name "geisserml"
git reset --hard HEAD
# autorelease.py --register automatically switches us onto the autorelease_tmp branch
python3 setupsrc/autorelease.py --register
- name: Get new version
id: get_version
run: echo "new_version=$(git describe --abbrev=0)" >> $GITHUB_OUTPUT
- name: Install pypdfium2
run: python3 -m pip install -v --no-build-isolation -e .
- name: Run test suite
run: python3 -m pytest tests/
# TODO make controllable whether musllinux packages are built through pdfium-binaries or cibw augmentation, consider enabling them here if inputs.augment is false
- name: Run PyPI packaging script
run: just packaging-pypi
env:
# only passed to craft.py, which uses a GH REST API that can hit rate limits otherwise
GH_TOKEN: ${{ github.token }}
- name: Upload release notes
uses: actions/upload-artifact@v7
with:
name: release_notes
path: RELEASE.md
# https://github.com/actions/upload-artifact/issues/331 ...
- name: Upload packages
uses: actions/upload-artifact@v7
with:
name: packages
path: dist/*
# tag deliberately not pushed (see above)
- name: Push autorelease_tmp branch
run: git push -u origin autorelease_tmp
test:
if: ${{ inputs.test }}
needs: build
strategy:
fail-fast: false
matrix:
os: ['ubuntu-latest', 'ubuntu-24.04-arm', 'macos-15-intel', 'macos-latest', 'windows-latest', 'windows-11-arm']
py: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
exclude:
# not supported by setup-python action
- os: windows-11-arm
py: '3.8'
- os: windows-11-arm
py: '3.9'
- os: windows-11-arm
py: '3.10'
include:
- os: ubuntu-latest
wheel: dist/*manylinux_*_x86_64*.whl
- os: ubuntu-24.04-arm
wheel: dist/*manylinux_*_aarch64*.whl
- os: macos-15-intel
wheel: dist/*macosx_*_x86_64*.whl
- os: macos-latest
wheel: dist/*macosx_*_arm64*.whl
- os: windows-latest
wheel: dist/*win_amd64.whl
- os: windows-11-arm
wheel: dist/*win_arm64.whl
runs-on: ${{ matrix.os }}
steps:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.py }}
- name: Check out repository
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
ref: autorelease_tmp
persist-credentials: false
- name: Download packages
uses: actions/download-artifact@v8
with:
name: packages
path: dist/
- name: Install dependencies
run: |
python3 -m pip install -U pip setuptools
python3 -m pip install -U pytest pillow numpy
- name: Install and run auditwheel (informational)
if: ${{ startsWith(matrix.os, 'ubuntu') }}
run: |
python3 -m pip install -U auditwheel
python3 -m auditwheel show $WHEEL
env:
WHEEL: ${{ matrix.wheel }}
- name: Install pypdfium2 from artifact
run: python3 -m pip install $WHEEL
env:
WHEEL: ${{ matrix.wheel }}
- name: Run Test Suite
run: python3 -m pytest tests/
augment_cibw:
if: ${{ inputs.augment }}
needs: build
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
cibw_class: musllinux
cibw_arch: x86_64
- os: ubuntu-latest
cibw_class: musllinux
cibw_arch: i686
- os: ubuntu-24.04-arm
cibw_class: musllinux
cibw_arch: aarch64
- os: ubuntu-24.04-arm
cibw_class: musllinux
cibw_arch: armv7l
- os: ubuntu-latest
cibw_class: musllinux
cibw_arch: ppc64le
- os: ubuntu-latest
cibw_class: manylinux
cibw_arch: riscv64
- os: ubuntu-latest
cibw_class: musllinux
cibw_arch: riscv64
- os: ubuntu-latest
cibw_class: manylinux
cibw_arch: loongarch64
- os: ubuntu-latest
cibw_class: musllinux
cibw_arch: loongarch64
- os: ubuntu-latest
cibw_class: manylinux
cibw_arch: s390x
- os: ubuntu-latest
cibw_class: musllinux
cibw_arch: s390x
uses: ./.github/workflows/cibw_one.yaml
with:
os: ${{ matrix.os }}
cibw_target: ${{ matrix.cibw_class }}_${{ matrix.cibw_arch }}
cibw_arch: ${{ matrix.cibw_arch }}
repo_tag: ${{ needs.build.outputs.new_version }}
branch: autorelease_tmp
test_pdfium: true
# # NOTE ppc64le is now supported with pdfium-binaries, commented out. However, this strategy might be useful for other platforms in the future.
# augment_sbuild:
#
# if: ${{ inputs.augment }}
# needs: build
#
# strategy:
# fail-fast: false
# matrix:
# include:
# - os: ubuntu-latest
# target_cpu: ppc64le
# tag: manylinux_2_17_ppc64le.manylinux2014_ppc64le
#
# uses: ./.github/workflows/sbuild_one.yaml
# with:
# os: ${{ matrix.os }}
# target_cpu: ${{ matrix.target_cpu }}
# tag: ${{ matrix.tag }}
# py_version: ${{ inputs.py_version }}
# repo_tag: ${{ needs.build.outputs.new_version }}
# branch: autorelease_tmp
publish:
needs:
- build
- test
- augment_cibw
# - augment_sbuild
if: ${{ inputs.publish && !cancelled() && !contains(needs.*.result, 'failure') }}
runs-on: ${{ inputs.runner }}
environment: release # PyPI upload via "trusted publishing"
permissions:
id-token: write # PyPI upload via "trusted publishing", and GH attestation
attestations: write # GH attestation
contents: write # autorelease repository changes
actions: write # GH pages workflow-dispatch
steps:
- name: Check out repository (deep)
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
fetch-depth: 0
persist-credentials: true # needed for push
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.py_version }}
- name: Download release notes
uses: actions/download-artifact@v8
with:
name: release_notes
- name: Download main packages
uses: actions/download-artifact@v8
with:
path: dist/
name: packages
- name: Download extra packages (cibw)
uses: actions/download-artifact@v8
with:
path: dist/
merge-multiple: true
pattern: cibw-*
# - name: Download extra packages (sbuild)
# uses: actions/download-artifact@v8
# with:
# path: dist/
# merge-multiple: true
# pattern: sbuild_*
- name: Isolate non-PyPI builds
if: ${{ inputs.augment }}
run: |
mkdir gh_only
mv dist/*linux_*_loongarch64*.whl gh_only/
- name: Apply and push repository changes
run: |
git config user.email "geisserml@gmail.com"
git config user.name "geisserml"
git checkout main
git merge origin/autorelease_tmp
git tag -a "$NEW_VERSION" -m "Autorelease"
git push
git push --tags
git checkout stable
git reset --hard main
git push --force
git checkout main
env:
NEW_VERSION: ${{ needs.build.outputs.new_version }}
# Upload to TestPyPI / PyPI via "trusted publishing".
# https://docs.pypi.org/trusted-publishers/adding-a-publisher/
# https://docs.pypi.org/trusted-publishers/using-a-publisher/
# https://github.com/pypa/gh-action-pypi-publish
- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: dist/ # the default
# https://github.com/pypa/gh-action-pypi-publish/issues/283#issuecomment-2499296440
attestations: false
verbose: true
- name: Attest build provenance
id: provenance
uses: actions/attest-build-provenance@v4
with:
subject-path: 'dist/*, gh_only/*'
- name: Rename provenance file
run: mv "$SRC_PATH" pypdfium2-attestation.json
env:
SRC_PATH: ${{ steps.provenance.outputs.bundle-path }}
# FIXME skip gh_only/*.whl if !inputs.augment
- name: Publish to GitHub
uses: ncipollo/release-action@v1
with:
immutableCreate: true
artifacts: 'dist/*.whl,gh_only/*.whl,dist/*.tar.gz,pypdfium2-attestation.json'
bodyFile: 'RELEASE.md'
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ needs.build.outputs.new_version }}
prerelease: ${{ contains(needs.build.outputs.new_version, 'b') }}
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/ # the default
- name: Trigger GH Pages rebuild
uses: benc-uk/workflow-dispatch@v1
with:
workflow: gh_pages.yaml # takes no inputs
conda_trigger:
needs: publish # i.e. goes after, regardless if publish is active or not
if: ${{ inputs.conda && !cancelled() && !contains(needs.*.result, 'failure') }}
runs-on: ${{ inputs.runner }}
steps:
- name: Trigger conda pypdfium2_helpers build
uses: benc-uk/workflow-dispatch@v1
with:
workflow: conda.yaml
inputs: |
{
"package": "helpers",
"pdfium_ver": "latest",
"new_only": "false",
"test": "true",
"publish": "${{ inputs.publish }}",
"py_version": "${{ inputs.py_version }}"
}
cleanup:
needs: [publish, conda_trigger]
if: ${{ !cancelled() }}
runs-on: ${{ inputs.runner }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
persist-credentials: true # needed for push
- name: Remove temporary branch
run: git push origin --delete autorelease_tmp