fix(ci): stabilize emulator boot in release smoke test #13
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| permissions: | |
| contents: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| ci: | |
| name: CI Gate | |
| uses: ./.github/workflows/ci.yml | |
| secrets: inherit | |
| release: | |
| name: Signed APK Release | |
| runs-on: ubuntu-latest | |
| needs: [ci] | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Apply submodule patches | |
| run: if ls patches/*.patch 1>/dev/null 2>&1; then cd zeroclaw && git apply ../patches/*.patch; fi | |
| - name: Ensure embedded web assets exist | |
| run: | | |
| mkdir -p zeroclaw/web/dist | |
| if [ ! -f zeroclaw/web/dist/index.html ]; then | |
| printf '%s\n' '<!doctype html><html><body>OpenClaw Web UI placeholder</body></html>' > zeroclaw/web/dist/index.html | |
| fi | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: 17 | |
| - uses: android-actions/setup-android@v3 | |
| - name: Install NDK | |
| run: sdkmanager "ndk;27.2.12479018" | |
| - name: Install Android build-tools | |
| run: sdkmanager "build-tools;35.0.0" | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: aarch64-linux-android,x86_64-linux-android | |
| - name: Install cargo-ndk | |
| run: cargo install cargo-ndk | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: zeroclaw-android -> target | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Configure release signing | |
| env: | |
| RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }} | |
| RELEASE_STORE_PASSWORD: ${{ secrets.RELEASE_STORE_PASSWORD }} | |
| RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }} | |
| RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${RELEASE_KEYSTORE_BASE64:-}" ] || [ -z "${RELEASE_STORE_PASSWORD:-}" ] || [ -z "${RELEASE_KEY_ALIAS:-}" ] || [ -z "${RELEASE_KEY_PASSWORD:-}" ]; then | |
| echo "::error::Release signing secrets are missing." | |
| exit 1 | |
| fi | |
| printf '%s' "$RELEASE_KEYSTORE_BASE64" | base64 --decode > release.jks | |
| if ! keytool -list -keystore release.jks -storepass "$RELEASE_STORE_PASSWORD" -alias "$RELEASE_KEY_ALIAS" >/dev/null 2>&1; then | |
| echo "::error::Keystore validation failed." | |
| exit 1 | |
| fi | |
| printf 'RELEASE_STORE_FILE=../release.jks\n' > local.properties | |
| printf 'RELEASE_STORE_PASSWORD=%s\n' "$RELEASE_STORE_PASSWORD" >> local.properties | |
| printf 'RELEASE_KEY_ALIAS=%s\n' "$RELEASE_KEY_ALIAS" >> local.properties | |
| printf 'RELEASE_KEY_PASSWORD=%s\n' "$RELEASE_KEY_PASSWORD" >> local.properties | |
| - name: Build signed release APK | |
| run: ./gradlew :app:assembleRelease | |
| - name: Verify APK signature | |
| run: | | |
| set -euo pipefail | |
| SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" | |
| APKSIGNER="${SDK_ROOT}/build-tools/35.0.0/apksigner" | |
| if [ ! -x "$APKSIGNER" ]; then | |
| APKSIGNER="$(find "${SDK_ROOT}/build-tools" -type f -name apksigner 2>/dev/null | sort -V | tail -n 1 || true)" | |
| fi | |
| if [ -z "${APKSIGNER:-}" ] || [ ! -x "$APKSIGNER" ]; then | |
| echo "::error::apksigner not found under Android SDK build-tools" | |
| exit 1 | |
| fi | |
| "$APKSIGNER" verify --print-certs app/build/outputs/apk/release/phoneclaw.apk | tee /tmp/apk-signing.txt | |
| grep -q "Signer #1 certificate DN:" /tmp/apk-signing.txt | |
| - name: Enable KVM | |
| run: | | |
| echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | |
| sudo udevadm control --reload-rules | |
| sudo udevadm trigger --name-match=kvm | |
| - name: Smoke test install/launch on emulator | |
| uses: reactivecircus/android-emulator-runner@v2 | |
| with: | |
| api-level: 35 | |
| target: google_apis | |
| arch: x86_64 | |
| profile: pixel_7 | |
| emulator-boot-timeout: 900 | |
| heap-size: 512M | |
| ram-size: 4096M | |
| emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim | |
| disable-linux-hw-accel: false | |
| disable-animations: true | |
| script: | | |
| adb install -r app/build/outputs/apk/release/phoneclaw.apk | |
| adb shell am start -n com.zeroclaw.android/.MainActivity | |
| sleep 6 | |
| adb shell pidof com.zeroclaw.android | |
| - name: Extract tag version | |
| id: version | |
| run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" | |
| - name: Validate tag version | |
| run: | | |
| TAG_VERSION="${GITHUB_REF#refs/tags/v}" | |
| APP_VERSION=$(grep 'versionName = "' app/build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/') | |
| if [ "$TAG_VERSION" != "$APP_VERSION" ]; then | |
| echo "::warning::Tag v${TAG_VERSION} does not match app version ${APP_VERSION}; continuing release." | |
| fi | |
| - name: Clean up signing material | |
| if: always() | |
| run: rm -f release.jks local.properties | |
| - name: Create or Update GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| if gh release view "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then | |
| gh release upload "${{ steps.version.outputs.tag }}" \ | |
| app/build/outputs/apk/release/phoneclaw.apk \ | |
| --clobber | |
| else | |
| gh release create "${{ steps.version.outputs.tag }}" \ | |
| --title "${{ steps.version.outputs.tag }}" \ | |
| app/build/outputs/apk/release/phoneclaw.apk | |
| fi |