Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 75 additions & 7 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
name: Upload Package
name: Build and upload package

on:
pull_request:
release:
types: [published]
workflow_dispatch:

permissions:
contents: read

jobs:
release-build:
build-sdist:
name: Build source distribution
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand All @@ -20,15 +23,80 @@ jobs:
- name: Prepare environment
uses: ./.github/actions/prepare

- name: Build release distributions
run: |
uv build -v --sdist
- name: Build source distribution
run: uv build -v --sdist

- name: Check source distribution
run: uv run twine check dist/*

- name: Upload source distribution
uses: actions/upload-artifact@v4
with:
name: distribution-sdist
path: dist/*.tar.gz
if-no-files-found: error

build-wheel:
name: Build ${{ matrix.build }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
build:
- cp312-manylinux_x86_64
- cp313-manylinux_x86_64
- cp312-musllinux_x86_64
- cp313-musllinux_x86_64
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
submodules: recursive

- name: Build and test wheel
uses: pypa/cibuildwheel@v3.4.1
with:
package-dir: .
output-dir: wheelhouse
env:
CIBW_BUILD: ${{ matrix.build }}
CIBW_BUILD_VERBOSITY: "1"
CIBW_TEST_COMMAND: python {project}/scripts/verify_wheel.py

- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: distribution-${{ matrix.build }}
path: wheelhouse/*.whl
if-no-files-found: error

publish:
name: Upload distributions to PyPI
if: github.event_name == 'release'
needs: [build-sdist, build-wheel]
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
submodules: recursive

- name: Prepare environment
uses: ./.github/actions/prepare

- name: Download distributions
uses: actions/download-artifact@v4
with:
pattern: distribution-*
path: dist
merge-multiple: true

# TODO: switch to PyPI Trusted Publishing (OIDC) and drop the token:
# https://docs.pypi.org/trusted-publishers/
- name: Upload distributions
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: |
uv run twine upload --verbose --repository pypi dist/*
run: uv run twine upload --verbose --repository pypi dist/*
43 changes: 43 additions & 0 deletions scripts/verify_wheel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Verify that an installed wheel is self-contained and importable."""

from importlib import import_module
from pathlib import Path
import shutil
import subprocess


EXTENSION_MODULES = (
"uringloop._liburing",
"uringloop._uringcore_liburing",
)


def dynamic_section(module_name: str) -> str:
module = import_module(module_name)
module_file = getattr(module, "__file__", None)
if module_file is None:
raise RuntimeError(f"{module_name} does not have an extension module path")

readelf = shutil.which("readelf")
if readelf is None:
raise RuntimeError("readelf is required to verify wheel dependencies")

result = subprocess.run(
[readelf, "-d", Path(module_file)],
check=True,
capture_output=True,
text=True,
)
return result.stdout


def main() -> None:
for module_name in EXTENSION_MODULES:
dependencies = dynamic_section(module_name)
if "liburing.so" in dependencies:
raise RuntimeError(f"{module_name} dynamically links liburing")
print(f"verified {module_name}")


if __name__ == "__main__":
main()
Loading