Skip to content

Commit 68d7d8e

Browse files
authored
Merge pull request #150 from codellm-devkit/fix/pypi-musl-alpine-smoke
ci: smoke-test musl wheels in Alpine, then publish them
2 parents a141d99 + df4a4f0 commit 68d7d8e

1 file changed

Lines changed: 116 additions & 12 deletions

File tree

.github/workflows/release-pypi.yml

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,10 @@ jobs:
218218
"$PY" -m build --wheel --outdir "$PWD/dist" "$PWD/pypi"
219219
ls -l "$PWD/dist"
220220
221+
# musl wheels can't be pip-installed on this glibc build host; they're
222+
# smoke-tested in a real Alpine (musl) container by the smoke-musl job.
221223
- name: Smoke test wheel
222-
if: matrix.rosetta != true
224+
if: matrix.rosetta != true && matrix.musl != true
223225
shell: bash
224226
env:
225227
PYTHON: ${{ runner.os == 'Linux' && '/opt/python/cp312-cp312/bin/python' || 'python3' }}
@@ -246,10 +248,14 @@ jobs:
246248
shasum -a 256 dist/*.whl
247249
fi
248250
251+
# Non-musl wheels are uploaded under the publishable `wheel-*` name and go
252+
# straight to release/publish. musl wheels are staged under a separate
253+
# name and only promoted to `wheel-*` by smoke-musl once they pass the
254+
# Alpine smoke test — so an unverified musl wheel is never published.
249255
- name: Upload wheel artifact
250256
uses: actions/upload-artifact@v4
251257
with:
252-
name: wheel-${{ matrix.name }}
258+
name: ${{ matrix.musl && format('musl-staging-{0}', matrix.name) || format('wheel-{0}', matrix.name) }}
253259
path: dist/*.whl
254260
if-no-files-found: error
255261

@@ -283,23 +289,94 @@ jobs:
283289
path: dist/*.tar.gz
284290
if-no-files-found: error
285291

292+
# --------------------------------------------------------------------------
293+
# Validate the musl wheels in a real Alpine (musl) container — they can't be
294+
# pip-installed on the glibc build host. Runs per-arch on native runners,
295+
# where docker is available (unlike inside the manylinux build container).
296+
# Only wheels that pass here are promoted to the publishable `wheel-*` name,
297+
# so an unverified musl wheel never reaches PyPI. Experimental: a musl
298+
# failure must never block the glibc/macOS release.
299+
# --------------------------------------------------------------------------
300+
smoke-musl:
301+
name: smoke-musl (${{ matrix.arch }})
302+
needs: build-wheels
303+
continue-on-error: true
304+
strategy:
305+
fail-fast: false
306+
matrix:
307+
include:
308+
- arch: x86_64
309+
runs-on: ubuntu-22.04
310+
name: musllinux-x86_64
311+
- arch: aarch64
312+
runs-on: ubuntu-22.04-arm
313+
name: musllinux-aarch64
314+
runs-on: ${{ matrix.runs-on }}
315+
steps:
316+
- name: Download staged musl wheel
317+
uses: actions/download-artifact@v4
318+
with:
319+
name: musl-staging-${{ matrix.name }}
320+
path: dist
321+
322+
- name: Smoke test in Alpine (musl)
323+
shell: bash
324+
run: |
325+
set -euo pipefail
326+
docker run --rm -v "$PWD/dist:/dist:ro" python:3.12-alpine sh -euc '
327+
wheel=$(ls /dist/*.whl | head -n1)
328+
echo "smoke-musl: testing $wheel"
329+
python -m venv /tmp/venv
330+
/tmp/venv/bin/pip install --upgrade pip >/dev/null
331+
/tmp/venv/bin/pip install "$wheel"
332+
echo "smoke-musl: codajv --version"
333+
/tmp/venv/bin/codajv --version
334+
echo "smoke-musl: codajv -s (level-1 source analysis, exercises bundled jmods)"
335+
out=$(/tmp/venv/bin/codajv -s "public class Smoke { public int answer() { return 42; } }")
336+
printf "%s" "$out" | head -c 2000; echo
337+
printf "%s" "$out" | grep -q Smoke || { echo "smoke-musl: FAILED — expected class Smoke in output"; exit 1; }
338+
echo "smoke-musl: OK"
339+
'
340+
341+
- name: Promote verified wheel for publishing
342+
uses: actions/upload-artifact@v4
343+
with:
344+
name: wheel-${{ matrix.name }}
345+
path: dist/*.whl
346+
if-no-files-found: error
347+
286348
# --------------------------------------------------------------------------
287349
# GitHub Release (tag pushes only): attach every wheel + sdist + checksums.
288350
# --------------------------------------------------------------------------
289351
github-release:
290352
name: github-release
291-
needs: [build-wheels, build-sdist]
292-
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
353+
needs: [build-wheels, build-sdist, smoke-musl]
354+
# Wait for smoke-musl (so verified musl wheels are attached) but never block
355+
# the release on it — only the essential build jobs must have succeeded.
356+
if: >-
357+
always() &&
358+
needs.build-wheels.result == 'success' &&
359+
needs.build-sdist.result == 'success' &&
360+
github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
293361
runs-on: ubuntu-22.04
294362
permissions:
295363
contents: write
296364
steps:
297-
- name: Download all artifacts
365+
# Pull only publishable artifacts: `wheel-*` (incl. musl wheels promoted
366+
# by smoke-musl) and the sdist — never the `musl-staging-*` artifacts.
367+
- name: Download wheels
298368
uses: actions/download-artifact@v4
299369
with:
370+
pattern: wheel-*
300371
path: dist
301372
merge-multiple: true
302373

374+
- name: Download sdist
375+
uses: actions/download-artifact@v4
376+
with:
377+
name: sdist
378+
path: dist
379+
303380
- name: Generate checksums
304381
run: |
305382
cd dist
@@ -321,23 +398,38 @@ jobs:
321398
# --------------------------------------------------------------------------
322399
publish-pypi:
323400
name: publish-pypi
324-
needs: [build-wheels, build-sdist]
401+
needs: [build-wheels, build-sdist, smoke-musl]
402+
# Wait for smoke-musl (so verified musl wheels publish too) but never block
403+
# the release on it — only the essential build jobs must have succeeded.
325404
if: >-
326-
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
327-
(github.event_name == 'workflow_dispatch' && inputs.publish_target == 'pypi')
405+
always() &&
406+
needs.build-wheels.result == 'success' &&
407+
needs.build-sdist.result == 'success' &&
408+
(
409+
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
410+
(github.event_name == 'workflow_dispatch' && inputs.publish_target == 'pypi')
411+
)
328412
runs-on: ubuntu-22.04
329413
environment:
330414
name: pypi
331415
url: https://pypi.org/p/codeanalyzer-java
332416
permissions:
333417
id-token: write
334418
steps:
335-
- name: Download all artifacts
419+
# `wheel-*` (incl. smoke-musl-promoted musl wheels) + sdist; never staging.
420+
- name: Download wheels
336421
uses: actions/download-artifact@v4
337422
with:
423+
pattern: wheel-*
338424
path: dist
339425
merge-multiple: true
340426

427+
- name: Download sdist
428+
uses: actions/download-artifact@v4
429+
with:
430+
name: sdist
431+
path: dist
432+
341433
- name: Keep only distributables
342434
run: find dist -type f ! -name '*.whl' ! -name '*.tar.gz' -delete && ls -l dist
343435

@@ -352,21 +444,33 @@ jobs:
352444
# --------------------------------------------------------------------------
353445
publish-testpypi:
354446
name: publish-testpypi
355-
needs: [build-wheels, build-sdist]
356-
if: github.event_name == 'workflow_dispatch' && inputs.publish_target == 'testpypi'
447+
needs: [build-wheels, build-sdist, smoke-musl]
448+
if: >-
449+
always() &&
450+
needs.build-wheels.result == 'success' &&
451+
needs.build-sdist.result == 'success' &&
452+
github.event_name == 'workflow_dispatch' && inputs.publish_target == 'testpypi'
357453
runs-on: ubuntu-22.04
358454
environment:
359455
name: testpypi
360456
url: https://test.pypi.org/p/codeanalyzer-java
361457
permissions:
362458
id-token: write
363459
steps:
364-
- name: Download all artifacts
460+
# `wheel-*` (incl. smoke-musl-promoted musl wheels) + sdist; never staging.
461+
- name: Download wheels
365462
uses: actions/download-artifact@v4
366463
with:
464+
pattern: wheel-*
367465
path: dist
368466
merge-multiple: true
369467

468+
- name: Download sdist
469+
uses: actions/download-artifact@v4
470+
with:
471+
name: sdist
472+
path: dist
473+
370474
- name: Keep only distributables
371475
run: find dist -type f ! -name '*.whl' ! -name '*.tar.gz' -delete && ls -l dist
372476

0 commit comments

Comments
 (0)