Un même projet Xcode peut compiler dans un répertoire de développement utilisé depuis longtemps, puis signaler des fichiers inexistants, des scripts introuvables ou des valeurs de configuration vides après sa copie dans un nouvel espace de travail Mac cloud VPSGit. Dans ce cas, ne commencez pas par transférer les anciens caches. Il faut d’abord vérifier qu’un build peut s’exécuter uniquement à partir du commit indiqué, d’une chaîne d’outils explicitement déclarée et des paramètres injectés par le pipeline.
Quels états isoler lors d’un clonage propre
Supprimer DerivedData n’écarte qu’une seule catégorie de cache et ne prouve pas que le projet est indépendant de la machine locale. Un espace de travail utilisé depuis longtemps accumule généralement des fichiers non commités, des configurations dans le répertoire utilisateur, des outils installés globalement, des scripts d’initialisation du Shell et des chemins absolus pointant hors du dépôt.
Il faut isoler au minimum les cinq couches suivantes :
- Utiliser un clone indépendant plutôt que nettoyer le répertoire d’origine.
- Créer des répertoires temporaires
HOMEetTMPDIRpour la tâche. - Affecter à DerivedData un répertoire propre à la tâche.
- Fixer
DEVELOPER_DIRafin d’éviter tout changement implicite de version de Xcode. - Ne transmettre au processus de build que des variables d’environnement autorisées.
L’objectif d’une validation par clonage propre n’est pas de « nettoyer une fois de plus » avant le build, mais de prouver qu’aucun état absent du dépôt, du manifeste des dépendances ou des paramètres du pipeline ne peut être utilisé silencieusement.
Lors du premier diagnostic, conservez un cas de référence : le build réussit dans l’espace de travail d’origine, mais échoue dans l’espace isolé. Les deux doivent utiliser le même commit, le même Scheme, la même Configuration et la même Destination afin que les différences observées soient réellement exploitables.
Créer un espace de travail isolé et temporaire
Le script ci-dessous crée depuis un dépôt existant un clone qui n’utilise pas les liens physiques locaux, extrait le commit indiqué, puis place le répertoire utilisateur, le répertoire temporaire et le cache de build dans un emplacement éphémère. Le nom du projet et le Scheme sont fournis en paramètres afin de ne pas figer les différences d’environnement dans le script.
#!/bin/bash
set -euo pipefail
SOURCE_REPO="${1:?source repository required}"
REVISION="${2:?revision required}"
PROJECT="${3:?project path required}"
SCHEME="${4:?scheme required}"
ROOT="$(mktemp -d "${TMPDIR:-/tmp}/clean-checkout.XXXXXX")"
trap 'rm -rf "$ROOT"' EXIT
git clone --no-local --no-checkout "$SOURCE_REPO" "$ROOT/repo"
git -C "$ROOT/repo" checkout --detach "$REVISION"
git -C "$ROOT/repo" submodule update --init --recursive
mkdir -p "$ROOT/home" "$ROOT/tmp" "$ROOT/DerivedData"
export HOME="$ROOT/home"
export TMPDIR="$ROOT/tmp"
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
cd "$ROOT/repo"
xcodebuild \
-project "$PROJECT" \
-scheme "$SCHEME" \
-configuration Debug \
-derivedDataPath "$ROOT/DerivedData" \
CODE_SIGNING_ALLOWED=NO \
build | tee "$ROOT/build.log"
CODE_SIGNING_ALLOWED=NO convient uniquement à la validation des étapes de compilation qui ne nécessitent pas de signature. Si la cible doit être archivée ou signée, les éléments requis doivent être injectés de manière sécurisée par la CI. Ne référencez pas de fichiers stockés dans le répertoire personnel d’un utilisateur simplement pour faire passer le script.
Faire apparaître au plus tôt les dépendances manquantes
Après le clonage, exécutez d’abord git status --porcelain ; la commande ne doit produire aucun résultat. Vérifiez ensuite l’état des sous-modules et la présence de tous les objets de fichiers volumineux. Si le projet comprend une étape de génération de code, distinguez clairement deux catégories d’artefacts : le code source et la version du générateur doivent être verrouillés ; les résultats générés doivent soit être commités conformément aux règles de l’équipe, soit être produits de manière reproductible pendant le build.
N’ajoutez pas ~/bin, /usr/local/bin ni le bureau d’un membre de l’équipe aux chemins de secours. Les outils auxiliaires doivent se trouver dans un répertoire d’outils du dépôt, être déclarés dans un manifeste de gestion de paquets avec une version contrainte, ou être installés dans une version fixe par le processus d’initialisation du nœud.
Identifier les entrées implicites à partir des journaux d’échec
Lorsqu’un build isolé échoue, recherchez la première erreur réelle plutôt que le récapitulatif situé à la fin du journal. Les signaux courants peuvent être classés selon le type d’entrée concerné :
| Signal d’échec | Cause fréquente | Piste de correction |
|---|---|---|
No such file or directory |
Fichier non commité ou chemin absolu | Ajouter le fichier au dépôt et utiliser un chemin relatif au dépôt |
command not found |
Dépendance à un Shell interactif ou à un outil global | Déclarer la version de l’outil et définir explicitement PATH |
| Valeur de configuration vide | Paramètre présent uniquement dans la configuration locale | L’injecter depuis la CI et échouer immédiatement s’il manque |
| Module visible dans l’ancien répertoire | Un cache partagé masque une dépendance manquante | Corriger la déclaration de dépendance au lieu de copier l’ancien cache |
| Erreur de permission sur un script | Le bit exécutable n’a pas été inclus dans le commit | Corriger le mode du fichier et créer un nouveau commit |
Les commandes suivantes permettent de vérifier si le commit courant contient réellement le fichier attendu et les permissions associées :
git ls-tree -r HEAD -- path/to/file
git status --short
git diff --summary HEAD
Si le chemin en erreur pointe vers /Users/某个名字/, il est généralement enregistré sous forme absolue dans la configuration du projet, un script ou un fichier généré. Corrigez la configuration source qui produit ce chemin au lieu de créer un répertoire du même nom sur le nouveau nœud.
Restreindre l’environnement sans provoquer de faux échecs
Utiliser directement env -i permet de détecter rapidement les dépendances à l’environnement, mais peut aussi supprimer le PATH, les paramètres régionaux et le répertoire temporaire nécessaires au build. Une approche plus fiable consiste à relever d’abord les variables effectivement lues par le build, puis à établir une liste blanche.
Il est recommandé de conserver HOME, TMPDIR, PATH, DEVELOPER_DIR, LANG ainsi que les paramètres métier explicitement injectés par le pipeline. Ajoutez un contrôle obligatoire pour chaque variable personnalisée, par exemple :
: "${API_BASE_URL:?API_BASE_URL must be provided by CI}"
: "${BUILD_FLAVOR:?BUILD_FLAVOR must be provided by CI}"
Une configuration manquante fera ainsi échouer le script dès son démarrage, plutôt que de provoquer une erreur ambiguë vers la fin de la compilation. Pour les valeurs sensibles, vérifiez uniquement leur présence sans les afficher dans les journaux. Le script de build ne doit pas non plus lire la configuration d’un Shell interactif, car ces fichiers peuvent ne jamais être chargés lors d’une tâche non interactive.
Intégrer la validation au pipeline quotidien
Un clone entièrement indépendant augmente l’utilisation du disque et le temps d’extraction ; il n’est donc pas nécessaire de bloquer chaque petit commit avec cette opération. La validation peut être divisée en deux niveaux : les tâches ordinaires réutilisent un espace de travail pour fournir un retour rapide, tandis que la validation par clonage propre s’exécute lors d’une fusion vers la branche principale, d’un changement de dépendance ou de version de Xcode, ainsi qu’avant une publication.
La validation ne doit réussir que si toutes les conditions suivantes sont remplies :
- Le commit indiqué peut être extrait intégralement dans un clone indépendant.
- L’arbre de travail ne contient aucune modification inattendue avant ou après le build.
- Le build ne lit ni l’espace de travail d’origine ni les répertoires personnels des utilisateurs.
- Tous les outils auxiliaires proviennent d’une source de version traçable.
- Les artefacts attendus sont toujours produits après suppression de DerivedData.
- Les journaux d’échec et le résumé de l’environnement permettent de reproduire le problème sans contenir de valeurs sensibles.
Lorsqu’une validation par clonage propre échoue alors qu’un build ordinaire réussit, considérez ce résultat comme un défaut de déclaration des dépendances. Corrigez d’abord les limites des entrées, puis seulement la restauration des caches. Maintenir cette validation dans la durée transforme la prise de relais par de nouveaux nœuds, l’extension parallèle de la capacité et les mises à niveau de la chaîne d’outils en processus d’ingénierie reproductibles, plutôt qu’en essais aléatoires sur une autre machine.
Questions fréquentes
Pourquoi git clean ne suffit-il pas pour cette vérification ?
git clean ne supprime que les fichiers non suivis de l’arborescence courante. Il n’isole ni le HOME, ni les outils globaux, ni les caches partagés, ni le Keychain, ni les chemins externes au dépôt.
Que faut-il examiner en premier après l’échec du build propre ?
Comparez d’abord les chemins d’entrée et les variables d’environnement de la commande en échec, puis vérifiez les sous-modules, fichiers volumineux, générateurs, configurations et outils déclarés.
Faut-il exécuter ce contrôle à chaque commit ?
Ce n’est pas nécessaire. Gardez un contrôle rapide au quotidien et lancez l’isolation complète avant une livraison, après une mise à jour de Xcode ou des dépendances, et lors des fusions majeures.
Configurez un Mac cloud pour votre prochain build ou votre prochaine tâche d’inférence
Choisissez parmi trois configurations Apple Silicon, six nœuds et des durées de location fixes. La disponibilité réelle est indiquée en temps réel dans la console.