-
Notifications
You must be signed in to change notification settings - Fork 1
232 lines (219 loc) · 9.43 KB
/
Copy pathrelease-python.yml
File metadata and controls
232 lines (219 loc) · 9.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
name: release-python
# Two ways in:
# - push of a `v*` tag -> builds AND publishes to PyPI automatically
# - workflow_dispatch (manual) -> builds only, unless `publish` is set to true
#
# NB: only `pyproject.toml`'s [project].version drives this release. The
# `gridr` (pure-Rust engine) crate versions independently and is NOT
# published here - see release-crate.yml (triggered by `gridr-v*` tags).
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
publish:
description: 'Actually publish (otherwise: build only)'
type: boolean
default: false
target:
description: 'Where to publish, if publish is ticked'
type: choice
options:
- testpypi
- pypi
default: testpypi
jobs:
# ---------------------------------------------------------------------
# Sanity check: for a tag push, the tag must match pyproject.toml's
# version, so nobody ever publishes a wheel under the wrong number.
# ---------------------------------------------------------------------
check-version:
if: always() && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Compare tag vs pyproject.toml version
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
PYPROJECT_VERSION=$(grep -m1 '^version = ' pyproject.toml | sed -E 's/version = "(.*)"/\1/')
echo "tag=$TAG_VERSION pyproject=$PYPROJECT_VERSION"
if [ "$TAG_VERSION" != "$PYPROJECT_VERSION" ]; then
echo "::error::Tag v$TAG_VERSION does not match pyproject.toml version $PYPROJECT_VERSION"
exit 1
fi
# ---------------------------------------------------------------------
# Wheels: manylinux_2_28 (x86_64), macOS Intel, macOS Apple Silicon,
# Windows x86_64. abi3 (py_limited_api=cp310) means ONE wheel per
# platform/arch covers Python 3.10-3.14+, so no Python-version matrix.
# ---------------------------------------------------------------------
build-wheels:
needs: [check-version]
if: always() && (needs.check-version.result == 'success' || needs.check-version.result == 'skipped')
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
cibw_platform: linux
cibw_archs: x86_64
rustflags: '-C target-feature=+avx2,+fma'
- os: windows-latest
cibw_platform: windows
cibw_archs: AMD64
rustflags: '-C target-feature=+avx2,+fma'
- os: macos-15-intel # macos-13 was retired Dec 2025; this is the current Intel/x86_64 label
cibw_platform: macos
cibw_archs: x86_64
rustflags: '-C target-feature=+avx2,+fma'
- os: macos-14 # Apple Silicon (arm64) GitHub-hosted runner image
cibw_platform: macos
cibw_archs: arm64
rustflags: '' # no AVX2/FMA on arm64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install Rust (macOS / Windows host)
if: matrix.cibw_platform != 'linux'
uses: dtolnay/rust-toolchain@stable
- name: Build wheel
uses: pypa/cibuildwheel@v4.1.0
env:
CIBW_BUILD_VERBOSITY: 1
CIBW_BUILD: 'cp310-*' # abi3: build only against the floor version
CIBW_SKIP: '*-musllinux_*' # manylinux only - numpy has no reliable musl+abi3 wheel
CIBW_ARCHS: ${{ matrix.cibw_archs }}
MACOSX_DEPLOYMENT_TARGET: "11.0"
CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
# manylinux builds run inside a Docker container with no Rust -
# install it there explicitly (rustup, minimal profile, stable).
# macOS/Windows already have Rust via the dtolnay step above.
CIBW_BEFORE_ALL_LINUX: >-
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs
| sh -s -- -y --default-toolchain stable --profile minimal
# CIBW_ENVIRONMENT_LINUX *replaces* (doesn't merge with) the
# generic CIBW_ENVIRONMENT below for Linux builds, so it must
# repeat DIST_EXTRA_CONFIG/RUSTFLAGS in full, plus prepend
# rustup's install location to PATH so the build step finds cargo.
CIBW_ENVIRONMENT_LINUX: >-
PATH=$HOME/.cargo/bin:$PATH
DIST_EXTRA_CONFIG=dist_extra_config.cfg
RUSTFLAGS="${{ matrix.rustflags }}"
CIBW_ENVIRONMENT: >-
DIST_EXTRA_CONFIG=dist_extra_config.cfg
RUSTFLAGS="${{ matrix.rustflags }}"
#CIBW_TEST_COMMAND: python -c "import gridr.cdylib as c; print(c.__native_version__, c.__native_core_version__)"
CIBW_TEST_COMMAND: python -c "from gridr.cdylib import *"
# Linux only: objdump/binutils ships preinstalled on ubuntu-latest, so
# this is a zero-extra-dependency, high-confidence check. Windows/macOS
# need a different disassembler (dumpbin / otool) and aren't automated
# here - spot-check those manually if needed (see conversation notes).
- name: Verify AVX2/FMA instructions actually made it into the binary
if: matrix.cibw_platform == 'linux' && matrix.rustflags != ''
run: |
set -euo pipefail
WHEEL=$(ls wheelhouse/*.whl)
rm -rf /tmp/wheel_check && mkdir -p /tmp/wheel_check
python3 -m zipfile -e "$WHEEL" /tmp/wheel_check
SO_FILE=$(find /tmp/wheel_check -name '_libgridr*.so')
echo "Inspecting: $SO_FILE"
if ! objdump -d "$SO_FILE" | grep -q 'ymm'; then
echo "::error::No AVX2 (ymm register) instructions found in $SO_FILE - RUSTFLAGS may not have been applied at build time"
exit 1
fi
echo "OK: AVX2 instructions (ymm registers) found in the compiled extension."
- uses: actions/upload-artifact@v6
with:
name: wheels-${{ matrix.cibw_platform }}-${{ matrix.cibw_archs }}
path: wheelhouse/*.whl
# ---------------------------------------------------------------------
# Source distribution (no compilation, just packaging).
# ---------------------------------------------------------------------
build-sdist:
needs: [check-version]
if: always() && (needs.check-version.result == 'success' || needs.check-version.result == 'skipped')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.12'
- run: python -m pip install build
- run: python -m build --sdist --outdir dist/
- uses: actions/upload-artifact@v6
with:
name: sdist
path: dist/*.tar.gz
# debug-state:
# needs: [build-wheels, build-sdist, check-version]
# # 'always()' force le job à s'exécuter même si tout le monde est skipped/failed
# if: always()
# runs-on: ubuntu-latest
# steps:
# - name: DIAGNOSTIC COMPLET DES ÉTATS
# run: |
# echo "=================================================="
# echo "Event Name : '${{ github.event_name }}'"
# echo "Result check-version: '${{ needs.check-version.result }}'"
# echo "Result build-wheels : '${{ needs.build-wheels.result }}'"
# echo "Result build-sdist : '${{ needs.build-sdist.result }}'"
# echo "Input publish raw : '${{ github.event.inputs.publish }}'"
# echo "Input publish parsed: '${{ inputs.publish }}'"
# echo "=================================================="
# -------------------------------------------------------------
# 1️ Publish for a tag push (uses the *pypi* environment)
# -------------------------------------------------------------
publish-pypi-tag:
needs: [build-wheels, build-sdist]
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment: pypi # <-- must exist in Settings
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v7
with:
pattern: wheels-*
path: dist/
merge-multiple: true
- uses: actions/download-artifact@v7
with:
name: sdist
path: dist/
- name: Publish
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://upload.pypi.org/legacy/
# -------------------------------------------------------------
# 2️ Publish for a manual dispatch (uses the *testpypi* env)
# -------------------------------------------------------------
publish-pypi-manual:
needs: [build-wheels, build-sdist]
# Must add always() and explicit checks because of check-version 'skipped'
if: |
always() &&
github.event_name == 'workflow_dispatch' &&
needs.build-wheels.result == 'success' &&
needs.build-sdist.result == 'success' &&
inputs.publish == true
runs-on: ubuntu-latest
environment: ${{ inputs.target }} # testpypi or pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v7
with:
pattern: wheels-*
path: dist/
merge-multiple: true
- uses: actions/download-artifact@v7
with:
name: sdist
path: dist/
- name: Publish
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: >-
${{ inputs.target == 'testpypi'
&& 'https://test.pypi.org/legacy/'
|| 'https://upload.pypi.org/legacy/' }}