Skip to content

Test build

Test build #88

Workflow file for this run

name: Test build
# Build de test signé par la clé plateforme, SANS publication dans les Releases.
# Les APK sortent en artifacts du run (onglet Actions → run → section Artifacts).
# L'OTA interroge /releases/latest, qui ignore artifacts, drafts et prereleases :
# ce workflow ne peut donc PAS perturber les mises à jour des utilisateurs.
#
# NOMMAGE — la version dérive de la DERNIÈRE beta publiée : "2.6.6-beta.13.test.42".
# Ce format n'est pas cosmétique, il conditionne l'OTA du testeur :
# • il est POSTÉRIEUR à beta.13 (plus d'identifiants à préfixe égal) → s'installe par-dessus ;
# • il reste ANTÉRIEUR à beta.14 (13 < 14 au 2ᵉ identifiant) → la prochaine beta publique est
# toujours proposée.
# ⚠️ Ne PAS simplifier en "2.6.6-test.42" : "test" > "beta" alphabétiquement, la beta suivante
# paraîtrait alors plus ancienne et ne serait JAMAIS proposée.
on:
workflow_dispatch:
inputs:
variant:
description: "Variante à construire"
type: choice
options: [both, online, offline]
default: both
build_type:
description: "Type de build"
type: choice
options: [release, debug]
default: release
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
env:
MG4_KEYSTORE_BASE64: ${{ secrets.MG4_KEYSTORE_BASE64 }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Decode platform keystore
run: |
# Sans "if:" : un secret absent sautait l'étape en silence et produisait un APK NON
# signé, impossible à installer par-dessus une version signée — et sans le dire.
if [ -z "$MG4_KEYSTORE_BASE64" ]; then
echo "::error::MG4_KEYSTORE_BASE64 absent : l'APK de test serait non signé."
exit 1
fi
printf '%s' "$MG4_KEYSTORE_BASE64" | tr -d '[:space:]' | base64 -d > "$RUNNER_TEMP/platform.keystore"
if [ "$(head -c1 "$RUNNER_TEMP/platform.keystore" | od -An -tx1 | tr -d ' ')" != "30" ]; then
echo "::error::MG4_KEYSTORE_BASE64 est invalide. Recréer le secret avec : base64 -w0 platform.keystore"
exit 1
fi
echo "MG4_KEYSTORE=$RUNNER_TEMP/platform.keystore" >> "$GITHUB_ENV"
# Reprend le suffixe de la dernière prerelease dont le cœur numérique correspond au
# versionName courant. Cœur différent = la version a été montée depuis, on repart de
# "beta.0" plutôt que d'hériter d'un numéro qui ne veut plus rien dire.
- name: Compute version from last beta
id: ver
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
BASE=$(sed -n 's/.*versionName = "\([^"]*\)".*/\1/p' app/build.gradle.kts | head -1)
if [ -z "$BASE" ]; then
echo "::error::versionName introuvable dans app/build.gradle.kts"; exit 1
fi
LAST=$(gh api "repos/$GITHUB_REPOSITORY/releases?per_page=50" \
| jq -r '.[] | select(.prerelease==true) | .tag_name' \
| sed 's/^v//' \
| awk -v base="$BASE" '{ c=$0; sub(/-.*/,"",c); if (c==base) { print; exit } }')
if [ -n "$LAST" ]; then
PRE="${LAST#$BASE-}"
echo "Dernière beta de $BASE : $LAST"
else
PRE="beta.0"
echo "Aucune beta pour $BASE → repli sur beta.0"
fi
SUFFIX="-${PRE}.test.${{ github.run_number }}"
echo "suffix=$SUFFIX" >> "$GITHUB_OUTPUT"
echo "full=${BASE}${SUFFIX}" >> "$GITHUB_OUTPUT"
echo "Version de test : ${BASE}${SUFFIX}"
- name: Build APK(s)
env:
MG4_KEYSTORE_PASSWORD: ${{ secrets.MG4_KEYSTORE_PASSWORD }}
MG4_KEY_ALIAS: ${{ secrets.MG4_KEY_ALIAS }}
MG4_KEY_PASSWORD: ${{ secrets.MG4_KEY_PASSWORD }}
run: |
chmod +x gradlew
# "release" → assembleOnlineRelease ; "debug" → assembleOnlineDebug
case "${{ inputs.build_type }}" in
release) SUFFIX="Release" ;;
debug) SUFFIX="Debug" ;;
esac
case "${{ inputs.variant }}" in
both) TASKS="assembleOnline$SUFFIX assembleOffline$SUFFIX" ;;
online) TASKS="assembleOnline$SUFFIX" ;;
offline) TASKS="assembleOffline$SUFFIX" ;;
esac
echo "Tâches : $TASKS"
./gradlew $TASKS --no-daemon \
-Pmg4.versionSuffix='${{ steps.ver.outputs.suffix }}'
- name: Collect APKs
run: |
mkdir -p dist
find app/build/outputs/apk -name "*.apk" -exec cp {} dist/ \;
ls -la dist/
# /!\ --min-sdk-version 23 est OBLIGATOIRE pour que ce rapport dise la vérité : sans lui,
# apksigner prend le minSdk de l'APK (28), ne vérifie qu'en v3, et affiche
# "Verified using v1 scheme: false" sur un APK qui CONTIENT bien une signature v1.
- name: Verify signature schemes
run: |
APKSIGNER=$(ls "$ANDROID_SDK_ROOT"/build-tools/*/apksigner | sort -V | tail -1)
for f in dist/*.apk; do
echo "── $(basename "$f") ──"
"$APKSIGNER" verify --print-certs -v --min-sdk-version 23 "$f" \
| grep -E 'Verified using v[0-9]|certificate SHA-256 digest'
# Présence RÉELLE de la v1, indépendamment de ce qu'apksigner choisit de vérifier :
# sans elle, l'app refuse l'installation (getPackageArchiveInfo ne lit aucun
# certificat sur AAOS 9). Autant casser ici plutôt que de le découvrir sur la voiture.
if ! unzip -l "$f" | grep -qE 'META-INF/.*[.](SF|RSA|DSA|EC)$'; then
echo "::error::$(basename "$f") n a PAS de signature v1 (JAR)"
exit 1
fi
echo " v1 (JAR) presente : OUI"
echo " sha256 : $(sha256sum "$f" | cut -d' ' -f1)"
echo
done
- name: Upload APKs (artifacts, PAS une release)
uses: actions/upload-artifact@v4
with:
name: mg4control-${{ steps.ver.outputs.full }}-${{ inputs.variant }}-${{ inputs.build_type }}
path: dist/*.apk
retention-days: 14
if-no-files-found: error