feat: Version 3.6.2 - Correctifs tâches #17-20

- #17: Amélioration gestion des secteurs et statistiques
- #18: Optimisation services API et logs
- #19: Corrections Flutter widgets et repositories
- #20: Fix création passage - détection automatique ope_users.id vs users.id

Suppression dossier web/ (migration vers app Flutter)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 14:11:15 +01:00
parent 7b78037175
commit 232940b1eb
196 changed files with 8483 additions and 7966 deletions

498
app/deploy-ios-full-auto.sh Executable file
View File

@@ -0,0 +1,498 @@
#!/bin/bash
# Script de déploiement iOS automatisé pour GEOSECTOR
# Version: 1.0
# Date: 2025-12-05
# Auteur: Pierre (avec l'aide de Claude)
#
# Usage:
# ./deploy-ios-full-auto.sh # Utilise ../VERSION
# ./deploy-ios-full-auto.sh 3.6.0 # Version spécifique
# ./deploy-ios-full-auto.sh 3.6.0 --skip-build # Skip Flutter build si déjà fait
set -euo pipefail
# =====================================
# Configuration
# =====================================
# Couleurs pour les messages
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Configuration Mac mini
MAC_MINI_HOST="minipi4" # Nom défini dans ~/.ssh/config
MAC_BASE_DIR="/Users/pierre/dev/geosector"
# Timestamp pour logs et archives
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="./logs/deploy-ios-${TIMESTAMP}.log"
mkdir -p ./logs
# Variables globales pour le rapport
STEP_START_TIME=0
TOTAL_START_TIME=$(date +%s)
ERRORS_COUNT=0
WARNINGS_COUNT=0
# =====================================
# Fonctions utilitaires
# =====================================
log() {
echo -e "$1" | tee -a "${LOG_FILE}"
}
log_step() {
STEP_START_TIME=$(date +%s)
log "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log "${CYAN}$1${NC}"
log "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}
log_substep() {
log "${MAGENTA}$1${NC}"
}
log_info() {
log "${BLUE} ${NC}$1"
}
log_success() {
local elapsed=$(($(date +%s) - STEP_START_TIME))
log "${GREEN}${NC} $1 ${CYAN}(${elapsed}s)${NC}"
}
log_warning() {
((WARNINGS_COUNT++))
log "${YELLOW}${NC}$1"
}
log_error() {
((ERRORS_COUNT++))
log "${RED}${NC} $1"
}
log_fatal() {
log_error "$1"
log "\n${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log "${RED}DÉPLOIEMENT ÉCHOUÉ${NC}"
log "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log_error "Consultez le log: ${LOG_FILE}"
exit 1
}
# Fonction pour exécuter une commande et capturer les erreurs
safe_exec() {
local cmd="$1"
local error_msg="$2"
if ! eval "$cmd" >> "${LOG_FILE}" 2>&1; then
log_fatal "$error_msg"
fi
}
# Fonction pour exécuter une commande SSH avec gestion d'erreurs
ssh_exec() {
local cmd="$1"
local error_msg="$2"
if ! ssh "$MAC_MINI_HOST" "$cmd" >> "${LOG_FILE}" 2>&1; then
log_fatal "$error_msg"
fi
}
# =====================================
# En-tête
# =====================================
clear
log "${BLUE}╔════════════════════════════════════════════════════════╗${NC}"
log "${BLUE}║ ║${NC}"
log "${BLUE}${GREEN}🍎 DÉPLOIEMENT iOS AUTOMATISÉ${BLUE}${NC}"
log "${BLUE}${CYAN}GEOSECTOR - Full Automation${BLUE}${NC}"
log "${BLUE}║ ║${NC}"
log "${BLUE}╚════════════════════════════════════════════════════════╝${NC}"
log ""
log_info "Démarrage: $(date '+%Y-%m-%d %H:%M:%S')"
log_info "Log file: ${LOG_FILE}"
log ""
# =====================================
# Étape 1 : Gestion de la version
# =====================================
log_step "ÉTAPE 1/8 : Gestion de la version"
# Déterminer la version à utiliser
if [ "${1:-}" != "" ] && [[ ! "${1}" =~ ^-- ]]; then
VERSION="$1"
log_info "Version fournie en argument: ${VERSION}"
else
# Lire depuis ../VERSION
if [ ! -f ../VERSION ]; then
log_fatal "Fichier ../VERSION introuvable et aucune version fournie"
fi
VERSION=$(cat ../VERSION | tr -d '\n\r ' | tr -d '[:space:]')
log_info "Version lue depuis ../VERSION: ${VERSION}"
fi
# Vérifier le format de version
if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
log_fatal "Format de version invalide: ${VERSION} (attendu: x.x.x)"
fi
# Calculer le build number
BUILD_NUMBER=$(echo $VERSION | tr -d '.')
FULL_VERSION="${VERSION}+${BUILD_NUMBER}"
log_success "Version configurée"
log_info " Version name: ${GREEN}${VERSION}${NC}"
log_info " Build number: ${GREEN}${BUILD_NUMBER}${NC}"
log_info " Full version: ${GREEN}${FULL_VERSION}${NC}"
# =====================================
# Étape 2 : Mise à jour pubspec.yaml
# =====================================
log_step "ÉTAPE 2/8 : Mise à jour pubspec.yaml"
# Backup du pubspec.yaml
cp pubspec.yaml pubspec.yaml.backup
# Mise à jour de la version
sed -i "s/^version: .*/version: $FULL_VERSION/" pubspec.yaml
# Vérifier la mise à jour
UPDATED_VERSION=$(grep "^version:" pubspec.yaml | sed 's/version: //' | tr -d ' ')
if [ "$UPDATED_VERSION" != "$FULL_VERSION" ]; then
log_fatal "Échec de la mise à jour de pubspec.yaml (attendu: $FULL_VERSION, obtenu: $UPDATED_VERSION)"
fi
log_success "pubspec.yaml mis à jour"
# =====================================
# Étape 3 : Préparation du projet
# =====================================
SKIP_BUILD=false
if [[ "${2:-}" == "--skip-build" ]]; then
SKIP_BUILD=true
log_warning "Mode --skip-build activé, Flutter build sera ignoré"
fi
if [ "$SKIP_BUILD" = false ]; then
log_step "ÉTAPE 3/8 : Préparation du projet Flutter"
log_substep "Configuration du cache local"
export PUB_CACHE="$PWD/.pub-cache-local"
export GRADLE_USER_HOME="$PWD/.gradle-local"
mkdir -p "$PUB_CACHE" "$GRADLE_USER_HOME"
log_info " Cache Pub: $PUB_CACHE"
log_info " Cache Gradle: $GRADLE_USER_HOME"
log_substep "Nettoyage du projet"
safe_exec "flutter clean" "Échec du nettoyage Flutter"
log_substep "Récupération des dépendances"
safe_exec "flutter pub get" "Échec de flutter pub get"
log_substep "Application du patch nfc_manager"
safe_exec "./fastlane/scripts/commun/fix-nfc-manager.sh" "Échec du patch nfc_manager"
log_substep "Application du patch permission_handler (si nécessaire)"
if [ -f "./fastlane/scripts/commun/fix-permission-handler.sh" ]; then
safe_exec "./fastlane/scripts/commun/fix-permission-handler.sh" "Échec du patch permission_handler"
fi
log_substep "Génération des fichiers Hive"
safe_exec "dart run build_runner build --delete-conflicting-outputs" "Échec de la génération de code"
log_success "Projet préparé (dépendances + patchs + génération de code)"
log_info " ⚠️ Build iOS sera fait sur le Mac mini via Fastlane"
else
log_step "ÉTAPE 3/8 : Préparation du projet (BUILD SKIPPED)"
log_substep "Configuration du cache local uniquement"
export PUB_CACHE="$PWD/.pub-cache-local"
export GRADLE_USER_HOME="$PWD/.gradle-local"
if [ ! -d "$PUB_CACHE" ]; then
log_warning "Cache local introuvable, le build pourrait échouer sur le Mac mini"
fi
log_success "Cache configuré (build Flutter ignoré)"
fi
# =====================================
# Étape 4 : Vérification de la connexion Mac mini
# =====================================
log_step "ÉTAPE 4/8 : Connexion au Mac mini"
log_substep "Test de connexion SSH à ${MAC_MINI_HOST}"
if ! ssh "$MAC_MINI_HOST" "echo 'Connection OK'" >> "${LOG_FILE}" 2>&1; then
log_fatal "Impossible de se connecter au Mac mini (${MAC_MINI_HOST})"
fi
log_success "Connexion SSH établie"
# Vérifier l'environnement Mac
log_substep "Vérification de l'environnement Mac"
MAC_INFO=$(ssh "$MAC_MINI_HOST" "sw_vers -productVersion && xcodebuild -version | head -1 && flutter --version | head -1" 2>/dev/null || echo "N/A")
log_info "$(echo "$MAC_INFO" | head -1 | xargs -I {} echo " macOS: {}")"
log_info "$(echo "$MAC_INFO" | sed -n '2p' | xargs -I {} echo " Xcode: {}")"
log_info "$(echo "$MAC_INFO" | sed -n '3p' | xargs -I {} echo " Flutter: {}")"
# =====================================
# Étape 5 : Transfert vers Mac mini
# =====================================
log_step "ÉTAPE 5/8 : Transfert du projet vers Mac mini"
DEST_DIR="${MAC_BASE_DIR}/app_${BUILD_NUMBER}"
log_substep "Création du dossier de destination: ${DEST_DIR}"
ssh_exec "mkdir -p ${DEST_DIR}" "Impossible de créer le dossier ${DEST_DIR} sur le Mac mini"
log_substep "Transfert rsync (peut prendre 2-5 minutes)"
TRANSFER_START=$(date +%s)
rsync -avz --progress \
--exclude='build/' \
--exclude='.dart_tool/' \
--exclude='ios/Pods/' \
--exclude='ios/.symlinks/' \
--exclude='macos/Pods/' \
--exclude='linux/flutter/ephemeral/' \
--exclude='windows/flutter/ephemeral/' \
--exclude='android/build/' \
--exclude='*.aab' \
--exclude='*.apk' \
--exclude='logs/' \
--exclude='*.log' \
./ "${MAC_MINI_HOST}:${DEST_DIR}/" >> "${LOG_FILE}" 2>&1 || log_fatal "Échec du transfert rsync"
TRANSFER_TIME=$(($(date +%s) - TRANSFER_START))
log_success "Transfert terminé"
log_info " Destination: ${DEST_DIR}"
log_info " Durée: ${TRANSFER_TIME}s"
# =====================================
# Étape 6 : Build et Archive avec Fastlane
# =====================================
log_step "ÉTAPE 6/8 : Build et Archive iOS avec Fastlane"
log_info "Cette étape peut prendre 15-25 minutes"
log_info "Fastlane va :"
log_info " 1. Nettoyer les artefacts"
log_info " 2. Installer les CocoaPods"
log_info " 3. Analyser le code"
log_info " 4. Build Flutter iOS"
log_info " 5. Archive Xcode (gym)"
log_info " 6. Export IPA"
log_info ""
log_substep "Lancement de: cd ${DEST_DIR} && fastlane ios build"
FASTLANE_START=$(date +%s)
# Créer un fichier temporaire pour capturer la sortie Fastlane
FASTLANE_LOG="/tmp/fastlane-ios-${TIMESTAMP}.log"
# Exécuter Fastlane en temps réel avec affichage des étapes importantes
ssh -t "$MAC_MINI_HOST" "cd ${DEST_DIR} && /opt/homebrew/bin/fastlane ios build" 2>&1 | tee -a "${LOG_FILE}" | tee "${FASTLANE_LOG}" | while IFS= read -r line; do
# Afficher les lignes importantes
if echo "$line" | grep -qE "(🧹|📦|🔧|🔍|🏗️|✓|✗|Error|error:|ERROR|Build succeeded|Build failed)"; then
echo -e "${CYAN} ${line}${NC}"
fi
done
# Vérifier le code de retour de Fastlane
FASTLANE_EXIT_CODE=${PIPESTATUS[0]}
FASTLANE_TIME=$(($(date +%s) - FASTLANE_START))
if [ $FASTLANE_EXIT_CODE -ne 0 ]; then
log_error "Fastlane a échoué (code: ${FASTLANE_EXIT_CODE})"
log_error "Analyse des erreurs..."
# Extraire les erreurs du log Fastlane
if [ -f "${FASTLANE_LOG}" ]; then
log ""
log "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log "${RED}ERREURS DÉTECTÉES :${NC}"
log "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
grep -i "error:\|Error:\|ERROR:\|❌\|✗" "${FASTLANE_LOG}" | head -20 | while IFS= read -r error_line; do
log "${RED} ${error_line}${NC}"
done
log "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
fi
log_fatal "Build iOS échoué via Fastlane. Consultez ${FASTLANE_LOG} pour plus de détails."
fi
log_success "Build et Archive iOS réussis"
log_info " Durée totale Fastlane: ${FASTLANE_TIME}s ($((FASTLANE_TIME/60))m $((FASTLANE_TIME%60))s)"
# Vérifier que l'IPA existe
log_substep "Vérification de l'IPA généré"
IPA_EXISTS=$(ssh "$MAC_MINI_HOST" "test -f ${DEST_DIR}/build/ios/ipa/Runner.ipa && echo 'YES' || echo 'NO'")
if [ "$IPA_EXISTS" != "YES" ]; then
log_fatal "IPA non trouvé dans ${DEST_DIR}/build/ios/ipa/Runner.ipa"
fi
IPA_SIZE=$(ssh "$MAC_MINI_HOST" "du -h ${DEST_DIR}/build/ios/ipa/Runner.ipa | cut -f1")
log_info " IPA trouvé: ${GREEN}${IPA_SIZE}${NC}"
# =====================================
# Étape 7 : Upload vers TestFlight (optionnel)
# =====================================
log_step "ÉTAPE 7/8 : Upload vers TestFlight"
log ""
log_info "${YELLOW}Voulez-vous uploader l'IPA vers TestFlight maintenant ?${NC}"
log_info " [Y] Oui - Upload automatique via fastlane ios upload"
log_info " [N] Non - Je ferai l'upload manuellement plus tard"
log ""
read -p "$(echo -e ${CYAN}Votre choix [Y/n]: ${NC})" -n 1 -r UPLOAD_CHOICE
echo
log ""
if [[ $UPLOAD_CHOICE =~ ^[Yy]$ ]] || [ -z "$UPLOAD_CHOICE" ]; then
log_substep "Lancement de: fastlane ios upload"
log_info "Upload vers TestFlight (peut prendre 5-10 minutes)"
UPLOAD_START=$(date +%s)
ssh -t "$MAC_MINI_HOST" "cd ${DEST_DIR} && /opt/homebrew/bin/fastlane ios upload" 2>&1 | tee -a "${LOG_FILE}"
UPLOAD_EXIT_CODE=${PIPESTATUS[0]}
UPLOAD_TIME=$(($(date +%s) - UPLOAD_START))
if [ $UPLOAD_EXIT_CODE -ne 0 ]; then
log_error "Upload TestFlight échoué (code: ${UPLOAD_EXIT_CODE})"
log_warning "L'IPA est disponible sur le Mac mini, vous pouvez réessayer manuellement"
log_info " Commande: ssh $MAC_USER@$MAC_MINI_IP \"cd ${DEST_DIR} && fastlane ios upload\""
else
log_success "Upload TestFlight réussi"
log_info " Durée: ${UPLOAD_TIME}s"
log_info " URL: ${CYAN}https://appstoreconnect.apple.com${NC}"
fi
else
log_info "Upload ignoré. Pour uploader manuellement plus tard :"
log_info " ${CYAN}ssh $MAC_MINI_HOST \"cd ${DEST_DIR} && /opt/homebrew/bin/fastlane ios upload\"${NC}"
fi
# =====================================
# Étape 8 : Nettoyage et archivage
# =====================================
log_step "ÉTAPE 8/8 : Nettoyage et archivage"
log_substep "Voulez-vous archiver le dossier de build ?"
log_info " [Y] Oui - Créer une archive ${DEST_DIR}.tar.gz"
log_info " [N] Non - Garder le dossier tel quel (défaut)"
log ""
read -p "$(echo -e ${CYAN}Votre choix [y/N]: ${NC})" -n 1 -r ARCHIVE_CHOICE
echo
log ""
if [[ $ARCHIVE_CHOICE =~ ^[Yy]$ ]]; then
log_substep "Création de l'archive..."
ssh_exec "cd ${MAC_BASE_DIR} && tar -czf app_${BUILD_NUMBER}.tar.gz app_${BUILD_NUMBER}" \
"Échec de la création de l'archive"
ARCHIVE_SIZE=$(ssh "$MAC_MINI_HOST" "du -h ${MAC_BASE_DIR}/app_${BUILD_NUMBER}.tar.gz | cut -f1")
log_success "Archive créée"
log_info " Archive: ${MAC_BASE_DIR}/app_${BUILD_NUMBER}.tar.gz (${ARCHIVE_SIZE})"
log_substep "Suppression du dossier de build"
ssh_exec "rm -rf ${DEST_DIR}" "Échec de la suppression du dossier"
log_success "Dossier de build supprimé"
else
log_info "Dossier conservé: ${DEST_DIR}"
fi
# Restaurer le pubspec.yaml original (optionnel)
log_substep "Restauration de pubspec.yaml local"
mv pubspec.yaml.backup pubspec.yaml
log_info " pubspec.yaml local restauré à son état initial"
# =====================================
# Rapport final
# =====================================
TOTAL_TIME=$(($(date +%s) - TOTAL_START_TIME))
TOTAL_MINUTES=$((TOTAL_TIME / 60))
TOTAL_SECONDS=$((TOTAL_TIME % 60))
log ""
log "${GREEN}╔════════════════════════════════════════════════════════╗${NC}"
log "${GREEN}║ ║${NC}"
log "${GREEN}║ ✓ DÉPLOIEMENT iOS TERMINÉ AVEC SUCCÈS ║${NC}"
log "${GREEN}║ ║${NC}"
log "${GREEN}╚════════════════════════════════════════════════════════╝${NC}"
log ""
log "${CYAN}📊 RAPPORT DE DÉPLOIEMENT${NC}"
log "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log ""
log " ${BLUE}Version déployée:${NC} ${GREEN}${VERSION} (Build ${BUILD_NUMBER})${NC}"
log " ${BLUE}Destination:${NC} ${DEST_DIR}"
log " ${BLUE}IPA généré:${NC} ${GREEN}${IPA_SIZE}${NC}"
log " ${BLUE}Durée totale:${NC} ${GREEN}${TOTAL_MINUTES}m ${TOTAL_SECONDS}s${NC}"
log ""
if [ $WARNINGS_COUNT -gt 0 ]; then
log " ${YELLOW}⚠ Avertissements:${NC} ${WARNINGS_COUNT}"
fi
if [ $ERRORS_COUNT -gt 0 ]; then
log " ${RED}✗ Erreurs:${NC} ${ERRORS_COUNT}"
fi
log ""
log "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log ""
log "${BLUE}📱 PROCHAINES ÉTAPES${NC}"
log "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log ""
if [[ $UPLOAD_CHOICE =~ ^[Yy]$ ]] || [ -z "$UPLOAD_CHOICE" ]; then
if [ $UPLOAD_EXIT_CODE -eq 0 ]; then
log " 1. ${GREEN}${NC} IPA uploadé sur TestFlight"
log " 2. Accéder à App Store Connect:"
log " ${CYAN}https://appstoreconnect.apple.com${NC}"
log " 3. Attendre le traitement Apple (5-15 min)"
log " 4. Configurer la conformité export si demandée"
log " 5. Ajouter des testeurs internes"
log " 6. Installer via TestFlight sur iPhone"
else
log " 1. ${YELLOW}${NC} Upload TestFlight a échoué"
log " 2. Réessayer manuellement:"
log " ${CYAN}ssh $MAC_USER@$MAC_MINI_IP \"cd ${DEST_DIR} && fastlane ios upload\"${NC}"
fi
else
log " 1. L'IPA est prêt sur le Mac mini"
log " 2. Pour uploader vers TestFlight:"
log " ${CYAN}ssh $MAC_USER@$MAC_MINI_IP \"cd ${DEST_DIR} && fastlane ios upload\"${NC}"
log " 3. Ou distribuer l'IPA manuellement via Xcode"
fi
log ""
log "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
log ""
log " ${BLUE}Log complet:${NC} ${LOG_FILE}"
log " ${BLUE}Fin:${NC} $(date '+%Y-%m-%d %H:%M:%S')"
log ""
# Nettoyer le log Fastlane temporaire
rm -f "${FASTLANE_LOG}"
exit 0