From 3cda1a9bd4d699e7fc36de6f8b4bc4464f9779e6 Mon Sep 17 00:00:00 2001 From: ospab Date: Thu, 30 Jul 2026 20:43:55 +0300 Subject: [PATCH] ci: cache the GUI/Android Rust builds, and diagnose signing failures early Build-time work, plus a fix for the v0.4.2 Android signing failure. Caching. The three Tauri GUI jobs were the slowest in the matrix (up to 9m17s vs 2-5m for the plain release targets) for two compounding reasons: - No restore-keys. The cache key ends in hashFiles('**/Cargo.lock'), and cutting a release rewrites every Cargo.lock (version bump), so the exact key missed on every single release. With no prefix fallback the cache restored nothing at all and each release rebuilt the full dependency graph from scratch. The plain release targets had restore-keys all along, which is exactly why they were multiples faster. - Wrong path. ostp-gui/src-tauri is excluded from the workspace, so its build output lands in ostp-gui/src-tauri/target/, not the cached target/. The bulk of each GUI job's Rust work was therefore never cached even when the key did hit - visible in the cache sizes (25-30 MiB for the macOS and Linux GUI entries, against 150-220 MiB for real target/ caches). The Android jobs had no Rust cache whatsoever, and rebuilt cargo-ndk from source every run; both now cache, the latter mirroring how `cross` is already handled. Signing diagnostics. v0.4.2's Android jobs failed after four minutes of Gradle with "keystore password was incorrect". The keystore is now decoded with stray CR/LF stripped (a single trailing \r corrupts the decode) and validated with keytool up front, so a bad password or a missing alias fails in seconds with a message that says which. The printed size and SHA-256 disclose nothing secret and let the operator tell a mangled transfer apart from a genuinely wrong password. --- .github/workflows/release.yml | 71 +++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6a80342..95f0d8d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -378,7 +378,15 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ + ostp-gui/src-tauri/target/ key: cargo-windows-gui-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }} + # Without a prefix fallback this cache NEVER restored on a release: + # cutting a release rewrites every Cargo.lock (version bump), which + # changes hashFiles(), which misses the exact key — so each release + # rebuilt every dependency from scratch. That is why the GUI jobs ran + # 2-4x longer than the plain release targets, which had this all along. + restore-keys: | + cargo-windows-gui-${{ matrix.target }}- - name: Download wintun shell: pwsh @@ -460,7 +468,10 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ + ostp-gui/src-tauri/target/ key: cargo-linux-gui-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-linux-gui-${{ matrix.target }}- - name: Build Tauri App working-directory: ostp-gui @@ -522,7 +533,10 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ + ostp-gui/src-tauri/target/ key: cargo-macos-gui-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-macos-gui-${{ matrix.target }}- - name: Build Tauri App working-directory: ostp-gui @@ -587,8 +601,33 @@ jobs: with: ndk-version: r26b - - name: Install cargo-ndk - run: cargo install cargo-ndk + # The Android jobs had no Rust caching at all, so every release recompiled + # the whole ostp-jni dependency graph from scratch — the main reason these + # were among the slowest jobs in the matrix. + - name: Cache cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: cargo-android-${{ matrix.arch }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-android-${{ matrix.arch }}- + + # cargo-ndk was built from source on every run. Cache the binary the same + # way the cross-compilation jobs already cache `cross`. + - name: Restore cargo-ndk binary cache + id: cargo-ndk-cache + uses: actions/cache@v4 + with: + path: ~/.cargo/bin/cargo-ndk + key: cargo-ndk-bin-${{ runner.os }}-v1 + + - name: Install cargo-ndk (if not cached) + if: steps.cargo-ndk-cache.outputs.cache-hit != 'true' + run: cargo install cargo-ndk --locked - name: Build Android APK shell: bash @@ -614,7 +653,33 @@ jobs: exit 1 fi export OSTP_KEYSTORE_PATH="$RUNNER_TEMP/ostp-upload.jks" - echo "$OSTP_KEYSTORE_B64" | base64 -d > "$OSTP_KEYSTORE_PATH" + # Strip any stray CR/LF before decoding: the secret is pasted from a + # shell whose line endings we don't control, and a single trailing \r + # is enough to corrupt the decode. + printf '%s' "$OSTP_KEYSTORE_B64" | tr -d '\r\n' | base64 -d > "$OSTP_KEYSTORE_PATH" + + # Verify the keystore opens BEFORE spending four minutes on Gradle only + # to fail at the packaging step. The size/SHA-256 are safe to print (a + # hash reveals nothing) and let the operator compare against the local + # file to tell a transport problem apart from a wrong password. + echo "keystore: $(stat -c%s "$OSTP_KEYSTORE_PATH") bytes, sha256 $(sha256sum "$OSTP_KEYSTORE_PATH" | cut -d' ' -f1)" + if ! keytool -list -keystore "$OSTP_KEYSTORE_PATH" \ + -storepass "$OSTP_KEYSTORE_PASSWORD" >/dev/null 2>&1; then + echo "::error::The keystore did not open with ANDROID_KEYSTORE_PASSWORD." + echo "::error::If the SHA-256 above matches your local ostp-upload.jks, the file" + echo "::error::arrived intact and the password secret itself is wrong - note that" + echo "::error::PowerShell expands \$ inside double quotes, so a password containing" + echo "::error::one gets mangled unless it was set with single quotes." + exit 1 + fi + if ! keytool -list -keystore "$OSTP_KEYSTORE_PATH" \ + -storepass "$OSTP_KEYSTORE_PASSWORD" -alias "$OSTP_KEY_ALIAS" >/dev/null 2>&1; then + echo "::error::Keystore opened, but it has no key under ANDROID_KEY_ALIAS." + echo "::error::Aliases present in the keystore:" + keytool -list -keystore "$OSTP_KEYSTORE_PATH" -storepass "$OSTP_KEYSTORE_PASSWORD" \ + | grep -i "PrivateKeyEntry" || true + exit 1 + fi # 2. Compile JNI mkdir -p android/app/src/main/jniLibs/${{ matrix.arch }}