Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4c1228e
Pin componentize-py git dependency to resolved commit SHA
posborne May 27, 2026
d19f618
Add release workflow for multi-platform binary wheels
posborne May 27, 2026
5d3ca26
Switch to abi3 wheels (CPython 3.12+)
posborne May 27, 2026
52b7fc6
Fix .gitignore gaps for __pycache__ and macOS debug symbols
posborne May 27, 2026
2cceed2
Extend check_version_sync.py to validate against a release tag
posborne May 27, 2026
6bab6bb
Add version consistency gate to release workflow
posborne May 27, 2026
3b92225
Add release process documentation to CONTRIBUTING.md
posborne May 27, 2026
950080c
Factor toolchain versions into workflow-level env vars
posborne May 27, 2026
49e0aaf
Extract shared Rust toolchain setup into a composite action
posborne May 27, 2026
54a5759
Incorporate some bits from componentize-py CI
posborne May 27, 2026
9279655
Upgrade actions/checkout from v4 to v6
posborne May 27, 2026
dd1d715
Fix failures from first pass of release CI
posborne May 27, 2026
a4c046b
Add wasm-tools/wac-cli to containers for release and pin
posborne May 27, 2026
b195a87
Fix wasm-tools install in release workflow
posborne May 27, 2026
f54dec8
Fix arm64 macOS wasm-tools download; disable macos-13 runner
posborne May 28, 2026
58a81c2
Update macOS runners to macos-26/macos-26-intel
posborne May 28, 2026
0953502
Tighten up the release docs in CONTRIBUTING.md
posborne May 28, 2026
185fcdf
`make format`
posborne May 28, 2026
c45cb6c
Add sdist alongside wheels
posborne May 28, 2026
6b324be
Drop make targets for checks, just do with lint
posborne May 28, 2026
ad25b7f
release: drop source/binary caches
posborne May 28, 2026
42ce28d
release: remove confusing/unecessary language related to nightly tool…
posborne May 28, 2026
798847e
release: include sdist in checksums, unify artifact collection
posborne May 28, 2026
0a64f91
Remove wasm-tools shell calls from build.rs
posborne May 28, 2026
cc0d9c6
Script installing pinned nightly with caching, remove wasm-tools/wac-cli
posborne May 28, 2026
d05b79c
Add back wasm-tools to main ci workflow
posborne May 28, 2026
c6654b4
Test nightly install differently
posborne May 29, 2026
00be019
release: target MACOSX_DEPLOYMENT_TARGET 10.15 for x86_64
posborne May 29, 2026
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
35 changes: 35 additions & 0 deletions .github/actions/setup-rust/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: "Setup Rust toolchains"
description: >
Installs the pinned stable and nightly Rust toolchains required by this
project. See .github/scripts/setup-nightly.sh for details on why nightly
is required.

inputs:
rust-stable:
description: "Stable toolchain version"
default: "1.92.0"
rust-nightly:
description: "Nightly toolchain date (e.g. nightly-2026-04-27)"
default: "nightly-2026-04-27"

runs:
using: "composite"
steps:
- name: Set up stable Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ inputs.rust-stable }}
target: wasm32-unknown-unknown
components: rustfmt,clippy
# Disable the built-in cargo cache -- callers manage their own.
cache: false

- name: Cache nightly toolchain
uses: actions/cache@v4
with:
path: ~/.rustup/toolchains/nightly-*
key: rustup-nightly-${{ runner.os }}-${{ inputs.rust-nightly }}-v1

- name: Set up nightly Rust toolchain
shell: bash
run: .github/scripts/setup-nightly.sh ${{ inputs.rust-nightly }}
30 changes: 30 additions & 0 deletions .github/scripts/setup-nightly.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Install the nightly Rust toolchain required to build this project.
#
# componentize-py's build.rs uses -Z build-std (nightly-only) to compile its
# wasm32-wasip1 runtime. It also invokes `rustup run nightly cargo build` by
# name, so both the pinned dated nightly and the bare 'nightly' channel must
# be installed; rustup rejects 'nightly' as a toolchain link target.
#
# Both installs are skipped if already present (e.g. restored from cache).
#
# Usage: setup-nightly.sh <nightly-date>
# e.g. setup-nightly.sh nightly-2026-04-27

set -euo pipefail

RUST_NIGHTLY="${1:?Usage: $0 <nightly-date>}"

if ! rustup toolchain list | grep -q "^${RUST_NIGHTLY}"; then
rustup toolchain install "$RUST_NIGHTLY" --component rust-src
rustup target add wasm32-wasip1 --toolchain "$RUST_NIGHTLY"
else
echo "Nightly toolchain $RUST_NIGHTLY already installed (cache hit)"
fi

if ! rustup run nightly rustc --version &>/dev/null; then
rustup toolchain install nightly --component rust-src
rustup target add wasm32-wasip1 --toolchain nightly
else
echo "Bare nightly toolchain already installed (cache hit)"
fi
36 changes: 17 additions & 19 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,46 @@ on:
branches:
- main
pull_request:
workflow_dispatch: # Allows manual triggering from GitHub Actions UI
workflow_dispatch: # allow manual triggering

# Cancel in-progress runs for the same branch/PR when a new push arrives.
# Omitted from release.yml — you never want to cancel an in-progress release.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Comment thread
posborne marked this conversation as resolved.

env:
VICEROY_TAG: v0.16.4
WASM_TOOLS_VERSION: "1.250.0"

jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Set up Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.92.0
target: wasm32-unknown-unknown
components: rustfmt, clippy
# Disable the built-in cargo cache - we use our own below
cache: false
- name: Set up nightly Rust toolchain with rust-src
run: |
rustup toolchain install nightly --component rust-src
rustup target add wasm32-wasip1 --toolchain nightly
- uses: actions/checkout@v6
- name: Set up Rust toolchains
uses: ./.github/actions/setup-rust
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
run: pip install uv

# Cache cargo binaries (viceroy, wasm-tools, etc.)
# Cache cargo binaries (viceroy, wasm-tools).
# wasm-tools is required by scripts/generate_patches, which runs as part
# of make lint to verify patches.py is up to date with the WIT sources.
- name: Cache cargo binaries
id: cache-cargo-bins
uses: actions/cache@v4
with:
key: cargo-bins-${{ runner.os }}-${{ env.VICEROY_TAG }}
key: cargo-bins-${{ runner.os }}-${{ env.VICEROY_TAG }}-wasm-tools-${{ env.WASM_TOOLS_VERSION }}
path: |
~/.cargo/bin/viceroy*
~/.cargo/bin/wasm-tools*
~/.cargo/bin/wac*
- name: Install wasm-tools and wac
- name: Install wasm-tools
if: steps.cache-cargo-bins.outputs.cache-hit != 'true'
run: cargo install wasm-tools wac-cli
run: cargo install wasm-tools --version ${{ env.WASM_TOOLS_VERSION }} --locked
- name: Install viceroy
if: steps.cache-cargo-bins.outputs.cache-hit != 'true'
run: cargo install --git https://github.com/fastly/Viceroy.git --tag "$VICEROY_TAG" viceroy
Expand Down
238 changes: 238 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
name: Release

# Triggers:
# - Push a version tag (e.g. git tag v0.1.0 && git push --tags) for a real release.
# - workflow_dispatch for ad-hoc test builds without creating a tag.
# Wheels are uploaded as GitHub Actions artifacts and no GitHub Release is created.
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Version label for artifacts (e.g. v0.1.0-test)"
required: true
default: "v0.0.0-dev"

# Minimal permissions by default; create-github-release job adds write where needed.
permissions:
contents: read

env:
# Bump these in one place when upgrading toolchains or maturin.
# RUST_STABLE and RUST_NIGHTLY must also be kept in sync with the defaults
# in .github/actions/setup-rust/action.yml.
PYTHON_VERSION: "3.12"
RUST_STABLE: "1.92.0"
RUST_NIGHTLY: "nightly-2026-04-27"
MATURIN_VERSION: "v1.13.3"

jobs:
# Verify that the versions in pyproject.toml and Cargo.toml match the tag
# (or the manually-supplied version label) before spending time on builds.
check-version:
name: "Check version consistency"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Verify versions match
run: |
python scripts/check_version_sync.py --tag "${{ github.event_name == 'workflow_dispatch' && inputs.version || github.ref_name }}"

# Linux wheels are built inside manylinux_2_28 containers via maturin-action.
# We explicitly target manylinux 2_28; auto likely would too but pinning
# avoids unexpected wheel renames. See https://github.com/pypa/manylinux.
#
# The composite setup-rust action cannot run inside the maturin-action
# container, so toolchain setup is handled via before-script-linux instead.
build-linux:
name: "Linux ${{ matrix.target }}"
runs-on: ubuntu-24.04
needs: [check-version]
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
manylinux: "2_28"
- target: aarch64-unknown-linux-gnu
manylinux: "2_28"

steps:
- uses: actions/checkout@v6

- name: Build wheels
uses: PyO3/maturin-action@v1
with:
maturin-version: ${{ env.MATURIN_VERSION }}
target: ${{ matrix.target }}
manylinux: ${{ matrix.manylinux }}
rust-toolchain: ${{ env.RUST_STABLE }}
# abi3-py312 is set in [tool.maturin] features; no -i needed.
args: --release --locked --compatibility pypi
before-script-linux: |
Comment thread
posborne marked this conversation as resolved.
.github/scripts/setup-nightly.sh ${{ env.RUST_NIGHTLY }}
rustup target add wasm32-unknown-unknown

- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-linux-${{ matrix.target }}
path: target/wheels/*.whl
if-no-files-found: error

# macOS wheels — native builds on GitHub-hosted runners.
# macos-14 is Apple Silicon (aarch64); macos-13 is Intel (x86_64).
build-macos:
name: "macOS ${{ matrix.target }}"
runs-on: ${{ matrix.runner }}
needs: [check-version]
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin
runner: macos-26-intel
# Maturin defaults to 10.12 for x86_64, but componentize-py's
# build.rs compiles a native CPython host binary that requires
# >=10.15 (sqlite3_create_window_function) with Xcode 26's SDK.
# Python 3.12 itself requires 10.13+, so 10.15 is a safe minimum.
macosx_deployment_target: "10.15"
- target: aarch64-apple-darwin
runner: macos-26
macosx_deployment_target: "11.0"

steps:
- uses: actions/checkout@v6

- name: Set up Rust toolchains
uses: ./.github/actions/setup-rust
with:
rust-stable: ${{ env.RUST_STABLE }}
rust-nightly: ${{ env.RUST_NIGHTLY }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Build wheels
uses: PyO3/maturin-action@v1
with:
maturin-version: ${{ env.MATURIN_VERSION }}
target: ${{ matrix.target }}
# container: off is implied for non-Linux but set explicitly for clarity.
container: "off"
# abi3-py312 is set in [tool.maturin] features; no -i needed.
args: --release --locked
env:
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}

- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-macos-${{ matrix.target }}
path: target/wheels/*.whl
if-no-files-found: error

# Windows is not supported at the currently pinned componentize-py commit:
# its build.rs calls a POSIX configure script unconditionally when building
# CPython for WASI. Newer releases of componentize-py have Windows support;
# re-enable this job when upgrading componentize-py.

# Build a source distribution for PyPI alongside the binary wheels.
build-sdist:
name: "Build sdist"
runs-on: ubuntu-24.04
needs: [check-version]
steps:
- uses: actions/checkout@v6

- name: Build sdist
uses: PyO3/maturin-action@v1
with:
maturin-version: ${{ env.MATURIN_VERSION }}
command: sdist
args: --out dist

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

# Collect all release artifacts (wheels + sdist) into a single artifact,
# generate SHA256 checksums, and upload everything together.
collect-artifacts:
name: "Collect release artifacts"
needs: [build-linux, build-macos, build-sdist]
runs-on: ubuntu-24.04

steps:
- name: Download all wheel artifacts
uses: actions/download-artifact@v4
with:
pattern: wheels-*
path: dist/
merge-multiple: true

- name: Download sdist
uses: actions/download-artifact@v4
with:
name: sdist
path: dist/

- name: Generate SHA256 checksums
run: |
cd dist
sha256sum *.whl *.tar.gz > checksums.txt
cat checksums.txt

- name: List artifacts
run: ls -lh dist/

- name: Upload combined artifact
uses: actions/upload-artifact@v4
with:
name: release-artifacts
path: dist/
if-no-files-found: error

# Create a GitHub Release and attach all artifacts.
# Only runs on tag pushes, workflow_dispatch builds stop at collect-artifacts,
# presumed to be used for testing CI or related.
create-github-release:
name: "Create GitHub Release"
needs: [collect-artifacts]
runs-on: ubuntu-24.04
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write # Required to create releases and upload assets.

steps:
- uses: actions/checkout@v6

- name: Download release artifacts
uses: actions/download-artifact@v4
with:
name: release-artifacts
path: dist/

- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
TAG="${{ github.ref_name }}"
gh release create "$TAG" dist/*.whl dist/*.tar.gz dist/checksums.txt \
--title "$TAG" \
--prerelease \
--generate-notes \
--notes-start-tag "$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo '')"
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
# Python/uv artifacts
.venv/
*.egg-info
__pycache__
**/__pycache__/

# Build artifacts
/build/
bin/

# Rust
target/

# Compiled Python extension (maturin develop output)
*.so
*.pyd

# macOS debug symbol bundles generated by maturin develop
*.dSYM/
Loading
Loading