Skip to content

chore(deps): bump actions/download-artifact from 7 to 8 #7

chore(deps): bump actions/download-artifact from 7 to 8

chore(deps): bump actions/download-artifact from 7 to 8 #7

Workflow file for this run

name: Build wheels (cibuildwheel — Rust Phase 2)
# Phase-2 gate for the Rust HDFE kernel spike.
#
# The Rust HDFE crate lives under `rust/statspai_hdfe/` and its
# `Cargo.toml` IS present on `main`. But cibuildwheel can only emit a
# platform wheel when the project's PEP 517 build-backend is maturin,
# so the PyO3 extension gets compiled into the wheel. Today
# `pyproject.toml` uses `setuptools.build_meta` (no `[tool.maturin]`),
# which yields a pure-Python `py3-none-any` wheel that cibuildwheel
# rejects with exit 5 (NonPlatformWheelError). The `check_rust_present`
# guard below therefore gates on the maturin backend — NOT on Cargo.toml
# presence — so this workflow stays INERT until the native wheel
# pipeline is actually wired. When a PR switches the build-backend to
# maturin, the guard opens and the cibuildwheel matrix runs.
#
# Matrix coverage mirrors the contract in `rust/README.md`:
# - macOS arm64 (macos-14) + x86_64 (macos-13)
# - manylinux_2_17 x86_64 + aarch64
# - musllinux_1_2 x86_64
# - Windows x86_64
#
# Security note: this workflow only reads `matrix.*` and `inputs.*`
# (both defined in this file, not user-controlled), and does not
# interpolate any `github.event.*` strings into `run:` blocks — so
# the GitHub Actions command-injection vectors do not apply.
on:
push:
branches:
- 'feat/rust-hdfe'
- 'feat/rust-phase2'
pull_request:
paths:
- 'rust/**'
- '.github/workflows/build-wheels.yml'
- 'pyproject.toml'
workflow_dispatch:
inputs:
publish_testpypi:
description: 'Upload wheels to TestPyPI after build'
type: boolean
default: false
# Opt into Node 24 runtime for JavaScript actions. GitHub's documented
# migration path (2025-09-19 changelog) ahead of the 2026-06-02 hard
# cutover. Preserves current action versions. No user input interpolated.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
jobs:
check_rust_present:
name: Detect Rust crate
runs-on: ubuntu-latest
outputs:
has_rust: ${{ steps.detect.outputs.has_rust }}
steps:
- uses: actions/checkout@v5
- id: detect
name: Detect a maturin (PyO3) build backend
run: |
# cibuildwheel can only build a platform wheel when the PEP 517
# backend is maturin (so the Rust extension is compiled in).
# Gate on that — Cargo.toml presence alone is NOT sufficient:
# with the setuptools backend a pure-Python wheel is produced
# and cibuildwheel exits 5 (NonPlatformWheelError). This keeps
# the workflow inert until the native build is really wired,
# while still re-triggering (via the pyproject.toml path filter)
# the moment a PR adopts the maturin backend.
if grep -Eq '^[[:space:]]*build-backend[[:space:]]*=[[:space:]]*"maturin' pyproject.toml \
&& [ -f rust/statspai_hdfe/Cargo.toml ]; then
echo "has_rust=true" >> "$GITHUB_OUTPUT"
echo "maturin backend + Rust crate present — cibuildwheel matrix will run."
else
echo "has_rust=false" >> "$GITHUB_OUTPUT"
echo "No maturin build-backend on this ref — wheel jobs skip (pure-Python build)."
fi
build_wheels:
name: Build wheels (${{ matrix.os }} / ${{ matrix.arch }})
needs: check_rust_present
if: needs.check_rust_present.outputs.has_rust == 'true'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux — manylinux_2_17 covers Python >=3.9 on most distros;
# musllinux covers Alpine/containers where glibc is absent.
- os: ubuntu-latest
arch: x86_64
cibw_build: "cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 cp313-manylinux_x86_64 cp39-musllinux_x86_64 cp310-musllinux_x86_64 cp311-musllinux_x86_64 cp312-musllinux_x86_64 cp313-musllinux_x86_64"
- os: ubuntu-latest
arch: aarch64
cibw_build: "cp39-manylinux_aarch64 cp310-manylinux_aarch64 cp311-manylinux_aarch64 cp312-manylinux_aarch64 cp313-manylinux_aarch64"
# macOS split — macos-13 runs x86_64 natively; macos-14 is
# Apple-silicon and only builds arm64 wheels.
- os: macos-13
arch: x86_64
cibw_build: "cp39-macosx_x86_64 cp310-macosx_x86_64 cp311-macosx_x86_64 cp312-macosx_x86_64 cp313-macosx_x86_64"
- os: macos-14
arch: arm64
cibw_build: "cp39-macosx_arm64 cp310-macosx_arm64 cp311-macosx_arm64 cp312-macosx_arm64 cp313-macosx_arm64"
# Windows — x86_64 only.
- os: windows-latest
arch: AMD64
cibw_build: "cp39-win_amd64 cp310-win_amd64 cp311-win_amd64 cp312-win_amd64 cp313-win_amd64"
env:
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_SKIP: "*-win32 *-manylinux_i686 pp*"
CIBW_BEFORE_BUILD_LINUX: "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal && source $HOME/.cargo/env && pip install maturin"
CIBW_BEFORE_BUILD_MACOS: "rustup target add aarch64-apple-darwin x86_64-apple-darwin && pip install maturin"
CIBW_BEFORE_BUILD_WINDOWS: "pip install maturin"
CIBW_TEST_REQUIRES: "pytest numpy pandas numba"
CIBW_TEST_COMMAND: >
python -c "import statspai; assert statspai.__version__"
&& pytest {project}/tests/test_fast_demean.py {project}/tests/test_hdfe_native.py -x -q
CIBW_ARCHS_LINUX: ${{ matrix.arch }}
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Enable QEMU for aarch64 (linux only)
if: matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64'
uses: docker/setup-qemu-action@v4
with:
platforms: arm64
- name: Install cibuildwheel
run: python -m pip install --upgrade pip cibuildwheel==2.21.3
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
- name: Upload artifact
uses: actions/upload-artifact@v6
with:
name: wheels-${{ matrix.os }}-${{ matrix.arch }}
path: ./wheelhouse/*.whl
build_sdist:
name: Build sdist
needs: check_rust_present
if: needs.check_rust_present.outputs.has_rust == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Build sdist
run: |
python -m pip install --upgrade pip build
python -m build --sdist
- uses: actions/upload-artifact@v6
with:
name: sdist
path: ./dist/*.tar.gz
publish_testpypi:
name: Upload to TestPyPI (opt-in)
needs: [build_wheels, build_sdist]
if: |
github.event_name == 'workflow_dispatch' &&
inputs.publish_testpypi == true
runs-on: ubuntu-latest
environment: testpypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: dist/
skip-existing: true