Skip to content

Build release wheels on native ARM runner (drop QEMU); publish one GitHub release#72

Merged
yokofly merged 1 commit into
developfrom
yokofly/native-arm-release-runners
Jun 15, 2026
Merged

Build release wheels on native ARM runner (drop QEMU); publish one GitHub release#72
yokofly merged 1 commit into
developfrom
yokofly/native-arm-release-runners

Conversation

@yokofly

@yokofly yokofly commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #71. CI improvement — same target artifacts (built natively
instead of under emulation), just faster and with a cleaner release flow. Not
urgent (0.3.0 already shipped); benefits the next release.

Speed: native ARM instead of QEMU

The release built aarch64 Linux wheels by emulating aarch64 on the single
x86_64 ubuntu-22.04 runner (the Set up QEMU step), making that leg take
~1h. This adds a native ubuntu-22.04-arm runner (free for public
repos) and sets [tool.cibuildwheel.linux] archs = "auto64" so each runner
builds only its native arch. QEMU step removed. Expected: ~10–15 min.
Wheels are functionally equivalent for the same target tags (not asserting
byte-for-byte equality). macOS unchanged (macos-14 builds arm64 natively +
cross-builds x86_64; no Intel mac runner exists anymore).

Structure: one GitHub-release job, decoupled from PyPI

Previously every matrix wheel job ran its own action-gh-release step — four
jobs racing to create/update the same release, each needing contents: write.
This moves it into a single publish-github-release job after the builds
that uploads the complete asset set (wheels + sdist) in one shot; builders
drop to contents: read. It's single-writer, not transactional — a
mid-upload failure can still leave a partial release (re-run to finish);
fail_on_unmatched_files: true guards against an empty glob.

Review-feedback decisions

  • Release ↔ PyPI coupling: publish-github-release deliberately depends on
    [build_wheels, build_sdist], not publish-to-pypi, so a PyPI failure
    still leaves a downloadable GitHub release (artifact fallback). If the team
    prefers the invariant "a GitHub release means PyPI is live," flip it to
    needs: [publish-to-pypi] (or publish a draft first). Easy to change — say
    the word.
  • PyPI auth: dropped the unused id-token: write from publish-to-pypi
    and corrected the misleading "trusted publishing" comment — it's token-based
    (PYPI_TOKEN). Migrating to real OIDC trusted publishing (no long-lived
    token, more secure) is worth doing but needs PyPI-side config, so it's left
    as a separate follow-up.

Validation

actions.yml parses; fail_on_unmatched_files confirmed a real @v2 input.
Jobs = build_wheels / build_sdist / publish-to-pypi / publish-github-release;
matrix = ubuntu-22.04, ubuntu-22.04-arm, windows-2022, macos-14. The native
ARM build + new release flow are only truly exercised by a workflow_dispatch
run
, so the real proof comes at the next release.

🤖 Generated with Claude Code

@coveralls

coveralls commented Jun 15, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 27528562816

Warning

No base build found for commit 6774dd4 on develop.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 94.387%

Details

  • Patch coverage: No coverable lines changed in this PR.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 3884
Covered Lines: 3666
Line Coverage: 94.39%
Coverage Strength: 12.44 hits per line

💛 - Coveralls

Speed: add a native ubuntu-22.04-arm runner (free for public repos) and
set [tool.cibuildwheel.linux] archs=auto64, so each runner builds only its
native arch. aarch64 wheels build natively instead of under ~10x-slower
QEMU emulation (the ~1h aarch64 leg drops to ~10-15 min); the Set-up-QEMU
step is removed. Same target artifacts (manylinux/musllinux aarch64/x86_64),
built natively instead of under emulation rather than byte-for-byte identical.

Structure: move the GitHub-release asset upload out of each matrix wheel
job into a single publish-github-release job that runs after the builds.
The release is published from one job (single-writer, not transactional)
with the complete asset set (wheels + sdist) instead of four jobs racing,
and the builders drop to contents: read. That job depends on the build
jobs, NOT on publish-to-pypi, so a PyPI upload failure still leaves a
downloadable GitHub release. fail_on_unmatched_files guards the upload glob.

Also drop the unused id-token: write from publish-to-pypi (it uses a token,
not OIDC trusted publishing) and correct the comment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yokofly yokofly force-pushed the yokofly/native-arm-release-runners branch from 676dd77 to 362a201 Compare June 15, 2026 06:35
@yokofly yokofly merged commit 89d2aaa into develop Jun 15, 2026
22 checks passed
@yokofly yokofly deleted the yokofly/native-arm-release-runners branch June 15, 2026 07:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants