Files
ml e07258c8bd
release / build (push) Successful in 5m34s
Fix VICE cross-compile and image cache-warming for release builds
build-image/Dockerfile: add bison (VICE's configure needs a yacc-compatible
parser generator, same category as the earlier flex fix) and exclude
packageRelease/signReleaseBundle from the cache-warm stage's gradlew run,
since those always fail there for lack of a keystore that's never baked
into the image.

vice_jni.c: guard getFrameCount()/setSoundEnabled() with #ifdef
HAVE_VICE_SRC like their sibling functions already do — they referenced
globals that only exist when VICE is linked in, breaking the documented
no-VICE placeholder build. Only surfaced now because the cache-warm stage
is the first thing to ever compile this file without VICE.

dist.sh: floor the untagged dev-build's versionCode at 1, since the
0.0.0-dev+<sha> placeholder otherwise computes to 0, which Android's
Gradle plugin rejects.

run-image.sh: wipe generated build artifacts (vice-src, vice-libs,
nibtools-src/libs, app/build, .cxx) before each run so it exercises a true
from-scratch build like CI does, instead of silently reusing artifacts
left over from a previous local run. Also chown the bind-mounted repo back
to the host user on exit, since the container runs as root and was
otherwise leaving root-owned files behind.
2026-07-04 15:11:53 +02:00

127 lines
5.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Builds release artifacts for both apps and drops them in dist/, named
# schwert-und-magie-<version>.{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+<sha> 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]} ))
# Android requires a positive versionCode — the untagged dev placeholder
# (0.0.0-dev+<sha>) would otherwise compute to 0 and fail Gradle configuration.
[ "$VERSION_CODE" -gt 0 ] || VERSION_CODE=1
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"
# Pebble's own build tooling parses package.json's version strictly as
# X.Y.Z integers — it rejects the -pre+meta suffix dist.sh otherwise allows
# (including the default "0.0.0-dev+<sha>" placeholder), so strip it here.
PEBBLE_VERSION="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
sed -i -e "s/\"version\": \"[^\"]*\"/\"version\": \"$PEBBLE_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"