Skip to content
Draft
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
163 changes: 163 additions & 0 deletions .github/workflows/build-opendp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# Based on upstream's own release pipeline:
# https://github.com/opendp/opendp/blob/v0.16.0/.github/workflows/.build.yml
# opendp is a Rust library exposed to Python as a plain cdylib (setuptools-rust,
# binding=NoBinding - no CPython linkage at all), so its own CI generates the
# Python glue code once (the "bindings" feature, architecture-independent) and
# then compiles the cdylib per platform. Upstream splits those two steps across
# separate runners only to share the glue code across its many OS/arch jobs;
# here they run as the two jobs below, narrowed to riscv64.
name: Build opendp wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/opendp.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-opendp.yml'
- 'docs/packages/opendp.yaml'
push:
branches: [main]
paths:
- '.github/workflows/build-opendp.yml'
- 'docs/packages/opendp.yaml'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
# Hardcoded in opendp's own setup.py RustExtension(features=[...]); the
# bindings-generation step below must use the same set so the generated
# Python glue matches what the compiled cdylib actually exports.
FEATURES: untrusted,polars-ffi

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: opendp
version: ${{ inputs.version }}

build_sdist:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build opendp ${{ matrix.version }} sdist
runs-on: ubuntu-latest
env:
OPENDP_VERSION: ${{ matrix.version }}

steps:
- name: Checkout opendp v${{ env.OPENDP_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: opendp/opendp
ref: v${{ env.OPENDP_VERSION }}
persist-credentials: false

- name: Install Rust
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --profile minimal -y

- name: Generate Python bindings
run: |
set -euo pipefail
source "$HOME/.cargo/env"
bash tools/rust_build.sh -r -n -f "${FEATURES},bindings"

- name: Stage Python source distribution
run: bash tools/python_stage.sh -s

- name: Build sdist
run: |
set -euo pipefail
python3 -m pip install --user build
python3 -m build python/. --sdist --outdir dist

- name: Upload sdist artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: opendp-${{ env.OPENDP_VERSION }}-sdist
path: dist/*.tar.gz
if-no-files-found: error

build_wheels:
needs: [setup, build_sdist]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build opendp ${{ matrix.version }} manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 240
env:
OPENDP_VERSION: ${{ matrix.version }}

steps:
- name: Download sdist
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: opendp-${{ env.OPENDP_VERSION }}-sdist
path: dist/

- id: sdist_path
run: echo "path=$(echo dist/*.tar.gz)" >> "$GITHUB_OUTPUT"

# One cp3xx-abi3 wheel (setup.cfg's [bdist_wheel] py_limited_api, since the
# cdylib has no CPython linkage at all - see the file header); cibuildwheel
# builds it once and reuses it across the other selectors.
- name: Build and test wheel
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
package-dir: ${{ steps.sdist_path.outputs.path }}
env:
CIBW_ARCHS: riscv64
CIBW_BUILD: 'cp312-* cp313-* cp314-*'
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# No Rust in the manylinux image; default features pull in a vendored
# OpenSSL build (openssl-src), which needs perl + a C compiler, and
# riscv64's atomics need libatomic explicitly (same packages upstream's
# own CIBW_BEFORE_BUILD_LINUX installs for this exact reason).
CIBW_BEFORE_ALL_LINUX: >-
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --profile minimal -y &&
dnf install -y perl-core openssl-devel pkgconfig libatomic
CIBW_ENVIRONMENT: 'PATH="$PATH:$HOME/.cargo/bin"'
CIBW_TEST_COMMAND: python -c "import opendp"

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

publish:
name: Publish opendp ${{ matrix.version }}
needs: [setup, build_sdist, build_wheels]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
secrets:
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
with:
artifact-pattern: opendp-${{ matrix.version }}-manylinux_riscv64
5 changes: 5 additions & 0 deletions docs/packages/opendp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package-name: opendp
source-code: https://github.com/opendp/opendp
license: MIT
versions:
- version: 0.16.0
Loading