This repository uses two classes of GitHub Actions:
- GitHub-hosted checks for fast, free, public-repository validation.
- Self-hosted workflows for the expensive Flutter Engine build and Android tablet smoke tests.
The goal is to keep pull requests cheap and safe while still making release builds reproducible.
This is a public open-source repository, so standard GitHub-hosted runner
minutes are free for the lightweight CI and Release check workflows. The
self-hosted build/device workflows also do not consume GitHub-hosted runner
minutes.
That does not mean Actions are unlimited:
- GitHub still enforces workflow, queue, API, concurrency, cache, and artifact limits. For example, GitHub-hosted jobs have a 6-hour execution limit, and self-hosted jobs have a 5-day execution limit.
- Larger GitHub-hosted runners are charged even for public repositories.
- Artifacts and caches should be kept small and short-lived. Large
.debrelease payloads belong in GitHub Releases, not as long-retained workflow artifacts. - Self-hosted runner capacity is limited by the maintainer's own WSL/Windows machine, disk space, tablet availability, and network.
References:
| Workflow | File | Runner | Trigger | Purpose |
|---|---|---|---|---|
| CI | .github/workflows/ci.yml |
ubuntu-latest |
PR, push to master, manual |
Python/shell/PowerShell syntax, package/docs/workflow sanity, whitespace checks |
| Build deb | .github/workflows/build-deb.yml |
self-hosted Linux/WSL | manual | Full build.py pipeline, .deb packaging, optional release publishing |
| Device smoke | .github/workflows/device-smoke.yml |
self-hosted Windows + ADB tablet | manual | Install deb in Termux, run post_install.sh, flutter doctor, create/build APK/Linux smoke |
| Release check | .github/workflows/release-check.yml |
ubuntu-latest |
release publish/edit, manual | Verify release asset name, size, and SHA256 digest |
Public repositories can use standard GitHub-hosted runners for free, but this project's full build is not a normal CI job:
gclient syncdownloads tens of GB.- Flutter Engine builds can take hours.
- The build needs Android NDK r27d at
/opt/android-ndk-r27d. - Real release confidence requires an attached Android/Termux tablet.
Therefore:
- PR CI must stay lightweight and never touch self-hosted device hardware.
- Full build and device smoke are manual self-hosted gates run by a maintainer.
- Release publishing is manual, not automatic on every merge to
master.
ci.yml runs on every PR and push to master:
python -m py_compile build.py package.py sysroot.py utils.py scripts/ci/check_repo.py
bash -n install_flutter_complete.sh scripts/install/*.sh scripts/test/gh_e2e_test.sh scripts/device/termux_smoke.sh
PowerShell parser check for scripts/device/run_termux_smoke.ps1
python scripts/ci/check_repo.py
git diff --check
check_repo.py validates repo-specific contracts, including:
- workflow YAML parses
- self-hosted workflows are not triggered by
pull_request package.yamlstill packagesdart,dartvm,dartaotruntime, andpost_installpost_install.shstill contains the Flutter 3.44PLATFORM_ABI_LISTand Android-host patches- installer defaults remain on Flutter 3.44.0 and NDK r29 for Termux installs
- release/download docs do not regress to stale 3.41.5 commands
Manual workflow: Build deb (self-hosted)
Default inputs:
flutter_version: 3.44.0
arch: arm64
runner_labels_json: ["self-hosted","linux"]
publish_release: false
release_tag: v3.44.0
Required self-hosted environment:
- Linux or WSL runner with enough disk space (100GB+ recommended)
- Python 3.12 available through
actions/setup-python /opt/android-ndk-r27dgit,curl,ninja,pkg-config, and normal build dependencies- network access for Flutter/Chromium/Termux downloads
The workflow bootstraps depot_tools if gclient is missing, then runs:
python3 build.py clone
python3 build.py sync
python3 build.py patch_engine
python3 build.py patch_dart
python3 build.py patch_skia
python3 build.py patch_flutter_sdk
python3 build.py build_all --arch=arm64
python3 build.py debuild --arch=arm64It uploads:
flutter_3.44.0_aarch64.debflutter_3.44.0_aarch64.deb.sha256flutter_3.44.0_aarch64.deb.size.txt
If publish_release=true, it creates or updates release_tag and uploads the deb with --clobber.
Merging to master does not publish a GitHub Release. The current release
flow is intentionally maintainer-triggered:
- Merge only after PR CI passes.
- Trigger Build deb (self-hosted) manually on the chosen commit/tag.
- Leave
publish_release=falsefor a dry build, or setpublish_release=trueonly when intentionally publishing. - Run device smoke against the produced or published
.deb. - Let Release check verify the release asset metadata after publish/edit.
This avoids accidental multi-hour engine builds and prevents unreviewed merges from overwriting a public release asset. A future release pipeline may chain build → device smoke → publish, but the current project keeps publish as an explicit maintainer action.
Manual workflow: Device smoke (self-hosted)
Default input tests the published v3.44.0 release asset:
deb_url: https://github.com/ImL1s/termux-flutter-wsl/releases/download/v3.44.0/flutter_3.44.0_aarch64.deb
expected_sha256: b8af08d26ee4ae4b3dcf1aab4ee6b05965529587ddf1bc9b936b48b5f01f9846
Required self-hosted environment:
- Windows runner with ADB installed
- Android tablet connected and authorized for USB debugging
- Termux installed and launchable as
com.termux - Tablet awake/unlocked before the run; secure lock screens block ADB text injection into Termux
- Enough tablet storage for the deb, Android SDK/NDK, Gradle caches, APK, and Linux build
The PowerShell driver intentionally keeps the tablet awake:
adb shell svc power stayon true
adb shell input keyevent 224
adb shell wm dismiss-keyguardIt then pushes the deb and scripts/device/termux_smoke.sh, launches Termux, injects:
sh /sdcard/Download/termux_ci_smoke.sh
and polls /sdcard/Download/termux_ci_smoke.txt until DONE or timeout.
Required success markers:
INSTALL_STATUS=0
POST_INSTALL_STATUS=0
FLUTTER_VERSION_STATUS=0
DART_VERSION_STATUS=0
DARTVM_VERSION_STATUS=0
DOCTOR_STATUS=0
CREATE_STATUS=0
BUILD_APK_STATUS=0
BUILD_LINUX_STATUS=0
DONE
The workflow turns svc power stayon back off before exiting.
release-check.yml verifies release metadata from GitHub:
- expected tag exists
- expected asset exists
- asset size is plausible
- asset digest matches the expected SHA256 when GitHub exposes the digest
This workflow is safe to run on GitHub-hosted runners because it only reads public release metadata.
- Fork PRs only get
ci.ymlon GitHub-hosted runners. - Self-hosted build/device workflows are
workflow_dispatchonly. - Device smoke does not run untrusted PR code automatically.
- Release publishing requires
contents: writeand only happens from the manual self-hosted build workflow whenpublish_release=true.
Fast local checks:
python -m py_compile build.py package.py sysroot.py utils.py scripts/ci/check_repo.py
bash -n scripts/install/post_install.sh
python scripts/ci/check_repo.py
git diff --checkManual Termux release E2E test inside Termux:
bash scripts/test/gh_e2e_test.shManual Windows-to-tablet smoke:
scripts/device/run_termux_smoke.ps1 `
-AdbPath "C:\Users\aa223\AppData\Local\Android\Sdk\platform-tools\adb.exe" `
-DebUrl "https://github.com/ImL1s/termux-flutter-wsl/releases/download/v3.44.0/flutter_3.44.0_aarch64.deb"