diff --git a/.github/workflows/build-pyqwest.yml b/.github/workflows/build-pyqwest.yml new file mode 100644 index 000000000..70779b8a8 --- /dev/null +++ b/.github/workflows/build-pyqwest.yml @@ -0,0 +1,138 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `linux` job of +# https://github.com/curioswitch/pyqwest/blob/v0.10.0/.github/workflows/release.yaml +name: Build pyqwest wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'pyqwest version to build (git tag without the leading v, e.g. 0.10.0)' + required: true + default: '0.10.0' + pull_request: + paths: + - '.github/workflows/build-pyqwest.yml' + +concurrency: + group: ${{ github.workflow }}-${{ inputs.version || '0.10.0' }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + # `inputs.version` is empty on pull_request events; default to 0.10.0 there. + PYQWEST_VERSION: ${{ inputs.version || '0.10.0' }} + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + + build_wheels: + needs: [setup] + name: Build pyqwest ${{ inputs.version || '0.10.0' }} ${{ matrix.tag }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 360 + strategy: + fail-fast: false + matrix: + include: + # pyo3/abi3-py310 is an opt-in feature upstream's own release job adds + # only on top of a `pyo3/extension-module`-only build (its second + # "Build abi3 wheels" step, `-i 3.10 --features pyo3/abi3-py310`); + # nothing in Cargo.toml turns it on by default. Built on cp310 -- + # the oldest interpreter the abi3 tag claims -- and re-tested on the + # newer ones via find_compatible_wheel. pyo3 disables abi3 under + # Py_GIL_DISABLED, so the free-threaded build is its own wheel. + - tag: cp310-abi3 + build: >- + cp310-manylinux_riscv64 cp311-manylinux_riscv64 + cp312-manylinux_riscv64 cp313-manylinux_riscv64 + cp314-manylinux_riscv64 + features: --features pyo3/extension-module --features pyo3/abi3-py310 + - tag: cp314t + build: cp314t-manylinux_riscv64 + features: --features pyo3/extension-module + + steps: + - name: Checkout pyqwest v${{ env.PYQWEST_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: curioswitch/pyqwest + ref: v${{ env.PYQWEST_VERSION }} + persist-credentials: false + + - name: Replace tests/conftest.py to drop the pyvoy-based local server + # The real conftest.py imports pyvoy unconditionally to run a local + # Envoy-based test server; pyvoy bundles Envoy and ships no riscv64 + # wheel anywhere. This keeps only the client_type fixture (copied + # verbatim) needed by the self-contained subset of tests below -- + # none of them open a socket or need a live server. + run: | + cat > tests/conftest.py <<'EOF' + from __future__ import annotations + + import pytest + + + @pytest.fixture(params=["async", "sync", "async_asgi", "sync_wsgi"]) + def client_type(request: pytest.FixtureRequest) -> str: + return request.param + EOF + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + output-dir: wheelhouse/ + env: + # musllinux is dropped: rustup.rs ships no riscv64 musl toolchain. + CIBW_BUILD: ${{ matrix.build }} + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + # pyqwest ships no [tool.cibuildwheel], so the Rust toolchain its + # maturin backend needs is installed in-container here. aws-lc-sys + # (pulled in by reqwest's rustls/http3 stack) ships prebuilt + # riscv64gc bindings, and cmake is already in the manylinux image. + CIBW_BEFORE_ALL_LINUX: >- + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + CIBW_ENVIRONMENT_LINUX: >- + PATH="$PATH:$HOME/.cargo/bin" + MATURIN_PEP517_ARGS="${{ matrix.features }}" + CIBW_TEST_REQUIRES: pytest pytest-asyncio pytest-benchmark + CIBW_TEST_SOURCES: >- + tests/__init__.py tests/_util.py tests/conftest.py + tests/test_common.py tests/test_multipart_encode.py + tests/test_protocol_errors.py tests/test_request.py + tests/test_response.py tests/test_timeout.py + tests/test_validation.py pyproject.toml + # The other test files need the pyvoy local server dropped above; + # this subset is the pyvoy-independent slice of upstream's own + # suite -- request/response/multipart construction, protocol-error + # framing over a raw socket (tests/_util.py's raw_server), TLS + # option validation and the sync timeout context manager. + CIBW_TEST_COMMAND: >- + python -c "import pyqwest._pyqwest as m; assert m.__file__.endswith('.so'), m.__file__" + && python -m pytest -v + tests/test_common.py tests/test_multipart_encode.py + tests/test_protocol_errors.py tests/test_request.py + tests/test_response.py tests/test_timeout.py + tests/test_validation.py + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pyqwest-${{ env.PYQWEST_VERSION }}-${{ matrix.tag }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish pyqwest ${{ inputs.version || '0.10.0' }} + needs: [setup, build_wheels] + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + with: + artifact-pattern: pyqwest-${{ inputs.version || '0.10.0' }}-*-manylinux_riscv64