release.sh hace el ciclo entero y siempre igual, se lance a mano o desde un runner: empaqueta el backend, compila, verifica y publica la release en gitea. Las verificaciones no son decorativas, son las que han cazado fallos reales en esta rama: una APK puede compilar, instalar y arrancar sin el backend dentro, o haber perdido los permisos de camara y quedarse sin videollamadas. Se comprueba que estan el backend y libnode.so, los dos permisos, y la firma. El versionCode sale del numero de commits, que sube solo; el versionName, de package.json, que es de donde lo saca tambien el backend, para que la version que muestra la aplicacion no pueda discrepar de la de la APK. Los dos se pasan por entorno a Gradle en vez de editarlos a mano. La release se crea como borrador a proposito: publicar una APK firmada sin que nadie la mire no deberia poder pasar por descuido. El workflow de gitea no se dispara con cada commit (la APK son mas de 100 MB) y necesita un runner con el SDK de Android; queda documentado en su cabecera.
151 lines
7 KiB
Bash
Executable file
151 lines
7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Construye la APK, la verifica y (si se le pasa un token) publica la release en
|
|
# gitea. Pensado para lanzarlo a mano o desde un runner; hace lo mismo en los dos
|
|
# sitios, que es lo que evita el clasico "en mi maquina si sale".
|
|
#
|
|
# Uso:
|
|
# ./scripts/release.sh # compila debug y verifica
|
|
# ./scripts/release.sh --release # compila release firmada
|
|
# ./scripts/release.sh --release --publish
|
|
#
|
|
# Variables:
|
|
# OASIS_KEYSTORE, OASIS_KEYSTORE_PASS, OASIS_KEY_ALIAS firma (obligatorias con --release)
|
|
# OASIS_GITEA_TOKEN publicar (obligatoria con --publish)
|
|
# OASIS_APK_BASE APK del que sacar node_modules la primera vez
|
|
# OASIS_GITEA_URL por defecto https://gitea.laenre.net
|
|
# OASIS_GITEA_REPO por defecto hacklab/OASIS_MOBILE
|
|
# ANDROID_HOME por defecto ~/Android/Sdk
|
|
# JAVA_HOME un JDK 17 o superior CON compilador
|
|
#
|
|
set -euo pipefail
|
|
|
|
HERE="$(cd "$(dirname "$0")/.." && pwd)"
|
|
REPO="$(cd "$HERE/.." && pwd)"
|
|
cd "$HERE"
|
|
|
|
MODE=debug
|
|
PUBLISH=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--release) MODE=release ;;
|
|
--publish) PUBLISH=1 ;;
|
|
*) echo "opcion desconocida: $arg"; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
GITEA_URL="${OASIS_GITEA_URL:-https://gitea.laenre.net}"
|
|
GITEA_REPO="${OASIS_GITEA_REPO:-hacklab/OASIS_MOBILE}"
|
|
SDK="${ANDROID_HOME:-$HOME/Android/Sdk}"
|
|
|
|
say() { printf '\n== %s\n' "$*"; }
|
|
die() { printf '\n!! %s\n' "$*" >&2; exit 1; }
|
|
|
|
# --- 1) version -------------------------------------------------------------
|
|
# El nombre sale de package.json, que es de donde lo saca tambien el backend, para
|
|
# que la version que muestra la aplicacion y la de la APK no puedan discrepar.
|
|
VERSION_NAME="${OASIS_VERSION_NAME:-$(node -p "require('$REPO/package.json').version" 2>/dev/null || echo 0.0.0)}"
|
|
# El codigo tiene que subir en cada publicacion o Android rechaza la instalacion:
|
|
# el numero de commits sirve y no hay que llevarlo a mano.
|
|
VERSION_CODE="${OASIS_VERSION_CODE:-$(git -C "$REPO" rev-list --count HEAD 2>/dev/null || echo 1)}"
|
|
TAG="v${VERSION_NAME}-${VERSION_CODE}"
|
|
export OASIS_VERSION_NAME="$VERSION_NAME" OASIS_VERSION_CODE="$VERSION_CODE"
|
|
say "version ${VERSION_NAME} (codigo ${VERSION_CODE}), modo ${MODE}"
|
|
|
|
# --- 2) comprobaciones previas ---------------------------------------------
|
|
[ -n "${JAVA_HOME:-}" ] || die "define JAVA_HOME apuntando a un JDK con compilador"
|
|
[ -x "${JAVA_HOME}/bin/javac" ] || die "en ${JAVA_HOME} no hay javac: es un runtime, no un JDK"
|
|
[ -d "$SDK" ] || die "no encuentro el SDK de Android en $SDK (define ANDROID_HOME)"
|
|
|
|
if [ "$MODE" = release ]; then
|
|
[ -n "${OASIS_KEYSTORE:-}" ] || die "--release necesita OASIS_KEYSTORE"
|
|
[ -f "$OASIS_KEYSTORE" ] || die "no existe el almacen de claves: $OASIS_KEYSTORE"
|
|
[ -n "${OASIS_KEYSTORE_PASS:-}" ] || die "--release necesita OASIS_KEYSTORE_PASS"
|
|
fi
|
|
if [ "$PUBLISH" = 1 ]; then
|
|
[ -n "${OASIS_GITEA_TOKEN:-}" ] || die "--publish necesita OASIS_GITEA_TOKEN"
|
|
[ "$MODE" = release ] || die "no se publica una APK de depuracion"
|
|
fi
|
|
|
|
# --- 3) backend empaquetado -------------------------------------------------
|
|
# prepare.sh es idempotente pero tarda; se rehace siempre porque el backend cambia
|
|
# en cada commit y una APK con el backend viejo es peor que no tener APK.
|
|
# La primera vez hace falta un APK base del que sacar node_modules: el del movil
|
|
# esta podado y sin binarios nativos, y un npm install normal no lo reproduce.
|
|
say "empaquetando el backend"
|
|
./scripts/prepare.sh ${OASIS_APK_BASE:+"$OASIS_APK_BASE"} \
|
|
|| die "prepare.sh ha fallado (define OASIS_APK_BASE con un APK del que sacar node_modules)"
|
|
|
|
ZIP=app/src/main/assets/nodejs-project.zip
|
|
[ -f "$ZIP" ] || die "falta $ZIP"
|
|
ZIP_MB=$(( $(stat -c%s "$ZIP") / 1024 / 1024 ))
|
|
[ "$ZIP_MB" -ge 20 ] || die "el backend empaquetado son $ZIP_MB MB: se ha quedado a medias"
|
|
say "backend: ${ZIP_MB} MB"
|
|
|
|
# --- 4) compilar ------------------------------------------------------------
|
|
say "compilando"
|
|
if [ "$MODE" = release ]; then
|
|
./gradlew --quiet assembleRelease
|
|
APK=$(ls app/build/outputs/apk/release/*.apk | head -1)
|
|
else
|
|
./gradlew --quiet assembleDebug
|
|
APK=$(ls app/build/outputs/apk/debug/*.apk | head -1)
|
|
fi
|
|
[ -f "$APK" ] || die "no se ha generado ninguna APK"
|
|
say "APK: $APK ($(( $(stat -c%s "$APK") / 1024 / 1024 )) MB)"
|
|
|
|
# --- 5) verificar -----------------------------------------------------------
|
|
# Estas tres comprobaciones son las que han cazado fallos de verdad: una APK que
|
|
# compila e instala puede no llevar el backend dentro, o haber perdido los permisos.
|
|
BT=$(ls -d "$SDK"/build-tools/* 2>/dev/null | sort -V | tail -1)
|
|
[ -n "$BT" ] || die "no encuentro build-tools en $SDK"
|
|
|
|
say "verificando"
|
|
# ojo con pipefail: grep -q cierra la tuberia y el productor muere con SIGPIPE,
|
|
# asi que se vuelca a fichero antes de mirar
|
|
LISTING=$(mktemp); PERMS=$(mktemp)
|
|
trap 'rm -f "$LISTING" "$PERMS"' EXIT
|
|
unzip -l "$APK" > "$LISTING"
|
|
"$BT/aapt2" dump permissions "$APK" > "$PERMS" 2>/dev/null || true
|
|
|
|
grep -q "assets/nodejs-project.zip" "$LISTING" || die "la APK no lleva el backend dentro"
|
|
grep -q "android.permission.CAMERA" "$PERMS" || die "la APK no declara CAMERA: no podria hacer videollamadas"
|
|
grep -q "android.permission.RECORD_AUDIO" "$PERMS" || die "la APK no declara RECORD_AUDIO"
|
|
grep -q "libnode.so" "$LISTING" || die "la APK no lleva el runtime de node"
|
|
|
|
if [ "$MODE" = release ]; then
|
|
"$BT/apksigner" verify --print-certs "$APK" > /tmp/oasis-signer.txt 2>&1 \
|
|
|| die "la APK no esta firmada correctamente"
|
|
FINGERPRINT=$(grep -m1 "SHA-256 digest" /tmp/oasis-signer.txt | awk '{print $NF}')
|
|
say "huella del certificado: $FINGERPRINT"
|
|
fi
|
|
|
|
SHA=$(sha256sum "$APK" | cut -d' ' -f1)
|
|
say "sha256 de la APK: $SHA"
|
|
|
|
# --- 6) publicar ------------------------------------------------------------
|
|
if [ "$PUBLISH" != 1 ]; then
|
|
say "listo (sin publicar)"
|
|
exit 0
|
|
fi
|
|
|
|
say "publicando $TAG en $GITEA_REPO"
|
|
API="$GITEA_URL/api/v1/repos/$GITEA_REPO"
|
|
AUTH="Authorization: token $OASIS_GITEA_TOKEN"
|
|
|
|
NOTES=$(printf 'Rama experimental del hacklab sobre el Oasis de epsylon.\n\nNO es Oasis oficial: https://github.com/epsylon/oasis\n\nVersion base: %s (codigo %s)\n\nsha256 de la APK: %s\nHuella del certificado: %s\n\nComprueba la huella antes de instalar:\n\n apksigner verify --print-certs oasis.apk\n' \
|
|
"$VERSION_NAME" "$VERSION_CODE" "$SHA" "${FINGERPRINT:-sin firmar}")
|
|
|
|
RELEASE_ID=$(curl -sf -X POST "$API/releases" -H "$AUTH" -H "Content-Type: application/json" \
|
|
-d "$(node -e '
|
|
const [tag, name, body] = process.argv.slice(1);
|
|
process.stdout.write(JSON.stringify({ tag_name: tag, name, body, draft: true, prerelease: true }));
|
|
' "$TAG" "Oasis Mobile $TAG" "$NOTES")" | node -pe 'JSON.parse(require("fs").readFileSync(0)).id' 2>/dev/null) \
|
|
|| die "no se ha podido crear la release (token sin permiso, o el tag ya existe)"
|
|
|
|
curl -sf -X POST "$API/releases/$RELEASE_ID/assets?name=oasis-$TAG.apk" \
|
|
-H "$AUTH" -F "attachment=@$APK" >/dev/null \
|
|
|| die "la release se ha creado pero no se ha podido subir la APK"
|
|
|
|
say "publicada como borrador: $GITEA_URL/$GITEA_REPO/releases"
|
|
say "revisala y quita el borrador a mano; no se publica sola a proposito"
|