Skip to content

chore: prepare Nova 1.2.0 release #426

chore: prepare Nova 1.2.0 release

chore: prepare Nova 1.2.0 release #426

Workflow file for this run

name: Build Nova APK
on:
push:
branches: [ master ]
tags: [ 'v*' ]
pull_request:
branches: [ master ]
workflow_dispatch:
inputs:
run_emulator_smoke:
description: 'Run the slow emulator instrumentation smoke test'
type: boolean
default: false
jobs:
verify:
name: Lint and unit test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
submodules: recursive
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
cache: gradle
- name: Set up Android SDK
uses: android-actions/setup-android@v4
- name: Install NDK
run: sdkmanager "ndk;27.0.12077973"
- name: Lint debug build
run: ./gradlew -PnovaAbis=x86_64 -PlintFailOnError=true lintNonRoot_gameDebug
- name: Run JVM tests
run: ./gradlew -PnovaAbis=x86_64 testNonRoot_gameDebugUnitTest
- name: Run helper and onboarding tests
run: python3 -m unittest tools.test_nova_retroid_smoke tools.test_native_submodule_preflight
android-smoke:
name: Emulator smoke test
needs: verify
if: ${{ github.event_name == 'workflow_dispatch' && inputs.run_emulator_smoke }}
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- uses: actions/checkout@v5
with:
submodules: recursive
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
cache: gradle
- name: Set up Android SDK
uses: android-actions/setup-android@v4
- 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: Install NDK
run: sdkmanager "ndk;27.0.12077973"
- name: Run instrumentation smoke test
timeout-minutes: 30
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 29
arch: x86_64
profile: Nexus 6
target: default
disk-size: 1024M
emulator-boot-timeout: 900
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-snapshot -no-metrics
script: ./gradlew -PnovaAbis=x86_64 connectedNonRoot_gameDebugAndroidTest --stacktrace
build:
name: Assemble release APK
needs: [verify, android-smoke]
if: ${{ always() && needs.verify.result == 'success' && (needs.android-smoke.result == 'success' || needs.android-smoke.result == 'skipped') }}
runs-on: ubuntu-latest
permissions:
contents: write
env:
HAS_KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 != '' }}
steps:
- uses: actions/checkout@v5
with:
submodules: recursive
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
cache: gradle
- name: Set up Android SDK
uses: android-actions/setup-android@v4
- name: Install NDK
run: sdkmanager "ndk;27.0.12077973"
- name: Build release APK
run: ./gradlew assembleNonRoot_gameRelease
- name: Sign APKs
if: github.event_name != 'pull_request' && env.HAS_KEYSTORE_BASE64 == 'true'
run: |
set -euo pipefail
shopt -s nullglob
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > /tmp/keystore.jks
APK_DIR="app/build/outputs/apk/nonRoot_game/release"
unsigned_apks=("${APK_DIR}"/*release-unsigned.apk)
if [ "${#unsigned_apks[@]}" -eq 0 ]; then
echo "No unsigned release APKs found in ${APK_DIR}" >&2
exit 1
fi
BUILD_TOOLS="${ANDROID_HOME}/build-tools/$(ls "${ANDROID_HOME}/build-tools/" | sort -V | tail -1)"
for APK in "${unsigned_apks[@]}"; do
SIGNED_APK="${APK/-unsigned/}"
"${BUILD_TOOLS}/zipalign" -v 4 "$APK" "${APK}.aligned"
"${BUILD_TOOLS}/apksigner" sign \
--ks /tmp/keystore.jks \
--ks-key-alias ${{ secrets.KEY_ALIAS }} \
--ks-pass pass:${{ secrets.KEYSTORE_PASSWORD }} \
--key-pass pass:${{ secrets.KEY_PASSWORD }} \
--out "$SIGNED_APK" \
"${APK}.aligned"
done
- name: Select APK artifacts
run: |
set -euo pipefail
shopt -s nullglob
APK_DIR="app/build/outputs/apk/nonRoot_game/release"
APK_ASSET_DIR="${PWD}/release-assets"
mkdir -p "${APK_ASSET_DIR}"
signed_apks=("${APK_DIR}"/*-release.apk)
if [ "${#signed_apks[@]}" -gt 0 ]; then
apk_files=("${signed_apks[@]}")
else
apk_files=("${APK_DIR}"/*release-unsigned.apk)
fi
if [ "${#apk_files[@]}" -eq 0 ]; then
echo "No release APKs found in ${APK_DIR}" >&2
exit 1
fi
if [[ "${GITHUB_REF}" == refs/tags/v* && "${#signed_apks[@]}" -eq 0 ]]; then
echo "Refusing to publish unsigned APKs for ${GITHUB_REF_NAME}" >&2
exit 1
fi
for apk in "${apk_files[@]}"; do
apk_name="$(basename "$apk")"
case "$apk_name" in
*arm64-v8a*) abi="arm64-v8a" ;;
*armeabi-v7a*) abi="armeabi-v7a" ;;
*x86_64*) abi="x86_64" ;;
*)
echo "Could not determine ABI for ${apk_name}" >&2
exit 1
;;
esac
if [[ "$apk_name" == *-unsigned.apk ]]; then
asset_name="Nova-Android-${abi}-unsigned.apk"
else
asset_name="Nova-Android-${abi}.apk"
fi
cp "$apk" "${APK_ASSET_DIR}/${asset_name}"
done
echo "APK_ASSET_DIR=${APK_ASSET_DIR}" >> "$GITHUB_ENV"
- name: Generate checksums
run: |
set -euo pipefail
shopt -s nullglob
for apk in "${APK_ASSET_DIR}"/*.apk; do
sha256sum "$apk" > "$apk.sha256"
done
- name: Upload APK artifact
uses: actions/upload-artifact@v7
continue-on-error: true
with:
name: nova-release-apk
path: ${{ env.APK_ASSET_DIR }}/*
if-no-files-found: error
retention-days: 3
- name: Upload GitHub Release assets
if: startsWith(github.ref, 'refs/tags/v')
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
set -euo pipefail
shopt -s nullglob
release_assets=("${APK_ASSET_DIR}"/*.apk "${APK_ASSET_DIR}"/*.apk.sha256)
for file in "${release_assets[@]}"; do
if [ ! -f "$file" ]; then
echo "Missing release asset: $file" >&2
exit 1
fi
done
if ! gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
gh release create "${GITHUB_REF_NAME}" \
--verify-tag \
--title "${GITHUB_REF_NAME}" \
--generate-notes
fi
gh release upload "${GITHUB_REF_NAME}" "${release_assets[@]}" --clobber
- name: Verify GitHub Release assets
if: startsWith(github.ref, 'refs/tags/v')
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
set -euo pipefail
asset_count=$(gh release view "${GITHUB_REF_NAME}" --json assets --jq '.assets | length')
if [ "${asset_count}" -lt 6 ]; then
echo "Expected at least 6 release assets on ${GITHUB_REF_NAME}, found ${asset_count}" >&2
exit 1
fi
gh release view "${GITHUB_REF_NAME}" --json assets --jq '.assets[].name' | grep -Fx 'Nova-Android-arm64-v8a.apk'
gh release view "${GITHUB_REF_NAME}" --json assets --jq '.assets[].name' | grep -Fx 'Nova-Android-armeabi-v7a.apk'
gh release view "${GITHUB_REF_NAME}" --json assets --jq '.assets[].name' | grep -Fx 'Nova-Android-x86_64.apk'