Skip to content

Commit 4937ca0

Browse files
committed
ci: add cross-platform PyPI release workflow with OIDC publishing
Build platform-tagged, impure wheels (each bundling a GraalVM native binary plus the JDK jmods it needs at runtime) across manylinux, musllinux, macOS, and Windows, then publish via OIDC Trusted Publishing. - release-pypi.yml: build-wheels matrix, sdist, GitHub Release on tag, and publish-pypi/publish-testpypi jobs gated on tag push or manual dispatch. - Linux legs build inside manylinux_2_28 containers so wheel tags are correct by construction; musllinux legs build a fully-static --libc=musl binary. - smoke-test.sh runs each wheel JVM-free (codajv --version plus a level-1 source analysis that exercises the bundled jmods). - setup-musl.sh provisions the musl toolchain + static zlib (experimental). - build.gradle: emit a static musl binary when CODEANALYZER_NATIVE_MUSL=true. - hatch_build.py: honor CODEANALYZER_WHEEL_PLATFORM to stamp the exact tag.
1 parent 2bda2d1 commit 4937ca0

5 files changed

Lines changed: 451 additions & 3 deletions

File tree

.github/scripts/setup-musl.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
# Best-effort musl cross toolchain + static zlib so GraalVM native-image can
3+
# produce a fully-static `--libc=musl` binary on a glibc (manylinux) host.
4+
# GraalVM can't run on Alpine, so the static binary is the only way to ship a
5+
# musllinux wheel. This leg is marked experimental in the workflow; failures
6+
# here should not be treated as a hard release blocker.
7+
#
8+
# Usage: setup-musl.sh <arch> where arch is x64|x86_64 or aarch64|arm64
9+
set -euo pipefail
10+
11+
ARCH="${1:-x64}"
12+
case "$ARCH" in
13+
x64 | x86_64) MUSL_TRIPLE=x86_64-linux-musl ;;
14+
aarch64 | arm64) MUSL_TRIPLE=aarch64-linux-musl ;;
15+
*)
16+
echo "setup-musl: unsupported arch '$ARCH'" >&2
17+
exit 1
18+
;;
19+
esac
20+
21+
PREFIX=/opt/musl
22+
mkdir -p "$PREFIX"
23+
24+
toolchain_url="https://musl.cc/${MUSL_TRIPLE}-native.tgz"
25+
echo "setup-musl: downloading toolchain $toolchain_url"
26+
curl -fsSL "$toolchain_url" | tar -xz -C "$PREFIX" --strip-components=1
27+
28+
export PATH="$PREFIX/bin:$PATH"
29+
echo "$PREFIX/bin" >> "$GITHUB_PATH"
30+
31+
# native-image links libz statically; build it against the musl toolchain and
32+
# install into the toolchain prefix so the musl gcc finds libz.a / zlib.h.
33+
ZLIB_VERSION=1.3.1
34+
workdir="$(mktemp -d)"
35+
echo "setup-musl: building static zlib ${ZLIB_VERSION} with ${MUSL_TRIPLE}-gcc"
36+
curl -fsSL "https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz" | tar -xz -C "$workdir" --strip-components=1
37+
(
38+
cd "$workdir"
39+
CC="${MUSL_TRIPLE}-gcc" ./configure --static --prefix="$PREFIX"
40+
make -j"$(nproc)"
41+
make install
42+
)
43+
44+
echo "CC=${MUSL_TRIPLE}-gcc" >> "$GITHUB_ENV"
45+
echo "setup-musl: installed musl toolchain + static zlib under $PREFIX"

.github/scripts/smoke-test.sh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env bash
2+
# Install the freshly built wheel into a throwaway venv and exercise the
3+
# `codajv` entry point JVM-free: it must run the bundled native binary and
4+
# resolve JDK types from the bundled jmods (no JAVA_HOME required).
5+
#
6+
# Usage: smoke-test.sh [DIST_DIR] (defaults to ./dist)
7+
# Honors $PYTHON to pick the interpreter that creates the venv.
8+
set -euo pipefail
9+
10+
PYTHON="${PYTHON:-python3}"
11+
DIST_DIR="${1:-dist}"
12+
13+
wheel=$(ls "$DIST_DIR"/*.whl 2>/dev/null | head -n1 || true)
14+
if [ -z "$wheel" ]; then
15+
echo "smoke-test: no wheel found in '$DIST_DIR'" >&2
16+
exit 1
17+
fi
18+
echo "smoke-test: testing $wheel"
19+
20+
venv="$(mktemp -d)/venv"
21+
"$PYTHON" -m venv "$venv"
22+
if [ -x "$venv/bin/python" ]; then
23+
vpy="$venv/bin/python"
24+
vcodajv="$venv/bin/codajv"
25+
else
26+
vpy="$venv/Scripts/python.exe"
27+
vcodajv="$venv/Scripts/codajv.exe"
28+
fi
29+
30+
"$vpy" -m pip install --upgrade pip >/dev/null
31+
"$vpy" -m pip install "$wheel"
32+
33+
echo "smoke-test: codajv --version"
34+
"$vcodajv" --version
35+
36+
echo "smoke-test: codajv -s (level-1 source analysis, exercises bundled jmods)"
37+
out="$("$vcodajv" -s 'public class Smoke { public int answer() { return 42; } }')"
38+
echo "$out" | head -c 2000
39+
echo
40+
if ! echo "$out" | grep -q 'Smoke'; then
41+
echo "smoke-test: FAILED — expected class 'Smoke' in analysis output" >&2
42+
exit 1
43+
fi
44+
echo "smoke-test: OK"

0 commit comments

Comments
 (0)