@@ -31,42 +31,31 @@ permissions:
3131 packages : write
3232
3333# Runner strategy:
34- # - Linux + Android + mipsel: self-hosted (mhrv-hetzner-*, Hetzner
35- # 8-core / 31 GB Ubuntu 24.04 box with
36- # Rust, Android SDK+NDK, Docker, all
37- # cross-compile toolchains pre-installed).
38- # Two runners registered for parallelism.
39- # - macOS arm64 + amd64, Windows: GitHub-hosted (we don't self-host those
40- # OSes; the free minutes on a public repo
41- # are plenty for those two platforms).
34+ # - Linux + Android + mipsel: GitHub-hosted Ubuntu runners.
35+ # - macOS arm64 + amd64, Windows: GitHub-hosted native OS runners.
4236#
43- # Why self-hosted: GH-hosted 2-core runners were spending ~13 min cold per
44- # release; on the Hetzner box a cold linux-amd64 build is 1m9s, and warm
45- # builds with Swatinem/rust-cache are sub-minute. Keeps the toolchain warm,
46- # and more importantly keeps target/ warm via the rust-cache action.
37+ # Why hosted: the repo no longer keeps persistent release builders
38+ # registered. Each release job provisions only the tools it needs, while
39+ # Swatinem/rust-cache keeps target/ and cargo registry rebuild cost sane.
4740
4841jobs :
4942 build :
5043 strategy :
5144 fail-fast : false
5245 matrix :
5346 include :
54- # Pin to Ubuntu 22.04 GLIBC target (GLIBC 2.35) so the glibc builds
55- # load on any distro ≥ Ubuntu 22.04 / Debian 12 / Mint 21 / Fedora 36.
56- # On self-hosted this is a Rust-side choice (cargo target triple),
57- # not an OS-of-the-runner choice — the runner itself is Ubuntu 24.04
58- # (GLIBC 2.39), but we link against the 2.35-era glibc via the
59- # x86_64-unknown-linux-gnu target triple which pins to the oldest
60- # GLIBC symbol version rustc is willing to emit. Users behind tight
61- # internet who can't dist-upgrade keep working.
47+ # Pin the runner to Ubuntu 22.04 and use the
48+ # x86_64-unknown-linux-gnu target so glibc builds stay compatible
49+ # with Ubuntu 22.04 / Debian 12 / Mint 21 / Fedora 36 era systems.
50+ # Users behind tight internet who can't dist-upgrade keep working.
6251 - target : x86_64-unknown-linux-gnu
63- os : [self-hosted, linux, x64, mhrv-build]
52+ os : ubuntu-22.04
6453 name : mhrv-rs-linux-amd64
6554 - target : aarch64-unknown-linux-gnu
66- os : [self-hosted, linux, x64, mhrv-build]
55+ os : ubuntu-22.04
6756 name : mhrv-rs-linux-arm64
6857 - target : arm-unknown-linux-gnueabihf
69- os : [self-hosted, linux, x64, mhrv-build]
58+ os : ubuntu-22.04
7059 name : mhrv-rs-raspbian-armhf
7160 - target : x86_64-apple-darwin
7261 os : macos-latest
@@ -89,10 +78,10 @@ jobs:
8978 # x86_64-pc-windows-gnu (windows-amd64) which covers ~99% of
9079 # active Windows installs (incl. all WoA64 emulation).
9180 - target : x86_64-unknown-linux-musl
92- os : [self-hosted, linux, x64, mhrv-build]
81+ os : ubuntu-22.04
9382 name : mhrv-rs-linux-musl-amd64
9483 - target : aarch64-unknown-linux-musl
95- os : [self-hosted, linux, x64, mhrv-build]
84+ os : ubuntu-22.04
9685 name : mhrv-rs-linux-musl-arm64
9786 # OpenWRT MT7621 (soft-float mipsel 32-bit). Dozens of cheap
9887 # home routers run this chipset and they *specifically* need
10392 # `continue-on-error: true` so a regression here doesn't block
10493 # the rest of the release. Issue #26.
10594 - target : mipsel-unknown-linux-musl
106- os : [self-hosted, linux, x64, mhrv-build]
95+ os : ubuntu-22.04
10796 name : mhrv-rs-openwrt-mipsel-softfloat
10897 mipsel_softfloat : true
10998
@@ -114,26 +103,6 @@ jobs:
114103 continue-on-error : ${{ matrix.mipsel_softfloat == true }}
115104
116105 steps :
117- # Heal any root-owned leftovers from a previous mipsel docker
118- # build that failed before its post-step chown could run. The
119- # docker container writes target/ as root, and if cargo errors
120- # inside the container the outer `sudo chown -R` line never
121- # executes (bash -e exits on the docker non-zero), leaving root-
122- # owned files that fail every subsequent `actions/checkout@v4`
123- # workspace clean with `EACCES: permission denied unlink`. This
124- # step is a no-op on a clean runner, so cheap to keep always-on.
125- # Self-hosted only; GitHub-hosted runners get a fresh VM each run.
126- - name : Pre-checkout — clean root-owned files (self-hosted only)
127- if : contains(matrix.os, 'self-hosted')
128- run : |
129- if [ -d "$GITHUB_WORKSPACE/target" ]; then
130- sudo rm -rf "$GITHUB_WORKSPACE/target" || true
131- fi
132- # Stale .rustc_info.json at the workspace root is the
133- # specific file `actions/checkout` errors on; nuke any
134- # other root-owned scraps that may be sitting there too.
135- sudo find "$GITHUB_WORKSPACE" -maxdepth 2 -uid 0 -exec rm -rf {} + 2>/dev/null || true
136-
137106 - uses : actions/checkout@v4
138107
139108 # Skip the host-level rustup install for mipsel-softfloat — that
@@ -145,10 +114,6 @@ jobs:
145114 # 'mipsel-unknown-linux-musl' is unavailable for download", which
146115 # fails the job before the docker step ever runs.
147116 #
148- # On self-hosted this action is mostly a no-op: rustup is already
149- # installed and the standard target triples are pre-added. It
150- # still verifies the target is present and is cheap enough to keep
151- # as a safety net.
152117 # Per-matrix-entry toolchain selection. Default is `stable` (latest)
153118 # for every target except where `rust_toolchain` is explicitly pinned
154119 # — currently just i686-pc-windows-msvc, which needs 1.77.2 to keep
@@ -159,19 +124,9 @@ jobs:
159124 toolchain : ${{ matrix.rust_toolchain || 'stable' }}
160125 targets : ${{ matrix.target }}
161126
162- # Cache target/ + cargo registry across runs — this is the big
163- # self-hosted speedup. Without it, actions/checkout@v4's default
164- # `git clean -ffdx` wipes target/ between runs and every build is
165- # cold. With it, warm builds are sub-minute even for the full
166- # release profile.
167- #
168- # cache-bin: false is MANDATORY on our self-hosted runners. With
169- # the default (true), rust-cache aggressively prunes $CARGO_HOME/bin
170- # of binaries it didn't install via `cargo install`, including the
171- # `rustup` binary that cargo/rustc/etc. are symlinked to. The next
172- # job then hits "command not found" or a broken-symlink TOML parse
173- # error from a stale cargo. We want target/ + registry caching, NOT
174- # bin pruning. rustup is pre-installed on the runners anyway.
127+ # Cache target/ + cargo registry across runs. cache-bin: false keeps
128+ # the cache focused on build artifacts and registry state instead of
129+ # pruning tool binaries installed by setup actions.
175130 - uses : Swatinem/rust-cache@v2
176131 if : matrix.mipsel_softfloat != true
177132 with :
@@ -182,13 +137,11 @@ jobs:
182137 key : ${{ matrix.target }}-${{ matrix.rust_toolchain || 'stable' }}
183138 cache-bin : " false"
184139
185- # eframe needs a few system libs on Linux for window management, keyboard,
186- # and OpenGL/X11/Wayland. Gated to GitHub-hosted runners only — the
187- # self-hosted runners pre-install all of these once at setup time, and
188- # letting multiple parallel matrix jobs race on `sudo apt-get install`
189- # fights over /var/lib/apt/lists/lock and fails them all.
140+ # eframe needs a few system libs on Linux for window management,
141+ # keyboard, and OpenGL/X11/Wayland. Only the x86_64 GNU Linux job
142+ # builds the UI on Linux, so the cross and musl jobs skip this.
190143 - name : Install Linux eframe system deps
191- if : runner.os == 'Linux' && runner.environment == 'github-hosted '
144+ if : matrix.target == 'x86_64-unknown-linux-gnu '
192145 run : |
193146 sudo apt-get update
194147 sudo apt-get install -y \
@@ -198,24 +151,22 @@ jobs:
198151 libx11-dev \
199152 libgl1-mesa-dev libglib2.0-dev libgtk-3-dev
200153
201- # Cross-compile toolchains. Same story as above — gated to hosted
202- # runners; self-hosted has gcc-aarch64-linux-gnu + gcc-arm-linux-gnueabihf
203- # pre-installed, and the linker entries live in
204- # /home/ghrunner/cargo-{01,02}/config.toml (seeded once at runner
205- # setup time, picked up via CARGO_HOME env).
154+ # Cross-compile toolchains for hosted Ubuntu runners.
206155 - name : Install aarch64 cross-compile toolchain (Linux only)
207- if : matrix.target == 'aarch64-unknown-linux-gnu' && runner.environment == 'github-hosted'
156+ if : matrix.target == 'aarch64-unknown-linux-gnu'
208157 run : |
209158 sudo apt-get update
210159 sudo apt-get install -y gcc-aarch64-linux-gnu
160+ mkdir -p ~/.cargo
211161 echo '[target.aarch64-unknown-linux-gnu]' >> ~/.cargo/config.toml
212162 echo 'linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config.toml
213163
214164 - name : Install armhf cross-compile toolchain (Linux only)
215- if : matrix.target == 'arm-unknown-linux-gnueabihf' && runner.environment == 'github-hosted'
165+ if : matrix.target == 'arm-unknown-linux-gnueabihf'
216166 run : |
217167 sudo apt-get update
218168 sudo apt-get install -y gcc-arm-linux-gnueabihf
169+ mkdir -p ~/.cargo
219170 echo '[target.arm-unknown-linux-gnueabihf]' >> ~/.cargo/config.toml
220171 echo 'linker = "arm-linux-gnueabihf-gcc"' >> ~/.cargo/config.toml
221172
@@ -284,11 +235,10 @@ jobs:
284235 # Always chown back, even if docker exits non-zero. The previous
285236 # form (`docker run …; sudo chown …`) ran chown only on success
286237 # because bash -e short-circuits on the docker failure; that
287- # left target/ root-owned and broke `actions/checkout@v4` on
288- # every subsequent self-hosted run with EACCES on
289- # target/.rustc_info.json. The `trap … EXIT` runs the chown
290- # whether docker succeeded or failed, so a transient mipsel
291- # compile regression never poisons the runner workspace.
238+ # left target/ root-owned for later steps in the same job. The
239+ # `trap … EXIT` runs the chown whether docker succeeded or failed,
240+ # so a transient mipsel compile regression never poisons the
241+ # workspace.
292242 set +e
293243 trap 'sudo chown -R "$(id -u):$(id -g)" target 2>/dev/null || true' EXIT
294244 docker run --rm -v "$PWD":/src -w /src \
@@ -408,24 +358,21 @@ jobs:
408358 # x86_64, x86) via cargo-ndk and drops the .so files into the Gradle
409359 # project's jniLibs/ tree, which then packages them into a single
410360 # universal APK. Users pick it once, no per-ABI split.
411- #
412- # Runs on self-hosted. The runner has Android SDK + NDK r26c + cargo-ndk
413- # pre-installed under /opt/android-sdk; the env block below points Gradle
414- # at those paths so we don't re-download ~1 GB of SDK per release.
415361 android :
416- runs-on : [self-hosted, linux, x64, mhrv-build]
362+ runs-on : ubuntu-latest
417363 env :
418- ANDROID_SDK_ROOT : /opt/android-sdk
419- ANDROID_HOME : /opt/android-sdk
420- ANDROID_NDK_HOME : /opt/android-sdk/ndk/26.2.11394342
421- ANDROID_NDK_ROOT : /opt/android-sdk/ndk/26.2.11394342
422- JAVA_HOME : /usr/lib/jvm/java-17-openjdk-amd64
364+ ANDROID_SDK_ROOT : /usr/local/lib/android/sdk
365+ ANDROID_HOME : /usr/local/lib/android/sdk
366+ ANDROID_NDK_HOME : /usr/local/lib/android/sdk/ndk/26.2.11394342
367+ ANDROID_NDK_ROOT : /usr/local/lib/android/sdk/ndk/26.2.11394342
423368 steps :
424369 - uses : actions/checkout@v4
425370
426- # Rust toolchain: idempotent on self-hosted (targets already present),
427- # kept here so the workflow still works if we ever run it on a GH-hosted
428- # fallback.
371+ - uses : actions/setup-java@v4
372+ with :
373+ distribution : temurin
374+ java-version : ' 17'
375+
429376 - uses : dtolnay/rust-toolchain@stable
430377 with :
431378 targets : aarch64-linux-android,armv7-linux-androideabi,x86_64-linux-android,i686-linux-android
@@ -434,9 +381,6 @@ jobs:
434381 # release builds back-to-back with LTO is where the cold cost comes
435382 # from; rust-cache brings warm runs down to ~3–4 min from ~9 min cold.
436383 # cache-bin: false — see the rationale on the matrix build job above.
437- # On top of that, `cargo-ndk` lives in /usr/local/bin/ on our runners
438- # (not $CARGO_HOME/bin), specifically so rust-cache's default bin
439- # pruning can't delete it.
440384 - uses : Swatinem/rust-cache@v2
441385 with :
442386 key : android-universal
@@ -446,6 +390,11 @@ jobs:
446390 workspaces : |
447391 . -> target
448392
393+ - name : Install Android NDK and cargo-ndk
394+ run : |
395+ yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;26.2.11394342"
396+ cargo install cargo-ndk --locked
397+
449398 # `./gradlew :app:assembleRelease` triggers cargoBuildRelease first
450399 # which invokes cargo-ndk with all four targets, then Gradle packages
451400 # the APK (release buildType signed with the committed release.jks —
@@ -583,11 +532,8 @@ jobs:
583532 cache-from : type=gha
584533 cache-to : type=gha,mode=max
585534
586- # release + telegram: lightweight aggregation jobs kept on GH-hosted
587- # ubuntu-latest. They only download artifacts and call APIs — no build
588- # tooling needed, no benefit from moving to self-hosted, and keeping them
589- # off the self-hosted runners avoids contention with Linux build jobs from
590- # the next tag if two releases overlap.
535+ # release + telegram: lightweight aggregation jobs on GitHub-hosted
536+ # ubuntu-latest. They only download artifacts and call APIs.
591537 release :
592538 needs : [build, android]
593539 runs-on : ubuntu-latest
0 commit comments