Mise en place du CI/CD avec GitLab CI et Fastlane d’un projet iOS, avec Déploiement sur Firebase Distribution
Mise en place d’un pipeline CI/CD complet pour un projet iOS, avec GitLab CI pour automatiser la compilation, les tests et le déploiement.
Introduction
Dans le monde moderne du DevOps, le CI/CD (Continuous Integration/Continuous Deployment) est devenu essentiel pour gérer efficacement les projets de développement logiciel. Que ce soit pour les développeurs, les ingénieurs cloud, ou les architectes de données, les compétences en CI/CD sont aujourd’hui incontournables. Ces pratiques permettent aux équipes de développement et d’opérations de travailler ensemble plus efficacement en automatisant le build, les tests et le déploiement des applications, facilitant ainsi la collaboration et l’amélioration continue des projets.
Qu’est-ce que l’Intégration Continue (CI) ?
L’Intégration Continue (CI) est une pratique permettant aux développeurs d’être plus productifs tout en écrivant du code de meilleure qualité. Concrètement, l’intégration continue consiste à intégrer régulièrement les modifications du code dans une branche principale partagée par tous les développeurs. Chaque modification du code est automatiquement testée et une compilation est lancée à chaque commit ou merge. Grâce à cette pratique, les erreurs et problèmes de sécurité sont détectés et corrigés plus tôt dans le cycle de développement, ce qui rend le processus global plus fluide.
Qu’est-ce que la Livraison Continue (CD) ?
La Livraison Continue (CD) prend le relais là où s’arrête l’intégration continue. Cette pratique automatise la livraison des applications dans différents environnements, que ce soit pour les tests ou pour la production. Avec la livraison continue, chaque modification du code est automatiquement prête à être déployée, ce qui permet de livrer des nouvelles fonctionnalités ou des correctifs rapidement, sans besoin d’interventions manuelles répétées.
Workflow de CI/CD
Voici comment fonctionne le flux de CI/CD avec GitLab CI:
- Modification du code : On apporte des modifications au code et on pousse un commit sur GitLab.
- Déclenchement par GitLab : GitLab détecte automatiquement le changement dans le code source.
- Exécution du pipeline CI : GitLab déclenche une compilation et exécute les commandes définis dans le fichier .yml en utilisant le GitLab Runner.
- Rapport des résultats : Le GitLab Runner envoie les résultats à GitLab.
- Visualisation des résultats : GitLab affiche les résultats du build et des tests, en indiquant si tout s’est bien passé ou si des corrections sont nécessaires.
- Déploiement : Si le build et les tests sont réussis, le pipeline peut automatiser le déploiement de l’application.
Automatiser les tâches répétitives, telles que les compilations, les tests, et les déploiements, devient indispensable au fur et à mesure que le projet avance, surtout lorsque les deadlines se rapprochent. Ces tâches peuvent rapidement devenir un vrai casse-tête. Heureusement, avec GitLab CI et Fastlane, on peut non seulement éviter les clics manuels interminables sur le bouton “Build” de Xcode, mais aussi s’assurer que tout est testé et prêt à être déployé automatiquement. Cela nous permet de nous concentrer sur ce qui compte vraiment : coder…
Dans cet article, on va vous guider à travers la mise en place d’un pipeline CI/CD en utilisant GitLab CI pour automatiser les builds et tests de notre projet, et Fastlane pour le déploiement. Tout ça, bien sûr, avec une touche finale de Firebase pour distribuer l’application aux testeurs via Firebase App Distribution. Si l’idée d’automatiser tout ce processus vous séduit, vous êtes au bon endroit. C’est parti!
Étape 1 : Configuration du projet iOS
1. Partager le Scheme du projet: Dans Xcode, on doit rendre le scheme du projet “shared”. Pourquoi ? C’est pour que GitLab Runner puisse le détecter et l’utiliser. Sans cela, impossible de compiler automatiquement. C’est une petite case à cocher dans Xcode, mais elle fait toute la différence.
2. Tests Unitaires: On s’assure d’avoir un target de tests unitaires dans le projet. Ces tests seront lancés automatiquement à chaque build, ce qui permet de garantir que tout fonctionne correctement.
3. Fichier .gitignore: Télécharger un fichier .gitignore pour exclure les fichiers inutiles (comme les paramètres spécifiques à Xcode). Cela permet de garder le dépôt propre et évite de partager des fichiers qui n’ont rien à voir avec le projet. On peut exécuter cette commande dans le répertoire de notre projet pour télécharger un modèle adapté aux projets iOS:
curl -o .gitignore https://www.gitignore.io/api/swift
4. Installation de xcpretty On installe xcpretty pour rendre les logs de Xcode plus lisibles dans GitLab CI.
sudo gem install xcpretty
Étape 2 : Création du Runner pour le projet dans GitLab
Pour que GitLab puisse exécuter les pipelines CI/CD, il faut un GitLab Runner. GitLab Runner est un service qui exécute des tâches définies dans le fichier .gitlab-ci.yml. Il automatise les étapes de build, test et déploiement de l’application.
Pour plus d’informations sur GitLab Runner, consultez la documentation officielle.
1. Installer GitLab Runner
On commence par installer GitLab Runner sur la machine:
brew install gitlab-runner
2. Enregistrer le Runner
Ensuite, il faut enregistrer ce runner dans le projet GitLab. Pour ça, on se rend sur l’interface de GitLab, dans les paramètres du projet sous “Settings” > “CI/CD” > “Runners”, on crée un nouveau runneret on ajoute un tag dont on aura besoin plus tard lors de la configuration.
On copie la commande d’enregistrement. Ensuite, on l’exécute dans le terminal :
gitlab-runner register
Voici quelques informations utiles à configurer :
- URL de GitLab : https://gitlab.com (si on utilise GitLab.com).
- Token d’enregistrement : fourni par GitLab lors de la création du runner.
- Executor : On choisit shell pour exécuter les tâches en local.
3. Lancer le Runner
Maintenant que tout est configuré, on peut lancer le runner avec la commande :
gitlab-runner run
4. Vérifier le statut du Runner
Pour être sûr que tout est prêt, on vérifie que le runner est actif et disponible avec :
gitlab-runner verify
Étape 3 : Création du fichier .gitlab-ci.yml
Le fichier .gitlab-ci.yml est le chef d’orchestre de tout le processus CI/CD. C’est là que l’on définit les différentes étapes que GitLab CI doit suivre.
Voici le fichier dans notre exemple :
stages:
- build
build_project:
stage: build
script:
# Clean the project
- xcodebuild clean -project Swiftui_Demo.xcodeproj -scheme Swiftui_Demo
# Create the reports directory before generating files
- mkdir -p build/reports
# Run tests and generate the xcresult file
- xcodebuild test -project Swiftui_Demo.xcodeproj -scheme Swiftui_Demo -destination 'platform=iOS Simulator,name=iPhone 16 Plus,OS=18.0' -enableCodeCoverage YES -resultBundlePath build/reports/Test.xcresult | tee build/reports/xcodebuild.log
# Use xccov to extract the coverage report from the xcresult bundle
- xcrun xccov view - report - json build/reports/Test.xcresult > build/reports/coverage.json
# Extract the coverage from the JSON and print it in the logs for GitLab to capture
- COVERAGE=$(cat build/reports/coverage.json | jq '.lineCoverage * 100')
- echo "Code Coverage || $COVERAGE%"
tags:
- ci_cd_demo # Make sure this tag matches the runner's tag
artifacts:
when: always
paths:
- build/reports/xcodebuild.log
- build/reports/coverage.json # Store the coverage report as an artifact
coverage: '/Code coverage: \d+(?:\.\d+)?/' # Capture the coverage from the printed output
Et maintenant, dès qu’on effectue un push de notre fichier yml, dans la section Pipelines, on peut voir que le clean build est en cours et que les tests unitaires se lancent automatiquement. Si tout se passe bien, le statut devrait être Passed.
Pour s’assurer que notre build, notre pipeline et notre runner fonctionnent correctement, on peut modifier notre test unitaire pour qu’il échoue. Ainsi, on pourra vérifier que le statut du pipeline est bien Failed.
Étape 4 : Installation et configuration de Fastlane
Fastlane est un outil open-source conçu pour automatiser la gestion des builds, les tests et les déploiements d’applications mobiles. Il simplifie la configuration et permet de gagner du temps en automatisant les tâches répétitives.
Pour en savoir plus sur Fastlane et ses fonctionnalités, rendez-vous sur la documentation officielle.
1. Installer Fastlane
On commence par installer Fastlane avec la commande suivante :
sudo gem install fastlane -NV
2. Initialiser Fastlane
Ensuite, dans le répertoire de notre projet, on lance la commande pour initialiser Fastlane :
fastlane init
Quand on arrive au choix du setup, on sélectionne Option 4 — Manual setup, parce qu’on aime bien garder un peu de contrôle sur ce qui se passe.
3. Configurer Gym pour la compilation
Gym est le module de Fastlane qui permet de gérer la compilation des projets iOS. On l’initialise avec :
fastlane gym init
Étape 5 : Mise en place de Firebase App Distribution
Firebase App Distribution est une plateforme qui permet de distribuer des versions bêta d’applications mobiles aux testeurs de manière simple et rapide, en rendant les builds disponibles directement via Firebase. On va utiliser Fastlane pour automatiser ce processus.
Tout d’abord on doit créer un projet sur Firebase Console et y ajouter une application iOS, en utilisant bien sûr le même bundle ID que celui de notre projet iOS.
1. Ajouter le plugin Firebase à Fastlane
D’abord, on ajoute le plugin Firebase à Fastlane avec cette commande :
fastlane add_plugin firebase_app_distribution
2. Authentification Firebase
Pour uploader les builds sur Firebase, il faut s’authentifier. On génère un token Firebase en exécutant cette commande :
firebase login:ci
Ensuite, on utilise le token pour configurer le fastfile.
3. Modifier le fichier Fastfile
On ajoute une lane dans le fichier Fastfile qui va uploader automatiquement notre build sur Firebase Distribution :
default_platform(:ios)
platform :ios do
desc "Build and upload .ipa to Firebase Distribution"
lane :upload_to_firebase do
scheme = "Swiftui_Demo"
# Clean before build
clear_derived_data
# Build the .ipa file
build_app(
scheme: scheme,
export_method: "development",
configuration: "Debug"
)
# Upload to Firebase Distribution
firebase_app_distribution(
app: "app_id dans la console de firebase",
ipa_path: "./build/Swiftui_Demo.ipa",
groups: "testers",
firebase_cli_token: "$FIREBASE_TOKEN",
release_notes: "Automatic build and upload via Fastlane"
)
end
end
Étape 6 : Automatisation du déploiement sur Firebase:
Tout est en place maintenant, il ne reste plus qu’à apporter les modifications nécessaires au fichier yml pour lancer le clean build, exécuter les tests unitaires, puis effectuer le déploiement automatique vers Firebase Distribution à chaque push.
stages:
- build
- deploy
build_project:
stage: build
script:
# Clean the project with verbose output
- xcodebuild clean -project Swiftui_Demo.xcodeproj -scheme Swiftui_Demo
# Create the reports directory before generating files
- mkdir -p build/reports
# Run tests and generate the xcresult file
- xcodebuild test -project Swiftui_Demo.xcodeproj -scheme Swiftui_Demo -destination 'platform=iOS Simulator,name=iPhone 16 Plus,OS=18.0' -enableCodeCoverage YES -resultBundlePath build/reports/Test.xcresult | tee build/reports/xcodebuild.log
# Use xccov to extract the coverage report from the xcresult bundle
- xcrun xccov view --report --json build/reports/Test.xcresult > build/reports/coverage.json
# Extract the coverage from the JSON and print it in the logs for GitLab to capture
- COVERAGE=$(cat build/reports/coverage.json | jq '.lineCoverage * 100')
- echo "Code Coverage || $COVERAGE%"
tags:
- ci_cd_demo # Make sure this tag matches the runner's tag
artifacts:
when: always
paths:
- build/reports/xcodebuild.log
- build/reports/coverage.json # Store the coverage report as an artifact
coverage: '/Code coverage: \d+(?:\.\d+)?/' # Capture the coverage from the printed output
upload_to_firebase:
stage: deploy
script:
# Run the Fastlane lane to upload to Firebase
- fastlane upload_to_firebase
tags:
- ci_cd_demo # Make sure this tag matches the runner's tag
Si tout se passe bien, le statut devrait Passed pour les deux scripts. Et si on se rend vers firebase distribution on devrait voir un build de notre application.
Étape 7 : Résolution des erreurs courantes
Erreur : Xcode Tools non détecté
On peut parfois rencontrer l’erreur suivante :
xcode-select: error: tool 'xcodebuild' requires Xcode but active developer directory is a command line tools instance
Solution :
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
Problèmes avec les permissions du Runner
Si le runner ne peut pas accéder à certains fichiers ou dossiers lors de l’exécution du pipeline, assurez-vous que les permissions sont correctement définies. Vous pouvez exécuter chmod -R 755 <dossier> pour donner les permissions nécessaires.
Problèmes avec .bash_profile, shell not found
Si le pipeline échoue sans explication après l’initialisation du Fastlane dans le projet et le gitlab-runner renvoie une erreur shell not found, il se peut que les fichiers .bash_profile et .profile soient mal configurés. Il suffit de faire une petite modification pour que tout fonctionne à nouveau.
Solution:
- Supprimer les lignes
"[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session as a function"
dans les fichiers ~/.bash_profile et ~/.profile
2. Ajouter
source "$HOME/.rvm/scripts/rvm"
dans .gitlab-ci.yml, dans before_script, pour définir la version de Ruby à utiliser avec RVM lorsque le pipeline s’exécute.
Conclusion
Et voilà ! On a mis en place un pipeline CI/CD complet pour un projet iOS, avec GitLab CI pour automatiser la compilation, les tests et le déploiement, Fastlane pour gérer le déploiement, et Firebase Distribution pour partager les builds avec nos testeurs. Ce processus permet de gagner du temps et d’éviter les erreurs manuelles tout en garantissant des versions plus fiables et plus rapides.
Mais ce n’est pas tout, ce même processus peut facilement être adapté pour déployer l’application via TestFlight ou directement sur l’App Store. Fastlane simplifie également la gestion des certificats, des profils de provisioning, et la soumission de builds vers TestFlight ou l’App Store Connect, rendant l’intégration avec ces plateformes tout aussi fluide.
Cependant, GitLab CI n’est qu’une des nombreuses options disponibles pour implémenter des pipelines CI/CD. Si vous recherchez d’autres solutions, vous pourriez envisager des outils comme Jenkins et Bitrise, qui apportent chacun des avantages spécifiques selon vos besoins.
Jenkins est un outil CI/CD extrêmement populaire, principalement en raison de sa flexibilité et de son extensibilité. Jenkins offre une immense bibliothèque de plugins qui permet d’adapter chaque aspect du pipeline à des besoins spécifiques, ce qui en fait un excellent choix pour des projets complexes ou multi-équipes.
De son côté, Bitrise est conçu spécifiquement pour les projets mobiles. Bitrise propose une interface utilisateur intuitive, des workflows préconfigurés et une infrastructure entièrement hébergée, simplifiant ainsi le processus pour les développeurs mobiles. Il offre également une intégration native avec Fastlane, facilitant l’automatisation des builds, des tests et des déploiements d’applications iOS ou Android.
Maintenant, on peut se concentrer sur l’essentiel : coder des fonctionnalités impressionnantes, sans se soucier de la partie déploiement ! 🎉
L’auteur : Seifallah Selmi • LinkedIn