ci: pre-clone flet shallowly; surface package-command progress #228
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: ['**'] | |
| tags: ['*'] | |
| pull_request: | |
| workflow_dispatch: | |
| # Auto-cancel in-flight runs when a new push lands on the same ref. | |
| # Tag builds (refs/tags/*) get a unique-per-run group so release runs | |
| # never cancel each other. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ startsWith(github.ref, 'refs/tags/') && github.run_id || github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| ROOT: "${{ github.workspace }}" | |
| SCRIPTS: "${{ github.workspace }}/.github/scripts" | |
| SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages" | |
| UV_PYTHON: "3.12" | |
| # Pin flet so the Python side matches the Dart-side flet version. With | |
| # `--only-binary :all:`, pip would otherwise silently downgrade to an | |
| # older flet whose transitive deps (e.g. msgpack) have wheels for the | |
| # target python_version / platform, leaving the two halves mismatched. | |
| FLET_VERSION: "0.85.3" | |
| # Python flet for the FFI-transport example is pinned to a git ref — | |
| # FletDartBridgeServer isn't on PyPI yet. The git URL is given to pip via | |
| # --requirements, which would normally clone the whole flet repo (large) | |
| # inside pip itself. On Windows this can take 30+ minutes and looks like | |
| # a hang because pip emits no progress during git clone. So the FFI jobs | |
| # first do an explicit `git clone --depth 1` into ${{ runner.temp }}/flet | |
| # and then pass the local subpath as the requirement. | |
| FLET_GIT_REF: "dart-bridge" | |
| FLET_GIT_URL: "https://github.com/flet-dev/flet.git" | |
| # Source installs additionally require SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet | |
| # on mobile targets to bypass --only-binary :all:; see package_command.dart. | |
| jobs: | |
| macos: | |
| name: Test Flet example on macOS (Python ${{ matrix.python_version }}) | |
| runs-on: macos-26 | |
| # Temporarily disabled — focusing CI on flet_ffi_example while the | |
| # dart_bridge transport stabilises. Flip back on before merging the | |
| # flet PR to confirm the socket transport still works. | |
| if: false | |
| 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: Run tests | |
| working-directory: "src/serious_python/example/flet_example" | |
| run: | | |
| dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} | |
| flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| ios: | |
| name: Test Flet example on iOS (Python ${{ matrix.python_version }}) | |
| runs-on: macos-26 | |
| if: false # see `macos:` for rationale | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # 3.13/3.14 disabled until msgpack 1.x ships iOS arm64 wheels for | |
| # those Python versions on pypi.flet.dev — with `--only-binary :all:` | |
| # pip otherwise silently downgrades flet to an older version, | |
| # leaving Python/Dart out of sync. | |
| python_version: ['3.12'] | |
| 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: | |
| # https://github.com/futureware-tech/simulator-action/wiki/Devices-macos-latest | |
| model: 'iPhone 17 Pro Max' | |
| os: "iOS" | |
| os_version: "26.5" | |
| shutdown_after_job: true | |
| wait_for_boot: true | |
| - name: Run tests | |
| working-directory: "src/serious_python/example/flet_example" | |
| run: | | |
| dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} | |
| flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| android: | |
| name: Test Flet example on Android (Python ${{ matrix.python_version }}) | |
| runs-on: ubuntu-latest | |
| if: false # see `macos:` for rationale | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python_version: ['3.12'] # see ios job for the 3.13/3.14 gate | |
| 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 | |
| - 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/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} | |
| cd src/serious_python/example/flet_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| windows: | |
| name: Test Flet example on Windows (Python ${{ matrix.python_version }}) | |
| runs-on: windows-latest | |
| if: false # see `macos:` for rationale | |
| 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: Run tests | |
| working-directory: "src/serious_python/example/flet_example" | |
| run: | | |
| dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} | |
| flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| linux: | |
| name: Test Flet example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) | |
| runs-on: ${{ matrix.runner }} | |
| if: false # see `macos:` for rationale | |
| 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 | |
| - arch: amd64 | |
| runner: ubuntu-24.04 | |
| title: AMD64 | |
| 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' }} # https://github.com/subosito/flutter-action/issues/345#issuecomment-2657332687 | |
| cache: true | |
| - name: Install dependencies | |
| 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 \ | |
| gstreamer1.0-tools \ | |
| gstreamer1.0-x \ | |
| gstreamer1.0-alsa \ | |
| gstreamer1.0-gl \ | |
| gstreamer1.0-gtk3 \ | |
| gstreamer1.0-qt5 \ | |
| gstreamer1.0-pulseaudio | |
| else | |
| sudo apt-get install -y \ | |
| clang \ | |
| ninja-build \ | |
| gstreamer1.0-plugins-bad \ | |
| gstreamer1.0-plugins-ugly \ | |
| gstreamer1.0-libav | |
| fi | |
| - name: Run tests | |
| working-directory: src/serious_python/example/flet_example | |
| run: | | |
| flutter pub get | |
| dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} | |
| xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| flet_ffi_macos: | |
| name: Test Flet FFI example on macOS (Python ${{ matrix.python_version }}) | |
| runs-on: macos-26 | |
| # Temporarily gated off while we debug the Windows hang — re-enable after. | |
| if: false | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python_version: ['3.12', '3.13', '3.14'] | |
| env: | |
| SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} | |
| SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet | |
| 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: Shallow-clone flet (dart-bridge) | |
| run: | | |
| git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" | |
| - name: Run tests | |
| working-directory: "src/serious_python/example/flet_ffi_example" | |
| run: | | |
| dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" | |
| flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| flet_ffi_ios: | |
| name: Test Flet FFI example on iOS (Python ${{ matrix.python_version }}) | |
| runs-on: macos-26 | |
| if: false # see `flet_ffi_macos:` rationale | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # 3.13/3.14 gated on msgpack iOS arm64 wheels landing on pypi.flet.dev | |
| # — see the flet_example ios job for the same rationale. | |
| python_version: ['3.12'] | |
| env: | |
| SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} | |
| SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet | |
| 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 17 Pro Max' | |
| os: "iOS" | |
| os_version: "26.5" | |
| shutdown_after_job: true | |
| wait_for_boot: true | |
| - name: Shallow-clone flet (dart-bridge) | |
| run: | | |
| git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" | |
| - name: Run tests | |
| working-directory: "src/serious_python/example/flet_ffi_example" | |
| run: | | |
| dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" | |
| flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| flet_ffi_android: | |
| name: Test Flet FFI example on Android (Python ${{ matrix.python_version }}) | |
| runs-on: ubuntu-latest | |
| if: false # see `flet_ffi_macos:` rationale | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python_version: ['3.12'] # see ios job for the 3.13/3.14 gate | |
| env: | |
| SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} | |
| SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet | |
| 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-ffi | |
| - name: Shallow-clone flet (dart-bridge) | |
| run: | | |
| git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" | |
| - 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/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" | |
| cd src/serious_python/example/flet_ffi_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| flet_ffi_windows: | |
| name: Test Flet FFI example on Windows (Python ${{ matrix.python_version }}) | |
| runs-on: windows-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python_version: ['3.12', '3.13', '3.14'] | |
| env: | |
| SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} | |
| SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet | |
| 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: Shallow-clone flet (dart-bridge) | |
| shell: bash | |
| run: | | |
| git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${RUNNER_TEMP}/flet-src" | |
| - name: Run tests | |
| working-directory: "src/serious_python/example/flet_ffi_example" | |
| shell: bash | |
| run: | | |
| dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${RUNNER_TEMP}/flet-src/sdk/python/packages/flet" | |
| flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| flet_ffi_linux: | |
| name: Test Flet FFI example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) | |
| runs-on: ${{ matrix.runner }} | |
| if: false # see `flet_ffi_macos:` rationale | |
| 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 | |
| - arch: amd64 | |
| runner: ubuntu-24.04 | |
| title: AMD64 | |
| env: | |
| SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} | |
| SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet | |
| 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 dependencies | |
| 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 \ | |
| gstreamer1.0-tools \ | |
| gstreamer1.0-x \ | |
| gstreamer1.0-alsa \ | |
| gstreamer1.0-gl \ | |
| gstreamer1.0-gtk3 \ | |
| gstreamer1.0-qt5 \ | |
| gstreamer1.0-pulseaudio | |
| else | |
| sudo apt-get install -y \ | |
| clang \ | |
| ninja-build \ | |
| gstreamer1.0-plugins-bad \ | |
| gstreamer1.0-plugins-ugly \ | |
| gstreamer1.0-libav | |
| fi | |
| - name: Shallow-clone flet (dart-bridge) | |
| run: | | |
| git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" | |
| - name: Run tests | |
| working-directory: src/serious_python/example/flet_ffi_example | |
| run: | | |
| flutter pub get | |
| dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" | |
| xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} | |
| bridge_example_macos: | |
| name: Test Bridge example on macOS (Python ${{ matrix.python_version }}) | |
| runs-on: macos-26 | |
| if: false # see `macos:` for rationale | |
| 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/example/bridge_example" | |
| run: | | |
| dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} | |
| flutter test integration_test -d macos | |
| bridge_example_ios: | |
| name: Test Bridge example on iOS (Python ${{ matrix.python_version }}) | |
| runs-on: macos-26 | |
| timeout-minutes: 25 | |
| if: false # see `macos:` for rationale | |
| 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 | |
| # serious_python_darwin's prepare_ios.sh downloads python-ios-dart-<ver>.tar.gz | |
| # (~100MB) into src/serious_python_darwin/darwin/dist_ios/ and skips the | |
| # download if the directory already exists. Cache it so reruns and | |
| # subsequent matrix jobs don't re-fetch from GitHub Releases. | |
| - name: Cache iOS Python framework | |
| uses: actions/cache@v4 | |
| with: | |
| path: src/serious_python_darwin/darwin/dist_ios | |
| key: ios-python-dist-${{ matrix.python_version }}-v2 | |
| - name: Setup iOS Simulator | |
| id: simulator | |
| uses: futureware-tech/simulator-action@v4 | |
| with: | |
| model: 'iPhone 17 Pro Max' | |
| os: "iOS" | |
| os_version: "26.5" | |
| shutdown_after_job: true | |
| wait_for_boot: true | |
| - name: Package + run integration test | |
| working-directory: "src/serious_python/example/bridge_example" | |
| run: | | |
| ts() { date '+%H:%M:%S'; } | |
| echo "[$(ts)] >>> dart run serious_python:main package" | |
| # 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 | |
| echo "[$(ts)] >>> flutter test integration_test" | |
| flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} | |
| echo "[$(ts)] >>> done" | |
| bridge_example_android: | |
| name: Test Bridge example on Android (Python ${{ matrix.python_version }}) | |
| runs-on: ubuntu-latest | |
| if: false # see `macos:` for rationale | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # x86_64 matches the emulator architecture; 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: 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/example/bridge_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} | |
| cd src/serious_python/example/bridge_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} | |
| - name: Diagnostics on failure | |
| if: failure() | |
| shell: bash | |
| run: | | |
| set +e | |
| REPO="$GITHUB_WORKSPACE" | |
| ABI=x86_64 | |
| echo "=== serious_python_android/android/src/main/jniLibs/$ABI/ ===" | |
| ls -la "$REPO/src/serious_python_android/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" | |
| echo | |
| echo "=== example/build/app/outputs/apk/debug/*.apk ===" | |
| APK=$(find "$REPO/src/serious_python/example/bridge_example/build" -name "*-debug.apk" 2>/dev/null | head -n1) | |
| echo "APK: $APK" | |
| if [ -n "$APK" ]; then | |
| echo "Native libs inside APK:" | |
| unzip -l "$APK" | grep -E "lib/$ABI/" || echo "(no lib/$ABI/ entries)" | |
| fi | |
| bridge_example_windows: | |
| name: Test Bridge example on Windows (Python ${{ matrix.python_version }}) | |
| runs-on: windows-latest | |
| if: false # see `macos:` for rationale | |
| 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/example/bridge_example" | |
| shell: bash | |
| run: | | |
| dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} | |
| # bash + pipefail so the test step actually fails when flutter fails | |
| # (default PowerShell shell on windows runners eats the failure when | |
| # piping into tail). | |
| set -o pipefail | |
| flutter test integration_test -d windows -v 2>&1 | tail -300 | |
| - name: Diagnostics on failure | |
| if: failure() | |
| shell: bash | |
| working-directory: "src/serious_python/example/bridge_example" | |
| run: | | |
| set +e | |
| DBG_DIR=build/windows/x64/runner/Debug | |
| echo "=== runner/Debug dir ===" | |
| ls -la $DBG_DIR/ || true | |
| echo | |
| echo "=== dart_bridge*.dll bundled? ===" | |
| ls -la $DBG_DIR/dart_bridge*.dll || echo "(no dart_bridge dll bundled)" | |
| echo | |
| echo "=== runner/Debug/Lib (Python stdlib) ===" | |
| ls $DBG_DIR/Lib | head -20 || true | |
| echo | |
| echo "=== runner/Debug/site-packages ===" | |
| ls -la $DBG_DIR/site-packages/ || true | |
| bridge_example_linux: | |
| name: Test Bridge example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) | |
| runs-on: ${{ matrix.runner }} | |
| if: false # see `macos:` for rationale | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python_version: ['3.12', '3.13', '3.14'] | |
| arch: [amd64, arm64] | |
| include: | |
| - arch: amd64 | |
| runner: ubuntu-24.04 | |
| title: AMD64 | |
| - arch: arm64 | |
| runner: ubuntu-24.04-arm | |
| title: ARM64 | |
| env: | |
| SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - 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: Package + run integration test | |
| working-directory: src/serious_python/example/bridge_example | |
| run: | | |
| flutter pub get | |
| dart run serious_python:main package app/src \ | |
| --platform Linux \ | |
| --python-version ${{ matrix.python_version }} | |
| set -o pipefail | |
| xvfb-run flutter test integration_test -d linux -v 2>&1 | tail -300 | |
| - name: Diagnostics on failure | |
| if: failure() | |
| working-directory: src/serious_python/example/bridge_example | |
| run: | | |
| set +e | |
| DBG_DIR=build/linux/${{ matrix.arch == 'arm64' && 'arm64' || 'x64' }}/debug/bundle | |
| echo "=== bundle dir ===" | |
| ls -la $DBG_DIR/ 2>/dev/null | |
| echo | |
| echo "=== bundle/lib (bundled shared libs) ===" | |
| ls -la $DBG_DIR/lib/ 2>/dev/null | |
| echo | |
| echo "=== readelf -d on libdart_bridge.so ===" | |
| readelf -d $DBG_DIR/lib/libdart_bridge.so 2>/dev/null | grep -E "NEEDED|libpython" || echo "(libdart_bridge.so not found)" | |
| echo | |
| echo "=== bundle data/flutter_assets/native_assets/linux/ ===" | |
| ls -la $DBG_DIR/data/flutter_assets/native_assets/linux/ 2>/dev/null | |
| echo | |
| echo "=== Python stdlib dir ===" | |
| ls -d $DBG_DIR/python3.* 2>/dev/null | head -5 | |
| publish: | |
| name: Publish to pub.dev | |
| needs: | |
| - macos | |
| - ios | |
| - android | |
| - windows | |
| - linux | |
| - bridge_example_macos | |
| - bridge_example_ios | |
| - bridge_example_android | |
| - bridge_example_linux | |
| - bridge_example_windows | |
| runs-on: ubuntu-22.04 | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v6 | |
| - name: Setup Flutter | |
| uses: kuhnroyal/flutter-fvm-config-action/setup@v3 | |
| with: | |
| path: '.fvmrc' | |
| cache: true | |
| - name: Compute PKG_VER | |
| run: | | |
| if [[ "$GITHUB_REF" == refs/tags/* ]]; then | |
| # Extract the tag name | |
| tag="${GITHUB_REF#refs/tags/}" | |
| # Remove leading "v" if present | |
| PKG_VER="${tag#v}" | |
| else | |
| # Get the latest tag, or fall back to "v0.0.0" if none exist | |
| cv=$(git describe --abbrev=0 2>/dev/null || echo "v0.0.0") | |
| # Remove leading "v" if present | |
| cv=${cv#v} | |
| # Split into major/minor components | |
| major=$(echo "$cv" | cut -d. -f1) | |
| minor=$(echo "$cv" | cut -d. -f2) | |
| # Construct the package version | |
| PKG_VER="${major}.${minor}.${GITHUB_RUN_NUMBER}" | |
| fi | |
| export PKG_VER | |
| echo "PKG_VER=$PKG_VER" | tee -a "$GITHUB_ENV" | |
| - name: Configure pub.dev credentials | |
| run: | | |
| mkdir -p $HOME/.config/dart | |
| echo "${{ secrets.PUB_DEV_TOKEN }}" | base64 --decode > $HOME/.config/dart/pub-credentials.json | |
| - name: Patch pubspec versions | |
| working-directory: "src" | |
| run: | | |
| for pkg in \ | |
| "serious_python" \ | |
| "serious_python_platform_interface" \ | |
| "serious_python_android" \ | |
| "serious_python_darwin" \ | |
| "serious_python_windows" \ | |
| "serious_python_linux"; do | |
| uv run "$SCRIPTS/patch_pubspec.py" "$pkg/pubspec.yaml" "$PKG_VER" | |
| done | |
| - name: Publish packages | |
| run: | | |
| publish_pkg () { | |
| pushd "$1" >/dev/null | |
| dart pub publish --force | |
| popd >/dev/null | |
| } | |
| publish_pkg src/serious_python_platform_interface | |
| sleep 600 | |
| publish_pkg src/serious_python_android | |
| publish_pkg src/serious_python_darwin | |
| publish_pkg src/serious_python_windows | |
| publish_pkg src/serious_python_linux | |
| sleep 600 | |
| publish_pkg src/serious_python |