Aller au contenu principal

Résolution en cascade et shorebird.yaml

Pour s'intégrer de manière fluide dans des projets Flutter simples comme dans des architectures d'entreprise multi-environnements (dev, staging, uat, prod), la CLI tk-ota-push implémente un moteur de résolution en cascade déterministe (lib/src/cli/project.dart).

Ce mécanisme permet d'exécuter tk-ota-push release ou tk-ota-push patch sans configuration redondante, tout en garantissant que les identifiants d'application, les URLs d'API et les clés cryptographiques sont résolus avec une priorité absolue accordée aux paramètres explicites.


1. Priorité de résolution des paramètres globaux​

Lorsqu'une commande est exécutée, chaque paramètre de configuration est résolu selon l'ordre strict suivant (du plus prioritaire au moins prioritaire) :

Ordre de résolution des paramètres de configuration
  1. Options en ligne de commande : Flags explicites (--server, --app-id, etc.).
  2. Variables d'environnement : $OTA_SERVER_URL, $OTA_API_KEY, etc.
  3. Session utilisateur active : Fichier de session locale ~/.tk_ota_push/credentials.json.
  4. Fichier de configuration : Fichier shorebird.yaml à la racine du projet Flutter.

Tableau de cascade par paramètre​

Paramètre1. Flag CLI2. Variable d'environnement3. Session active4. shorebird.yaml5. Détection native / Défaut
app_id--app-idOTA_APP_ID, APP_ID—environments.<env>, flavors.<flavor>, app_idbuild.gradle (applicationId) ou project.pbxproj (PRODUCT_BUNDLE_IDENTIFIER)
server--serverOTA_SERVER_URL, SHOREBIRD_BASE_URL—base_urlhttp://localhost:8080
tenant_id--tenant-idOTA_TENANT_IDsession.tenantIdtenant_iddefault
token / API Key—OTA_API_KEYsession.accessToken (avec auto-refresh)—Aucun (requête non authentifiée)
channel-c, --channel——channelstable
web_console_url--web-urlOTA_WEB_CONSOLE_URLsession.webConsoleUrlweb_console_urlhttp://localhost:3000
countries--countries——geo.default_countries ou rollout.countriesnull (Mondial / Tous pays)

2. Cascade de résolution de l'app_id (resolveEffectiveAppId)​

L'identifiant de l'application (app_id) est l'élément central identifiant votre projet dans la base de données OTA. La méthode FlutterProject.resolveEffectiveAppId inspecte successivement 9 niveaux d'autorité :

1. Flag CLI explicite : --app-id <id>
└── Surcharge absolue, prioritaire sur tout le reste.

2. Variable injectée via --dart-define :
└── Inspecte APP_ID, SHOREBIRD_APP_ID, APPLICATION_ID ou OTA_APP_ID.

3. Fichier injecté via --dart-define-from-file :
└── Parse les fichiers JSON, YAML ou .env passés en argument à la recherche des mêmes clés.

4. Déduction du nom d'environnement actif (deduceEnvironmentName) :
├── --env <nom> ou --flavor <nom>
├── --dart-define ENV=... ou ENVIRONMENT=... ou FLAVOR=...
├── --target lib/main_<env>.dart (ex: lib/main_dev.dart -> "dev")
└── --dart-define-from-file env/<env>.json (ex: env/staging.json -> "staging")

5. Mapping d'environnement dans shorebird.yaml :
├── Section environments.<env>
└── Section flavors.<env>

6. Fichiers de configuration locaux du projet :
└── Cherche env/<env>.json, config/<env>.json, .env.<env>, env/.env.<env>, environments/<env>.json.

7. Champ racine de shorebird.yaml :
└── app_id: "..."

8. Variables d'environnement système :
└── $OTA_APP_ID ou $APP_ID

9. Détection native automatique déterministe :
├── Android : android/app/build.gradle[.kts] (applicationId, namespace, productFlavors, buildTypes)
└── iOS : ios/Runner.xcodeproj/project.pbxproj (PRODUCT_BUNDLE_IDENTIFIER) ou ios/Runner/Info.plist

3. Structure complète du fichier shorebird.yaml​

Le fichier shorebird.yaml doit être placé à la racine du projet Flutter (aux côtés de pubspec.yaml). Voici un exemple exhaustif de configuration d'entreprise :

# ==============================================================================
# Configuration OTA TkushPatch / Shorebird
# ==============================================================================

# Identifiant par défaut de l'application (fallback universel)
app_id: "com.entreprise.superapp"

# Identifiant du Tenant (multi-entités / multi-organisations)
tenant_id: "banque-atlantique"

# URL du Control Plane Serveur TkushPatch On-Premise
base_url: "https://ota.cloud.entreprise.internal"

# URL du portail d'administration Web (utilisé pour tk-ota-push login)
web_console_url: "https://console-ota.cloud.entreprise.internal"

# Canal de distribution par défaut
channel: "stable"

# Clé publique clé publique de signature (Base64) synchronisée depuis le serveur
patch_public_key: |
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyN6K7...

# ------------------------------------------------------------------------------
# Mapping multi-environnements / multi-flavors
# ------------------------------------------------------------------------------
environments:
dev: "com.entreprise.superapp.dev"
staging: "com.entreprise.superapp.staging"
uat: "com.entreprise.superapp.uat"
prod: "com.entreprise.superapp"

# Alias supporté pour la compatibilité Shorebird standard
flavors:
dev: "com.entreprise.superapp.dev"
staging: "com.entreprise.superapp.staging"
prod: "com.entreprise.superapp"

# ------------------------------------------------------------------------------
# Ciblage géographique par défaut (Geo-Rollout)
# ------------------------------------------------------------------------------
geo:
default_countries:
- CI
- SN
- CM
- BF
Injection automatique dans shorebird.yaml

Lorsqu'un projet ne possède pas d'app_id explicite dans son shorebird.yaml, la méthode ensureShorebirdYamlAppId() injecte automatiquement l'app_id résolu à la première ligne du fichier avant la compilation. Cela garantit que le moteur C++/Rust de Shorebird l'embarque dans les assets binaires de l'application.


4. Détection native automatique (Zéro-Config)​

Si vous n'avez pas encore configuré shorebird.yaml, tk-ota-push est capable de déduire l'identifiant directement depuis les sources natives :

Sous Android (build.gradle.kts ou build.gradle)​

La méthode _detectAndroidApplicationId inspecte :

  1. La directive applicationId ou namespace dans defaultConfig.
  2. Si un --flavor ou --env est spécifié (ex: dev), elle recherche le bloc productFlavors ou buildTypes correspondant et extrait un applicationId spécifique ou applique le suffixe applicationIdSuffix (ex: com.entreprise.app.dev).
  3. En dernier recours, elle parse android/app/src/main/AndroidManifest.xml pour récupérer l'attribut package.

Sous iOS (project.pbxproj ou Info.plist)​

La méthode _detectIosBundleId inspecte :

  1. ios/Runner.xcodeproj/project.pbxproj à la recherche de PRODUCT_BUNDLE_IDENTIFIER (en filtrant les cibles de tests RunnerTests).
  2. Si un flavor est spécifié, elle sélectionne l'identifiant contenant le nom du flavor.
  3. En dernier recours, elle lit la clé CFBundleIdentifier dans ios/Runner/Info.plist.

5. Exemples concrets de résolution​

Scénario A : Projet monolithique standard​

  • pubspec.yaml présent
  • build.gradle avec applicationId "com.example.monapp"
  • Aucun shorebird.yaml
tk-ota-push release 1.0.0+1 -p android

Résultat : L'app_id est automatiquement détecté comme com.example.monapp. Un fichier shorebird.yaml est généré avec app_id: "com.example.monapp".

Scénario B : Multi-Flavors avec fichier JSON​

  • shorebird.yaml avec section environments
  • Commande exécutée avec --dart-define-from-file=env/staging.json
tk-ota-push patch 1.0.0+1 -p android --dart-define-from-file=env/staging.json

Résultat : deduceEnvironmentName() extrait staging depuis le nom du fichier env/staging.json, puis résout l'app_id configuré dans environments.staging.