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) :
- Options en ligne de commande : Flags explicites (
--server,--app-id, etc.). - Variables d'environnement :
$OTA_SERVER_URL,$OTA_API_KEY, etc. - Session utilisateur active : Fichier de session locale
~/.tk_ota_push/credentials.json. - Fichier de configuration : Fichier
shorebird.yamlà la racine du projet Flutter.
Tableau de cascade par paramètre
| Paramètre | 1. Flag CLI | 2. Variable d'environnement | 3. Session active | 4. shorebird.yaml | 5. Détection native / Défaut |
|---|---|---|---|---|---|
app_id | --app-id | OTA_APP_ID, APP_ID | — | environments.<env>, flavors.<flavor>, app_id | build.gradle (applicationId) ou project.pbxproj (PRODUCT_BUNDLE_IDENTIFIER) |
server | --server | OTA_SERVER_URL, SHOREBIRD_BASE_URL | — | base_url | http://localhost:8080 |
tenant_id | --tenant-id | OTA_TENANT_ID | session.tenantId | tenant_id | default |
token / API Key | — | OTA_API_KEY | session.accessToken (avec auto-refresh) | — | Aucun (requête non authentifiée) |
channel | -c, --channel | — | — | channel | stable |
web_console_url | --web-url | OTA_WEB_CONSOLE_URL | session.webConsoleUrl | web_console_url | http://localhost:3000 |
countries | --countries | — | — | geo.default_countries ou rollout.countries | null (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
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 :
- La directive
applicationIdounamespacedansdefaultConfig. - Si un
--flavorou--envest spécifié (ex:dev), elle recherche le blocproductFlavorsoubuildTypescorrespondant et extrait unapplicationIdspécifique ou applique le suffixeapplicationIdSuffix(ex:com.entreprise.app.dev). - En dernier recours, elle parse
android/app/src/main/AndroidManifest.xmlpour récupérer l'attributpackage.
Sous iOS (project.pbxproj ou Info.plist)
La méthode _detectIosBundleId inspecte :
ios/Runner.xcodeproj/project.pbxprojà la recherche dePRODUCT_BUNDLE_IDENTIFIER(en filtrant les cibles de testsRunnerTests).- Si un flavor est spécifié, elle sélectionne l'identifiant contenant le nom du flavor.
- En dernier recours, elle lit la clé
CFBundleIdentifierdansios/Runner/Info.plist.
5. Exemples concrets de résolution
Scénario A : Projet monolithique standard
pubspec.yamlprésentbuild.gradleavecapplicationId "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.yamlavec sectionenvironments- 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.