Skip to content
Merged
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
172 changes: 172 additions & 0 deletions .github/workflows/build-stream-unzip.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/uktrade/stream-unzip/blob/v0.0.101/.github/workflows/build-source-package-and-wheels.yml
name: Build stream-unzip wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'stream-unzip version to build (git tag without leading v, e.g. 0.0.101)'
required: true
default: '0.0.101'
pull_request:
paths:
- '.github/workflows/build-stream-unzip.yml'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '0.0.101' }}-${{ 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.0.101 there.
STREAM_UNZIP_VERSION: ${{ inputs.version || '0.0.101' }}
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
setup:
uses: $/.github/workflows/_setup.yml

python_sdist:
needs: [setup]
runs-on: ubuntu-latest
outputs:
sdist_artifact_name: ${{ steps.build_sdist.outputs.sdist_artifact_name }}
package_version: ${{ steps.build_sdist.outputs.package_version }}
steps:
- name: Checkout stream-unzip v${{ env.STREAM_UNZIP_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: uktrade/stream-unzip
ref: v${{ env.STREAM_UNZIP_VERSION }}
persist-credentials: false

- name: Install Python
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: '3.12'
activate-environment: true
enable-cache: false

- name: Update version placeholder and build sdist
id: build_sdist
run: |
set -euo pipefail
rm -rf dist

# Upstream's own release CI does this same sed on tag push (see
# build-source-package-and-wheels.yml); the checked-out pyproject.toml
# still carries the 0.0.0.dev0 placeholder.
sed -i "s/0\\.0\\.0\\.dev0/${STREAM_UNZIP_VERSION}/g" pyproject.toml

uv pip install 'maturin>=1.7.4,<2.0.0' build
python -m build --sdist --outdir dist

sdist_name="$(ls dist)"
{
echo "sdist_artifact_name=${sdist_name}"
echo "package_version=$(echo "${sdist_name}" | sed -En 's/stream_unzip-(.+)\.tar\.gz/\1/p')"
} >> "$GITHUB_OUTPUT"

- name: Upload sdist artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ steps.build_sdist.outputs.sdist_artifact_name }}
path: dist/${{ steps.build_sdist.outputs.sdist_artifact_name }}
if-no-files-found: error

build_wheels:
needs: [setup, python_sdist]
name: Build stream-unzip ${{ inputs.version || '0.0.101' }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
# stream-unzip's _zipcrypto extension is a PyO3 module built per-interpreter
# (not abi3 - upstream ships cp3x-cp3x wheels), so every Python version needs
# its own build. Repo-standard riscv64 target set. Upstream doesn't build a
# 3.14t wheel yet, so skip it for now.
python: ["cp312", "cp313", "cp314"]

steps:
- name: Fetch sdist artifact
id: fetch_sdist
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.python_sdist.outputs.sdist_artifact_name }}

- name: Install uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: '3.12'
activate-environment: true
enable-cache: false

- name: Build and test wheel
env:
CIBW_ARCHS: riscv64
# Only manylinux: rustup.rs ships no riscv64 musl host toolchain, so
# musllinux can't build (same reason build-tiktoken.yml/build-fastuuid.yml
# skip it).
CIBW_BUILD: ${{ matrix.python }}-manylinux_riscv64
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# stream-unzip ships no [tool.cibuildwheel], so the Rust toolchain its
# maturin backend needs is installed in-container here, and Cython (a
# transitive build dependency of its stream-inflate runtime dependency,
# which has no riscv64 wheel yet) is resolved from our own registry.
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"
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
# Test each wheel the way upstream does - run its test suite (via pytest,
# which can also collect a plain unittest.TestCase, so upstream's suite
# runs unmodified). trio is an upstream ci-extra dev dependency used by
# one async test; pycryptodome and stream-inflate are pulled in
# automatically as the wheel's own runtime dependencies (pycryptodome
# already ships a riscv64 wheel on our registry; stream-inflate doesn't
# yet, so pip builds it from its public sdist using the Cython wheel
# above). Tests and fixtures live at the sdist root, not inside the
# importable package, so reference them via {package} (=
# /project/stream-unzip), NOT {project} - see gotcha 5.
#
# test_bad_deflate_data is deselected: it corrupts one byte of a raw
# DEFLATE stream and asserts zlib.decompressobj raises (mapped to
# DeflateError). manylinux_2_39_riscv64 has no dedicated zlib build step
# (unlike e.g. openssl/sqlite3) and links CPython's zlib module against
# the image's system zlib-ng-compat instead, which decodes this
# particular corrupted stream without raising - the corruption then only
# surfaces once the decompressed bytes fail the trailing CRC-32 check, as
# CRC32IntegrityError. Same underlying image behavior as gotchas 272/279.
CIBW_TEST_REQUIRES: pytest trio
CIBW_TEST_COMMAND: >-
cd {package} &&
python -m pytest -v test.py --deselect test.py::TestStreamUnzip::test_bad_deflate_data
run: |
set -euo pipefail
mkdir stream-unzip
tar zxf "${{ steps.fetch_sdist.outputs.download-path }}/${{ needs.python_sdist.outputs.sdist_artifact_name }}" \
--strip-components=1 -C stream-unzip
uv pip install --upgrade cibuildwheel
python -m cibuildwheel --output-dir wheelhouse ./stream-unzip

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: stream-unzip-${{ env.STREAM_UNZIP_VERSION }}-${{ matrix.python }}-manylinux_riscv64
path: ./wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish stream-unzip ${{ inputs.version || '0.0.101' }}
needs: [setup, build_wheels]
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
with:
artifact-pattern: stream-unzip-${{ inputs.version || '0.0.101' }}-*-manylinux_riscv64