Lo del 10 de octubre que sigue valiendo sobre la base 1.3.3: - con un tag v* el workflow publica la APK; a mano sigue en borrador - el workflow trae el APK oficial de la misma version: de ahi salen node_modules y libnode.so (prepare.sh ya lo usaba, pero el runner no lo tenia) - versionName sale de package.json en vez de ir escrito a mano - libnode.so comprimida, como en la oficial (unos 35 MB menos por descarga) - release.sh: JAVA_HOME en el PATH, no deja salir una release debuggable, exige CHANGE_WIFI_MULTICAST_STATE y avisa si la APK pasa de 80 MB Se queda fuera la poda de prepare.sh y la sha256 de la APK 1.2.5: ahora el node_modules viene ya podado del APK oficial.
175 lines
8.4 KiB
Bash
Executable file
175 lines
8.4 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 # borrador, para revisarla
|
|
# ./scripts/release.sh --release --publish --public # publicada: la descarga del README
|
|
#
|
|
# 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
|
|
PUBLIC=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--release) MODE=release ;;
|
|
--publish) PUBLISH=1 ;;
|
|
--public) PUBLIC=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"
|
|
# apksigner y aapt2 son scripts que llaman a "java" a pelo: sin esto fallaban con
|
|
# "java: no encontrado" y parecia que la APK estaba mal firmada
|
|
export PATH="$JAVA_HOME/bin:$PATH"
|
|
[ -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"
|
|
grep -q "CHANGE_WIFI_MULTICAST_STATE" "$PERMS" || die "la APK no declara CHANGE_WIFI_MULTICAST_STATE: no veria otros moviles en la misma wifi"
|
|
|
|
# Una APK debuggable deja leer por adb los datos de la app, clave secreta incluida.
|
|
if "$BT/aapt2" dump badging "$APK" 2>/dev/null | grep -q "application-debuggable"; then
|
|
[ "$MODE" = release ] && die "la APK release ha salido debuggable"
|
|
say "OJO: APK de depuracion (debuggable). Solo para probar en tu movil, no la repartas"
|
|
fi
|
|
|
|
# La oficial pesa ~54 MB; si esta se dispara es que prepare.sh ha dejado de adelgazar
|
|
APK_MB=$(( $(stat -c%s "$APK") / 1024 / 1024 ))
|
|
[ "$APK_MB" -le 80 ] || say "OJO: la APK son ${APK_MB} MB (la oficial ~54): revisa que mete prepare.sh"
|
|
|
|
if [ "$MODE" = release ]; then
|
|
"$BT/apksigner" verify --print-certs "$APK" > /tmp/oasis-signer.txt 2>&1 \
|
|
|| { cat /tmp/oasis-signer.txt >&2; 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);
|
|
const pub = process.argv[4] === "1";
|
|
process.stdout.write(JSON.stringify({ tag_name: tag, name, body, draft: !pub, prerelease: !pub }));
|
|
' "$TAG" "Oasis Mobile $TAG" "$NOTES" "$PUBLIC")" | 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)"
|
|
|
|
# Siempre con el mismo nombre: el README enlaza a releases/download/latest/oasis-mobile.apk,
|
|
# y la version ya va en el tag y en el titulo de la release.
|
|
curl -sf -X POST "$API/releases/$RELEASE_ID/assets?name=oasis-mobile.apk" \
|
|
-H "$AUTH" -F "attachment=@$APK" >/dev/null \
|
|
|| die "la release se ha creado pero no se ha podido subir la APK"
|
|
|
|
if [ "$PUBLIC" = 1 ]; then
|
|
say "publicada: $GITEA_URL/$GITEA_REPO/releases/latest"
|
|
else
|
|
say "publicada como borrador: $GITEA_URL/$GITEA_REPO/releases"
|
|
say "revisala y quita el borrador a mano (o usa --public); no se publica sola a proposito"
|
|
fi
|