If KEYSTORE_BASE64 is unset, base64 -d writes an empty file silently,
cargo ndk then spends ~7 min compiling all ABIs, and only then does
apksigner fail. Add a size check after decode so the job fails in
seconds with a clear error message instead of wasting a full build.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The runner LXC was bumped from ~56 GB to 106 GB, giving ~70 GB of free
space — well above the ~40 GB a full 3-ABI release build needs. Revert
the disk-budget workarounds added in ab35fcf:
- Remove "Free disk space" step (no longer needed)
- Restore x86_64 target (arm64-v8a + armeabi-v7a + x86_64)
- Remove ABIS override so build script uses its full default set
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run 181 (v0.25.0 tag) failed at "Build signed release APK" after ~7 min —
same disk-exhaustion pattern that hit the debug build. The debug workflow
was already fixed to arm64-v8a only; the release workflow still built all 3
ABIs and exceeded the runner's disk budget.
Changes:
- Add "Free disk space" step before system deps: removes /usr/local/lib/android,
/usr/share/dotnet, /opt/ghc, /usr/local/share/boost (~10 GB reclaimed).
- Limit ABIS to arm64-v8a + armeabi-v7a (drops x86_64, which is emulator-only).
- Remove x86_64 from rustup target add to match.
arm64-v8a covers all modern Android devices; armeabi-v7a covers legacy ARM.
x86_64 can be re-added later if a simulator-targeted test build is needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- default_theme_id() returns "dark" (was briefly "classic" after the
rename commit 20b7a61)
- sanitized() migrates "default" and "classic" → "dark" so existing
settings.json files are upgraded automatically on next launch
- Registry lists Dark first so the Settings picker opens with it at top
- Classic remains available as an option in the picker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The disk-budget fix worked — debug APK now builds, signs, and verifies
in ~6 minutes on a single ABI. But the upload step failed with:
GHESNotSupportedError: @actions/artifact v2.0.0+, upload-artifact@v4+
and download-artifact@v4+ are not currently supported on GHES.
upload-artifact@v4 rewrote the upload path to use a new artifact
service hosted on github.com; Gitea's GHES-compatibility layer doesn't
implement that endpoint. v3 still uses the older chunked HTTP upload
API that Gitea supports.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous run got all the way through compile + link + zipalign and
then died inside apksigner with `IOException: No space left on device`.
Cross-compiling all three Android ABIs (arm64-v8a, armeabi-v7a, x86_64)
in debug mode blows target/ past 25 GB, and by the time apksigner is
streaming the signed APK to disk the runner has nothing left.
Two changes:
1. build_android_apk.sh now reads `ABIS` from the environment (defaults
to all three for backwards compat) and uses it to assemble the
cargo-ndk `-t` flags.
2. android-build.yml passes ABIS=arm64-v8a, since the debug artifact
is consumed by adb-installing to a single arm64 device and the
other two ABIs were dead weight.
Also frees \$STAGING/app-unsigned.apk right after zipalign so it's not
sitting next to the aligned APK and the output APK during signing.
Release workflow is untouched — release APKs still ship all three ABIs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cargo-apk 0.10 and its fork cargo-apk2 both failed to discover the
installed Android platform in this Gitea runner, despite ANDROID_HOME,
platforms;android-34, build-tools, and NDK all being present, readable,
and pointed at correctly. We never isolated whether the bug is in the
shared ndk-build crate's discovery logic or in the runner's env-var
propagation through cargo subcommand exec, so this commit stops fighting
either tool and assembles the APK from explicit toolchain steps instead:
cargo ndk -> per-ABI .so files
aapt2 compile/link -> manifest + resources -> base APK
zip -> bundle native libs into lib/<abi>/
zipalign -> 4-byte alignment
apksigner -> v2/v3 signing (debug keystore for CI, real for release)
The pipeline lives in scripts/build_android_apk.sh so it's reproducible
locally (same env vars, same commands). AndroidManifest.xml is now
checked in under solitaire_app/android/ and mirrors what cargo-apk would
have generated from [package.metadata.android] — keep them in sync if
either is changed. Local `cargo apk build` still works on developer
machines where cargo-apk is happy; CI just stops depending on it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
cargo-apk 0.10.0 has been unable to discover an installed Android
platform in this runner environment despite ANDROID_HOME, NDK,
build-tools, and platforms;android-34 all being present and readable.
cargo-apk2 is the maintained community fork on crates.io that reads
the same `[package.metadata.android]` block, so the solitaire_app
Cargo.toml needs no changes. Cache keys updated to apk2- so we don't
restore the broken cargo-apk binary from prior runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirror the fix from android-build.yml: rename ANDROID_HOME -> ANDROID_SDK
in the env block to avoid the Docker-image-baked ANDROID_HOME overriding
the workflow value in run scripts. Use ${{ env.ANDROID_SDK }} template
expressions throughout, and explicitly export ANDROID_HOME/ANDROID_NDK_HOME
before cargo-apk build so it finds the SDK at the right path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace shell variable $ANDROID_HOME references in run blocks with
${{ env.ANDROID_SDK }} template expressions. Gitea runner v1 may not
override Docker-image-baked ENV vars via docker exec; template expansion
happens at workflow compilation time, so the literal path is hardcoded
into the script before the shell runs it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove SDK detection logic and install directly to /opt/android-sdk,
matching the release workflow. The container Docker image has ANDROID_HOME
baked in at /usr/local/lib/android/sdk; installing there with sudo while
cargo-apk resolves ANDROID_HOME from the image ENV created a divergence.
Using a controlled path we own eliminates that class of conflict entirely.
Add SDK cache shared with the release workflow (same key prefix v2-).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ANDROID_SDK_ROOT was never set; zipalign and apksigner were resolving
to empty paths and would fail. All three occurrences replaced with
ANDROID_HOME which is defined in the workflow env block.
Also adds sudo to the cache-miss SDK install (mkdir/mv/sdkmanager) to
match the debug workflow pattern — /opt/android-sdk requires root on
a fresh runner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Classic SVGs and manifest are now compiled in via include_bytes!(),
making the theme available on all platforms (desktop, Android) without
requiring filesystem assets. Removes the now-redundant Dockerfile COPY
of solitaire_engine/assets/themes/classic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
solitaire_engine/assets/themes/classic/ was absent from the container
because only the workspace-root assets/ directory was copied. The
AssetServer serves themes/classic/ from that same root, so the classic
theme manifested as a missing-asset load failure at runtime.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename assets/themes/default/ → assets/themes/dark/; update theme.ron
id/name to "dark"/"Dark"
- Rename all DEFAULT_THEME_* constants → DARK_THEME_* and
default_theme_svg_bytes / populate_embedded_default_theme → dark_*
- Add bundled_theme_url() helper for URL resolution without needing the
registry (used by Startup systems where ordering isn't guaranteed)
- Registry now lists Classic first (new player default), Dark second
- settings.rs default_theme_id() returns "classic" so fresh installs
start on the white card theme
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
White/cream card faces with traditional red (hearts/diamonds) and black
(clubs/spades) colours, plus a navy diamond-pattern card back. Shipped
as a bundled AssetServer theme alongside the existing Default theme.
Registry updated to include the Classic entry; registry tests updated
to reflect the new BUNDLED_COUNT of 2.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>