ci: run on the self-hosted x86_64 runner and drop the toolchain installers
Targets runs-on: flutter-android for both jobs. Since that runner is host mode with the toolchain preinstalled, subosito/flutter-action and actions/setup-java are removed — they would have downloaded a second Flutter and JDK over the ones being used, and CI would no longer be building with the toolchain the release was verified against. A Toolchain step fails loudly if flutter or ANDROID_HOME is missing rather than letting a later step fail obscurely. Documents in docs/README.md why the runner cannot be the Gitea host, what host mode trades away, and what each job protects — including why building the release APK is necessary but not sufficient, which is the reason the JNI name guard exists at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+17
-18
@@ -6,18 +6,28 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
|
# Both jobs target a self-hosted runner, by capability rather than by hostname.
|
||||||
|
# See tool/setup_ci_runner.sh for how that runner is provisioned and why it is
|
||||||
|
# not the Gitea host: Flutter cannot build an Android APK on a Linux arm64 host
|
||||||
|
# (flutter/flutter#189724), and the Gitea box is aarch64. The runner is
|
||||||
|
# registered at android-stuff org scope so any repo in the org can use it.
|
||||||
|
#
|
||||||
|
# The runner is host-mode, so Flutter, the JDK and the Android SDK/NDK are the
|
||||||
|
# machine's own — the same toolchain that produced the verified release, and no
|
||||||
|
# multi-hundred-MB download per run. Nothing here installs a toolchain; the
|
||||||
|
# Toolchain step fails loudly if one is missing.
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
name: Analyze & Test
|
name: Analyze & Test
|
||||||
runs-on: ubuntu-latest
|
runs-on: flutter-android
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: subosito/flutter-action@v2
|
- name: Toolchain
|
||||||
with:
|
run: |
|
||||||
flutter-version: '3.47.1'
|
flutter --version
|
||||||
channel: 'stable'
|
echo "ANDROID_HOME=${ANDROID_HOME:?not set on this runner}"
|
||||||
cache: true
|
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
@@ -32,21 +42,10 @@ jobs:
|
|||||||
|
|
||||||
release-apk:
|
release-apk:
|
||||||
name: Release APK
|
name: Release APK
|
||||||
runs-on: ubuntu-latest
|
runs-on: flutter-android
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: '17'
|
|
||||||
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
with:
|
|
||||||
flutter-version: '3.47.1'
|
|
||||||
channel: 'stable'
|
|
||||||
cache: true
|
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
|
|
||||||
|
|||||||
@@ -183,6 +183,41 @@ Dart uses `Completer<Iperf3Result>` to await native completion. The MethodChanne
|
|||||||
| `isTestRunning()` | `isTestRunning` | Check if test is in progress |
|
| `isTestRunning()` | `isTestRunning` | Check if test is in progress |
|
||||||
| `setTempDir(String)` | `setTempDir` | Point `mkstemp()` at the app cache dir |
|
| `setTempDir(String)` | `setTempDir` | Point `mkstemp()` at the app cache dir |
|
||||||
|
|
||||||
|
## CI
|
||||||
|
|
||||||
|
Both jobs run on a **self-hosted runner registered at `android-stuff` org scope**,
|
||||||
|
targeted by the capability label `flutter-android` rather than by hostname.
|
||||||
|
`tool/setup_ci_runner.sh` provisions it.
|
||||||
|
|
||||||
|
It does not run on the Gitea host. Gitea lives on an aarch64 box, and Flutter
|
||||||
|
cannot build an Android APK on a Linux arm64 host at all — the SDK ships no
|
||||||
|
arm64-host `gen_snapshot` ([flutter#189724](https://github.com/flutter/flutter/issues/189724),
|
||||||
|
[#75864](https://github.com/flutter/flutter/issues/75864), open as of July 2026).
|
||||||
|
An x86_64 runner is a requirement, not a preference.
|
||||||
|
|
||||||
|
The runner is **host mode**: jobs use the machine's own Flutter, JDK and Android
|
||||||
|
SDK/NDK. That means CI builds with the same toolchain that produced the verified
|
||||||
|
release, and no NDK download per run. The trade is isolation — workflows run as
|
||||||
|
that user on that machine — so the runner is only for repos whose workflows are
|
||||||
|
trusted.
|
||||||
|
|
||||||
|
Two jobs:
|
||||||
|
|
||||||
|
| Job | What it protects |
|
||||||
|
|---|---|
|
||||||
|
| `analyze` | `flutter analyze`, then `flutter test` — which includes `architecture_test.dart`, failing the build if a layer boundary is crossed |
|
||||||
|
| `release-apk` | builds the **minified** APK and runs `tool/check_jni_keep_rules.sh` |
|
||||||
|
|
||||||
|
The second exists because of a specific escape. A release APK that aborted on
|
||||||
|
every test shipped once, while every on-device check passed — because those
|
||||||
|
checks all used the debug build, which does not minify. Building the release APK
|
||||||
|
is necessary but not sufficient: a renamed JNI callback still produces a
|
||||||
|
*successful build* and a broken app. So the guard reads R8's `mapping.txt` for
|
||||||
|
the callback classes and methods, and the DEX string pool for the native entry
|
||||||
|
points. It is verified to fail: delete the keep rules from
|
||||||
|
`android/app/proguard-rules.pro`, rebuild, and it reports `MainThreadCallback`,
|
||||||
|
`onOutput`, `onError` and `onComplete` renamed.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
|
|||||||
Reference in New Issue
Block a user