#!/usr/bin/env bash # Builds release artifacts for both apps and drops them in dist/, named # schwert-und-magie-.{aab,apk,pbw}. # # Version comes from the current git tag (vX.Y.Z) by default — push a tag to # drive a release. Override with VERSION=1.2.3 ./dist.sh, or just run it # untagged for a local dev build (gets a 0.0.0-dev+ placeholder version). # # Android output requires a release signing config — see docs/publish.md §2.1-2.3 # (keystore.properties + release.keystore in SchwertUndMagieOnPebbleCompanionApp/). # Without it, Gradle still produces an unsigned/debug-signed build; that's not # fatal (useful for local testing) so it's a warning, not a hard stop. set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" ROOT="$(pwd)" DIST="$ROOT/dist" COMPANION="$ROOT/SchwertUndMagieOnPebbleCompanionApp" WATCH="$ROOT/SchwertUndMagieOnPebbleWatchApp" GRADLE_KTS="$COMPANION/app/build.gradle.kts" WATCH_PKG_JSON="$WATCH/package.json" fail() { echo "PREFLIGHT FAIL: $*" >&2; exit 1; } warn() { echo "WARNING: $*" >&2; } echo "== Preflight checks ==" command -v pebble >/dev/null 2>&1 \ || fail "pebble CLI not found in PATH (needed to build the watch app)" [ -x "$COMPANION/gradlew" ] \ || fail "$COMPANION/gradlew missing or not executable" SDK_DIR="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" if [ -f "$COMPANION/local.properties" ]; then LOCAL_SDK="$(sed -n 's/^sdk\.dir=//p' "$COMPANION/local.properties")" [ -n "$LOCAL_SDK" ] && SDK_DIR="$LOCAL_SDK" fi [ -n "$SDK_DIR" ] && [ -d "$SDK_DIR" ] \ || fail "Android SDK not found (checked local.properties sdk.dir, \$ANDROID_SDK_ROOT, \$ANDROID_HOME)" NDK_VERSION="$(sed -n 's/.*ndkVersion *= *"\(.*\)".*/\1/p' "$GRADLE_KTS")" [ -n "$NDK_VERSION" ] \ || fail "could not read ndkVersion from app/build.gradle.kts" [ -d "$SDK_DIR/ndk/$NDK_VERSION" ] \ || fail "NDK $NDK_VERSION not installed under $SDK_DIR/ndk (Android Studio > SDK Manager > SDK Tools > NDK side by side)" [ -f "$COMPANION/res/vice-3.8.tar.gz" ] \ || fail "$COMPANION/res/vice-3.8.tar.gz missing (VICE source tarball required by the buildVice Gradle task)" compgen -G "$COMPANION/res/nibtools-*.tar.gz" >/dev/null \ || fail "$COMPANION/res/nibtools-*.tar.gz missing (nibtools source tarball required by the buildNibtools Gradle task)" # Signing config: missing/broken keystore.properties still builds (unsigned), # so warn here and rely on the post-build apksigner check for the real answer. if [ ! -f "$COMPANION/keystore.properties" ]; then warn "keystore.properties not found — release build will likely be unsigned (see docs/publish.md §2.1-2.3)" else STORE_FILE="$(sed -n 's/^storeFile=//p' "$COMPANION/keystore.properties")" if [ -z "$STORE_FILE" ] || [ ! -f "$COMPANION/$STORE_FILE" ]; then warn "keystore.properties found but its storeFile ('$STORE_FILE') does not exist — release build will likely be unsigned" fi fi echo "== Resolving version ==" if [ -z "${VERSION:-}" ]; then if TAG="$(git describe --tags --exact-match --match 'v[0-9]*.[0-9]*.[0-9]*' 2>/dev/null)"; then VERSION="${TAG#v}" else VERSION="0.0.0-dev+$(git rev-parse --short HEAD)" warn "HEAD is not on a vX.Y.Z tag — building placeholder version $VERSION (push a tag to drive a real release version)" fi fi [[ "$VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]] \ || fail "VERSION '$VERSION' is not a semantic version (expected X.Y.Z, optionally with a -pre+meta suffix)" VERSION_CODE=$(( ${BASH_REMATCH[1]} * 10000 + ${BASH_REMATCH[2]} * 100 + ${BASH_REMATCH[3]} )) echo "Version: $VERSION (Android versionCode $VERSION_CODE)" # Patch versions into the tracked source files for this build only, then # restore them — dist.sh must never leave the working tree dirty. restore_version_files() { git -C "$ROOT" checkout -- "$GRADLE_KTS" "$WATCH_PKG_JSON" 2>/dev/null || true } trap restore_version_files EXIT sed -i \ -e "s/versionCode = [0-9]\+/versionCode = $VERSION_CODE/" \ -e "s/versionName = \"[^\"]*\"/versionName = \"$VERSION\"/" \ "$GRADLE_KTS" sed -i -e "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" "$WATCH_PKG_JSON" mkdir -p "$DIST" echo "== Android companion app ==" cd "$COMPANION" ./gradlew bundleRelease assembleRelease cp -f app/build/outputs/bundle/release/app-release.aab "$DIST/schwert-und-magie-$VERSION.aab" cp -f app/build/outputs/apk/release/app-release.apk "$DIST/schwert-und-magie-$VERSION.apk" echo "== Pebble watch app ==" cd "$WATCH" pebble build cp -f build/SchwertUndMagieOnPebbleWatchApp.pbw "$DIST/schwert-und-magie-$VERSION.pbw" echo "== Verifying APK signature ==" APK="$DIST/schwert-und-magie-$VERSION.apk" APKSIGNER="$(compgen -G "$SDK_DIR/build-tools/*/apksigner" | sort -V | tail -1 || true)" if [ -z "$APKSIGNER" ]; then warn "apksigner not found under $SDK_DIR/build-tools — could not verify APK signature" elif ! "$APKSIGNER" verify "$APK" >/dev/null 2>&1; then warn "$APK is UNSIGNED (failed apksigner verification) — not installable/publishable as-is" elif "$APKSIGNER" verify --print-certs "$APK" 2>/dev/null | grep -qi "CN=Android Debug"; then warn "$APK is signed with the Android debug cert, not the release keystore" fi echo "== Done ==" ls -la "$DIST"