Skip to content

fix(ci): stabilize emulator boot in release smoke test #13

fix(ci): stabilize emulator boot in release smoke test

fix(ci): stabilize emulator boot in release smoke test #13

Workflow file for this run

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