Journal d’ingénierie

Rendre l’environnement Homebrew d’un Mac cloud reproductible avec Brewfile

Rendre l’environnement Homebrew d’un Mac cloud reproductible avec Brewfile

Après plusieurs semaines de builds continus sur un Mac dans le cloud, le problème d’environnement le plus courant n’est généralement pas l’absence d’un outil, mais le fait que différents outils aient été installés à différents moments par différentes personnes. Une tâche dépend de jq, un autre script suppose que swiftlint est présent, tandis que des interventions ponctuelles ont laissé plusieurs formules sur la machine. Lorsqu’une nouvelle machine prend le relais, copier uniquement le dépôt ne permet pas de recréer cette couche de dépendances système. Un Brewfile répond bien à la question « de quels outils avons-nous besoin ? », mais ce n’est pas un fichier de verrouillage des versions exactes. Une approche fiable consiste à gérer séparément les déclarations, les preuves de version et la procédure de nettoyage.

Commencer par auditer la machine plutôt que tout exporter

Vérifiez d’abord le chemin de Homebrew et l’architecture actuelle afin d’éviter que les scripts continuent d’utiliser un ancien chemin provenant d’une autre installation.

command -v brew
brew --prefix
uname -m
brew doctor

Examinez ensuite séparément les formules de premier niveau, toutes les versions installées et les services en arrière-plan :

brew leaves
brew list --formula --versions
brew services list

brew leaves constitue un meilleur point de départ qu’une liste exhaustive, car cette commande affiche principalement les outils de premier niveau installés explicitement. La liste complète des versions doit plutôt être archivée comme preuve de l’environnement de build, et non copiée telle quelle dans le Brewfile.

N’effectuez aucune mise à niveau ni aucun nettoyage tant que des tâches de build sont en cours. Commencez par interrompre leur distribution, puis vérifiez qu’aucun compilateur, aucune base de données et aucun service auxiliaire ne sont encore utilisés par un processus.

Si la machine est utilisée depuis longtemps, commencez par exporter un fichier candidat, puis examinez-le ligne par ligne :

mkdir -p ci/homebrew
brew bundle dump --force --file=ci/homebrew/Brewfile.candidate
git diff -- ci/homebrew/Brewfile.candidate

Ce fichier candidat peut contenir des outils personnels, des logiciels de débogage temporaires ou des applications graphiques sans rapport avec le projet. Seuls les éléments réellement nécessaires aux builds et au diagnostic doivent figurer dans la liste définitive.

Utiliser le Brewfile comme déclaration des besoins

Une liste de base destinée aux builds continus iOS peut rester très courte :

brew "git"
brew "jq"
brew "swiftlint"
brew "xcbeautify"

Enregistrez le fichier sous ci/homebrew/Brewfile dans le dépôt et indiquez explicitement son chemin lors de l’installation :

brew bundle check --file=ci/homebrew/Brewfile
brew bundle install --file=ci/homebrew/Brewfile --no-upgrade

La commande check convient au point d’entrée des tâches. Elle vérifie uniquement que les déclarations sont satisfaites ; elle ne doit pas déclencher automatiquement une mise à niveau complète à chaque build. La commande install --no-upgrade installe les outils manquants tout en réduisant le risque qu’un build ordinaire modifie accidentellement l’environnement existant.

Séparer les listes selon leur rôle

Si un même Mac cloud VMKeep doit prendre en charge plusieurs types de travaux, il est préférable de séparer la liste de base de celle du projet. La couche de base peut, par exemple, contenir uniquement Git, les outils de traitement JSON et les utilitaires de journalisation, tandis que la couche du projet ajoute les outils de contrôle du code ou d’aide à la publication. L’ordre d’installation doit rester fixe : la couche de base d’abord, puis celle du projet.

N’utilisez pas un Brewfile global en croissance permanente pour couvrir tous les dépôts. Il deviendrait difficile d’évaluer l’impact de chaque nettoyage et pourrait conduire un nouveau projet à considérer, à tort, des outils historiques comme ses propres dépendances indispensables.

Enregistrer séparément les versions et le contexte d’exécution

Un Brewfile ne verrouille généralement pas les formules ordinaires sur une version exacte. Le fait que deux machines possèdent la même liste ne garantit donc pas qu’elles produiront le même résultat. Après chaque modification de l’environnement, enregistrez un instantané des versions réellement installées :

{
  date -u
  sw_vers
  xcodebuild -version
  brew --version
  brew list --formula --versions
} > ci/homebrew/toolchain.snapshot.txt

Cet instantané peut être conservé comme artefact du pipeline ou ajouté au journal d’exploitation après une mise à niveau de l’environnement dûment examinée. En cas d’écart, comparez d’abord les versions de Xcode, de macOS, de Homebrew et des dépendances directes, puis contrôlez les fichiers de verrouillage du projet. Ne commencez pas par supprimer tous les caches.

Définir clairement les limites de version

brew pin empêche uniquement les mises à niveau locales sur la machine actuelle. Cette commande ne garantit pas qu’une nouvelle machine pourra encore obtenir la même version historique. Elle peut donc servir de protection à court terme, mais ne remplace ni une image de machine figée, ni un gestionnaire de versions propre au projet, ni des artefacts binaires vérifiés.

Pour les outils qui influencent directement les livrables, les scripts doivent vérifier au démarrage que leur version se situe dans une plage acceptable et échouer explicitement dans le cas contraire. Une plage plus large peut être autorisée pour les outils servant uniquement à améliorer la présentation des journaux, afin qu’une différence non critique n’interrompe pas le build.

Nettoyer sans risque grâce à un aperçu et à une fenêtre d’inactivité

Avant tout nettoyage effectif, affichez les éléments qui ne figurent pas dans le Brewfile :

brew bundle cleanup --file=ci/homebrew/Brewfile

Cette étape sert uniquement à examiner la sortie. Exécutez les commandes suivantes seulement après avoir confirmé que les formules répertoriées ne sont utilisées par aucun autre projet, LaunchAgent ou service en arrière-plan :

brew bundle cleanup --file=ci/homebrew/Brewfile --force
brew autoremove
brew cleanup

La prudence est particulièrement importante sur les machines partagées : l’absence d’une formule dans le Brewfile du dépôt actuel ne signifie pas qu’aucune autre tâche ne l’utilise. Une séparation plus fiable consiste à affecter un nœud physique dédié à chaque catégorie de charge de travail durable ou, au minimum, à utiliser des comptes d’exécution, des répertoires de travail et des listes distincts.

Après le nettoyage, exécutez de nouveau brew bundle check, puis une chaîne minimale de validation : affichez les versions des outils, analysez la configuration du projet et réalisez un build sans publier les livrables. La modification de l’environnement n’est terminée que lorsque ces trois étapes ont réussi.

Faire de chaque modification de l’environnement un événement révisable

Un processus stable ne doit pas permettre aux scripts de build d’exécuter brew install de manière improvisée. Lors de l’ajout d’un outil, le commit doit inclure la modification du Brewfile, une description de son usage, un instantané des versions et une procédure de retour arrière. Les mises à niveau doivent être réalisées dans une fenêtre dédiée : validez d’abord des projets représentatifs, puis réactivez la distribution des tâches.

Il est recommandé de limiter les contrôles courants à quatre points :

  1. brew bundle check réussit-il ?
  2. Les versions de Xcode et des formules essentielles correspondent-elles aux attentes ?
  3. Le Brewfile contient-il des modifications qui n’ont pas été examinées ?
  4. Des services en arrière-plan non déclarés sont-ils toujours en cours d’exécution ?

La valeur d’un Brewfile ne réside pas dans l’installation automatique de tous les outils possibles, mais dans la transformation des dépendances système, auparavant simples faits établis sur une machine, en déclarations stockées dans le dépôt, discutables, comparables et réversibles. Associé à des instantanés de versions et à un nettoyage prudent, il permet de remplacer les suppositions ponctuelles sur l’environnement d’un Mac cloud par des écarts de configuration étayés par des preuves.

Questions fréquentes

Brewfile verrouille-t-il précisément les versions des paquets Homebrew ?

Non. Brewfile décrit les outils requis, mais les formules ordinaires suivent les mises à jour du dépôt. Pour une version exacte, conservez un relevé des versions et utilisez une image fixe ou un gestionnaire propre au projet.

Peut-on lancer directement brew bundle cleanup --force sur un Mac partagé ?

Non. Commencez sans --force pour examiner la liste, vérifiez qu’aucune autre tâche ne dépend des outils concernés, puis effectuez le nettoyage pendant une période d’inactivité.

Nœud physique dédié

Poursuivez la validation de ce workflow sur un Mac dans le cloud

Choisissez la mémoire, le stockage, le nœud et la durée de location adaptés parmi trois configurations Apple Silicon.

Choisir une configuration et commander