Skip to content

Add missing Android upload-artifact + Windows shim diagnostics #12

Add missing Android upload-artifact + Windows shim diagnostics

Add missing Android upload-artifact + Windows shim diagnostics #12

name: Test bridge (no publish, no slow platform tests)
# Throwaway workflow that exercises just the new serious_python_bridge work —
# the cibuildwheel matrix, the Android NDK cross-build, and the macOS bridge
# example integration test — without triggering the slow flet_example
# platform matrix or the publish/release steps in ci.yml. Delete before
# merging to main.
on:
push:
branches: [dart-bridge]
workflow_dispatch:
env:
# Mirrors ci.yml's workflow-level env: serious_python_darwin's
# sync_site_packages.sh and the Linux CMakeLists.txt both read this to know
# where package_command.dart staged the bundled site-packages.
SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages"
jobs:
test_wheel_build:
name: cibuildwheel (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v2.21.3
with:
package-dir: src/serious_python_bridge/python
- name: List built wheels
shell: bash
run: |
ls -la wheelhouse/
echo
echo "Wheel filenames (expect cp312-abi3-<plat>):"
ls wheelhouse/*.whl
- name: Upload wheel artifacts
uses: actions/upload-artifact@v4
with:
name: bridge-wheels-${{ matrix.os }}
path: wheelhouse/*.whl
if-no-files-found: error
test_android_build:
name: Android cross-build (${{ matrix.abi }})
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
abi: [arm64-v8a, armeabi-v7a, x86_64]
env:
PYTHON_VERSION: "3.12"
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download python-android-mobile-forge tarball
run: |
set -euo pipefail
VER="$PYTHON_VERSION"
ABI="${{ matrix.abi }}"
ARCHIVE="python-android-mobile-forge-${VER}.tar.gz"
curl -fL -o "$ARCHIVE" \
"https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}"
mkdir -p pydist
tar -xzf "$ARCHIVE" -C pydist \
"install/android/${ABI}/python-${VER}.13/include/" \
"install/android/${ABI}/python-${VER}.13/lib/"
echo "Python.h candidates:"
find pydist -name "Python.h"
echo "libpython candidates:"
find pydist -name "libpython*.so"
- name: Cross-compile dart_bridge.abi3.so
run: |
set -euxo pipefail
VER="$PYTHON_VERSION"
ABI="${{ matrix.abi }}"
case "$ABI" in
arm64-v8a) TARGET=aarch64-linux-android ;;
armeabi-v7a) TARGET=armv7a-linux-androideabi ;;
x86_64) TARGET=x86_64-linux-android ;;
*) echo "unsupported ABI: $ABI" >&2 ; exit 1 ;;
esac
API=21
NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK_LATEST_HOME}}"
TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64"
CC="$TOOLCHAIN/bin/${TARGET}${API}-clang"
test -x "$CC"
INCLUDE_DIR=$(find pydist -path "*/python-${VER}.13/include/python${VER}" | head -n1)
LIBPYTHON=$(find pydist -path "*/python-${VER}.13/lib/libpython${VER}.so" | head -n1)
test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON"
OUT="dart_bridge.abi3-android-${ABI}.so"
$CC -shared -fPIC -fvisibility=hidden \
-DPy_LIMITED_API=0x030c0000 \
-I"$INCLUDE_DIR" \
-I"src/serious_python_bridge/native" \
src/serious_python_bridge/native/dart_bridge.c \
src/serious_python_bridge/native/dart_api/dart_api_dl.c \
"$LIBPYTHON" \
-Wl,-z,max-page-size=16384 \
-o "$OUT"
- name: Inspect output
run: |
ls -lh dart_bridge.abi3-android-*.so
file dart_bridge.abi3-android-*.so
- name: Upload .so artifact
uses: actions/upload-artifact@v4
with:
name: bridge-android-${{ matrix.abi }}
path: dart_bridge.abi3-android-*.so
if-no-files-found: error
test_bridge_example_macos:
name: Bridge example macOS round-trip (Python ${{ matrix.python_version }})
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
python_version: ['3.12', '3.13', '3.14']
env:
SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Flutter
uses: kuhnroyal/flutter-fvm-config-action/setup@v3
with:
path: '.fvmrc'
cache: true
- name: Package + run integration test
working-directory: "src/serious_python_bridge/example"
run: |
dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }}
flutter test integration_test -d macos
test_bridge_example_ios:
name: Bridge example iOS round-trip (Python ${{ matrix.python_version }})
runs-on: macos-latest
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
python_version: ['3.12', '3.13', '3.14']
env:
SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Flutter
uses: kuhnroyal/flutter-fvm-config-action/setup@v3
with:
path: '.fvmrc'
cache: true
- name: Setup iOS Simulator
id: simulator
uses: futureware-tech/simulator-action@v4
with:
model: 'iPhone 16 Pro Max'
os: "iOS"
os_version: "^18.6"
shutdown_after_job: true
wait_for_boot: true
- name: Package + run integration test
working-directory: "src/serious_python_bridge/example"
run: |
# certifi is a placeholder requirement: serious_python_darwin's
# sync_site_packages.sh only populates dist_ios/site-xcframeworks
# (which bundle-python-frameworks-ios.sh then requires at build
# time) when iOS-specific site-packages subdirs exist. Empty
# --requirements skips that branch and the build fails.
dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi
flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }}
test_bridge_example_linux:
name: Bridge example Linux ${{ matrix.title }} round-trip (Python ${{ matrix.python_version }})
runs-on: ${{ matrix.runner }}
needs: test_wheel_build
strategy:
fail-fast: false
matrix:
python_version: ['3.12', '3.13', '3.14']
arch: [arm64, amd64]
include:
- arch: arm64
runner: ubuntu-24.04-arm
title: ARM64
wheel_artifact: bridge-wheels-ubuntu-24.04-arm
- arch: amd64
runner: ubuntu-24.04
title: AMD64
wheel_artifact: bridge-wheels-ubuntu-24.04
env:
SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup uv
uses: astral-sh/setup-uv@v6
- name: Get Flutter version from .fvmrc
uses: kuhnroyal/flutter-fvm-config-action/config@v3
id: fvm-config-action
with:
path: '.fvmrc'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }}
channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }}
cache: true
- name: Install Linux desktop build deps
run: |
sudo apt-get update --allow-releaseinfo-change
sudo apt-get install -y xvfb libgtk-3-dev
if [ "${{ matrix.arch }}" = "amd64" ]; then
sudo apt-get install -y \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly gstreamer1.0-libav
else
sudo apt-get install -y \
clang ninja-build gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly gstreamer1.0-libav
fi
- name: Download dart_bridge wheel artifact
uses: actions/download-artifact@v4
with:
name: ${{ matrix.wheel_artifact }}
path: ${{ runner.temp }}/dart_bridge_wheels
- name: Pick matching wheel for this arch
id: wheel
run: |
set -euo pipefail
WHL=$(ls "${{ runner.temp }}/dart_bridge_wheels"/dart_bridge-*manylinux*.whl | head -n1)
test -n "$WHL"
echo "path=$WHL" >> "$GITHUB_OUTPUT"
echo "Picked: $WHL"
- name: Package + run integration test
working-directory: src/serious_python_bridge/example
run: |
flutter pub get
dart run serious_python:main package app/src \
--platform Linux \
--python-version ${{ matrix.python_version }} \
--requirements ${{ steps.wheel.outputs.path }}
xvfb-run flutter test integration_test -d linux
test_bridge_example_android:
name: Bridge example Android round-trip (Python ${{ matrix.python_version }})
runs-on: ubuntu-latest
needs: test_android_build
strategy:
fail-fast: false
matrix:
# x86_64 matches the emulator architecture below; only build/install
# for that ABI to keep CI fast.
python_version: ['3.12', '3.13', '3.14']
env:
SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Flutter
uses: kuhnroyal/flutter-fvm-config-action/setup@v3
with:
path: '.fvmrc'
cache: true
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Gradle cache
uses: gradle/actions/setup-gradle@v3
- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-bridge
- name: Download Android bridge .so for x86_64
uses: actions/download-artifact@v4
with:
name: bridge-android-x86_64
path: ${{ runner.temp }}/dart_bridge_android
- name: Inject dart_bridge.abi3.so into bundled site-packages
run: |
# serious_python_android's gradle takes everything from
# SERIOUS_PYTHON_SITE_PACKAGES/<abi>/ and zips it as
# libpythonsitepackages.so, which ends up in the APK. Drop our
# cross-compiled dart_bridge.abi3.so there so Python finds it at
# runtime. The .so name has to be the canonical 'dart_bridge.abi3.so'
# for CPython's import to match.
set -euxo pipefail
ABI=x86_64
DEST="$SERIOUS_PYTHON_SITE_PACKAGES/$ABI"
mkdir -p "$DEST"
cp "${{ runner.temp }}/dart_bridge_android/dart_bridge.abi3-android-$ABI.so" \
"$DEST/dart_bridge.abi3.so"
ls -lh "$DEST"
- name: Setup Android Emulator + Run tests
uses: reactivecircus/android-emulator-runner@v2
env:
EMULATOR_PORT: 5554
with:
avd-name: android_emulator
api-level: 33
target: google_atd
arch: x86_64
profile: pixel_5
sdcard-path-or-size: 128M
ram-size: 2048M
disk-size: 4096M
emulator-port: ${{ env.EMULATOR_PORT }}
disable-animations: true
emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192
pre-emulator-launch-script: |
sdkmanager --list_installed
script: |
cd src/serious_python_bridge/example
dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }}
flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }}
test_bridge_example_windows:
name: Bridge example Windows round-trip (Python ${{ matrix.python_version }})
runs-on: windows-latest
needs: test_wheel_build
strategy:
fail-fast: false
matrix:
python_version: ['3.12', '3.13', '3.14']
env:
SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Flutter
uses: kuhnroyal/flutter-fvm-config-action/setup@v3
with:
path: '.fvmrc'
cache: true
- name: Download dart_bridge wheel artifact
uses: actions/download-artifact@v4
with:
name: bridge-wheels-windows-latest
path: ${{ runner.temp }}\dart_bridge_wheels
- name: Pick matching wheel
id: wheel
shell: bash
run: |
set -euo pipefail
WHL=$(ls "$RUNNER_TEMP/dart_bridge_wheels"/dart_bridge-*-win_amd64.whl | head -n1)
test -n "$WHL"
echo "path=$WHL" >> "$GITHUB_OUTPUT"
echo "Picked: $WHL"
- name: Package + run integration test
working-directory: "src/serious_python_bridge/example"
run: |
dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }}
flutter test integration_test -d windows