Une semaine avant le lancement du Phone 18, personne dans la salle ne parlait de focale caméra — tout le monde fixait une liste Actions pleine de pastilles rouges. Xcode 27, le SDK iOS 27, le label hébergé GitHub xcode-27, plus quelques runners Apple Silicon self-hosted tout juste branchés : quatre lignes la même semaine. Si l’une dérive, captures App Store et bêta TestFlight s’arrêtent ensemble. Nous avons refait toute la CI/CD iOS — de « ça passe au vert » à « ça tient la semaine de lancement » — et noté ici les vrais pièges.
L’ancre temporelle est nette : le 10 septembre 2026, GitHub écrit dans le Changelog que l’image runner Xcode 27 tourne désormais sur macOS 27 — labels toujours xcode-27 / xcode-27-xlarge, et arm64 uniquement. Un job encore « vert par chance » la veille sur base macOS 26 peut basculer en masse après le cut d’image : version OS, nom de simulateur, ou niveau disque. Pour la fenêtre GA Golden Gate et le cutoff machines, voir en interne macOS 27 Golden Gate : date de sortie et modèles supportés ; ici, uniquement le côté CI : où ça casse, comment on range.
Pourquoi tout rejouer avant le lancement — pas juste retoucher la matrix
Réflexe courant : passer xcode-version de 26 à 27, destination en iPhone 18. Avant la fenêtre Phone 18, ça explose presque toujours. Trois couches. Première : SDK et image runner ne sortent pas synchrones — en local Xcode 27 GM, l’image hébergée encore en public preview, ou juste passée de base macOS 26 à 27. Deuxième : la table des appareils simulateur change. Le runtime iOS 27 n’a pas forcément votre nom en dur ; name=iPhone 18 finit en Unable to find a device matching the provided destination. Troisième : si les cache keys DerivedData, SwiftPM, CocoaPods restent liés aux chemins « avant le grand saut Xcode », un hit restaure les déchets d’hier dans le compilateur d’aujourd’hui.
Nous séparons l’acceptation : « ça compile » vs « ça tient la semaine de lancement ». L’un : un job PR vert. L’autre : concurrence, disque, certificats et cold start simulateur ne se marchent pas dessus au pic. Côté hébergé, lire d’abord la doc des runners hébergés GitHub ; self-hosted, séparer par labels le feedback PR rapide et les jobs Archive lourds — même logique que GitHub Actions ralentit la CI iOS/Xcode : nouvelle approche, déclencheur Phone 18 cette fois.
Piège 1 : encore macos-latest — ou croire que xcode-27 = « n’importe quel Mac »
macos-latest reste correct à l’automne 2026 pour « ça tourne », mais inadapté comme seule surface d’acceptation la semaine Phone 18. Il suit la politique d’image par défaut GitHub — pas « SDK iOS 27 + votre simulateur déjà là ». Pour Xcode 27, écrire explicitement runs-on: xcode-27 (jobs lourds : xcode-27-xlarge), plutôt que compter sur maxim-lobanov/setup-xcode sur une mauvaise base — sans runtime, même le bon Xcode.app ne sauve pas simctl.
Plus sournois : le Changelog insiste sur arm64 uniquement. Si des nœuds Intel self-hosted restent, ou si runs-on: [self-hosted, macOS] signifie « tout Mac prend les jobs Xcode 27 », la matrix devient « parfois vert, parfois rouge » — vert = Apple Silicon, rouge = Intel incapable de la toolchain. Labels = l’ensemble réellement prêt, ex. [self-hosted, macOS, ARM64, xcode27], et retirer du label les nœuds non upgradés.
xcode-27, qui la ligne compat macos-26 : dans le runbook, et à croiser chaque semaine sur la page Runners Actions.
Piège 2 : destination figée sur iPhone 18 — l’image n’a pas encore ce « téléphone »
Le Phone 18 marketing et le nom d’appareil simulateur ne sont pas la même table. Dans actions/runner-images, le runtime iOS 27.0 liste aujourd’hui la série iPhone 17, iPhone Air, plusieurs iPad — sans garantie qu’un simulateur nommé iPhone 18 apparaisse le jour J. Un YAML en -destination 'platform=iOS Simulator,name=iPhone 18,OS=27.0' est l’auto-blessure la plus courante avant release.
Reproductible : en tête de job, xcrun simctl list devices available -j, parser le JSON, trier « runtime iOS 27 + nom commence par iPhone », prendre une machine, UDID dans $GITHUB_OUTPUT, puis xcodebuild test uniquement avec id=…. Matrix multi-appareils : intersection liste dispo ∩ whitelist ; manquant → skip + alerte, pas toute la ligne Release au rouge. UI tests : le premier cold start du nouvel OS peut manger plusieurs minutes — timeout encore calé sur les 20 min de l’ère Xcode 26, et l’intermittent devient systématique.
| Écriture | Risque semaine de lancement | Alternative plus stable |
|---|---|---|
name=iPhone 18,OS=27.0 | Nom absent → échec | Choix dynamique par UDID |
OS=27.0 en dur | Image peut être 27.0.1 | Préfixe runtime ou dernière dispo |
Seulement macos-latest | SDK/simulateur incertains | Surface d’acceptation xcode-27 explicite |
| Intel + Apple Silicon mélangés | Même job, échecs d’arch sporadiques | Pools séparés, ligne 27 ARM64 seulement |
Piège 3 : cache key pas invalidé avec Xcode 27 — le vert est l’« ancien monde »
Sur une major, la plus belle illusion de « c’est réparé » vient du cache. SourcePackages SwiftPM, Pods CocoaPods, tarballs DerivedData maison : si la key n’a que le branch ou le hash du lockfile, sans $(xcodebuild -version) / version d’image, Actions restaure joyeusement des artefacts Xcode 26. Symptômes : symboles linker manquants, Swift driver qui plante, tests qui buildent mais check de module cache qui échoue.
Nous forçons trois segments dans la key : version courte Xcode, version d’image runner (hébergé : env ou doc), plus Package.resolved / Podfile.lock. Le jour de l’upgrade, changer le préfixe — plutôt 8–12 min de cold start de plus que de debugger en semaine de lancement pourquoi le même commit passe en local et pas en CI. Self-hosted Apple Silicon : DerivedData partagé entre jobs sans dossiers par version Xcode mélange preview et GM.
Piège 4 : runners Apple Silicon là — disque et file vous ramènent au point de départ
Xcode 27 + runtime iOS 27 + plusieurs simulateurs : tueurs de disque. L’image hébergée xcode-27 est déjà lourde ; un Mac mini self-hosted qui garde Xcode 26, deux betas et le DerivedData de trois apps explose souvent tard dans l’Archive avec No space left on device. Avant la semaine de lancement : une seule Xcode « acceptation courante », runtimes en whitelist, DerivedData nettoyé par job, cron nocturne df -h et xcrun simctl delete unavailable.
La file ne disparaît pas avec le Silicon. Avant le keynote, la matrix passe de « un SDK » à « compat 26 + acceptation 27 » — concurrence hébergée et slots self-hosted saturés ensemble. Feedback PR rapide et Archive TestFlight doivent avoir des labels distincts : minutes pour l’un, file OK pour l’autre sans bloquer le premier. Qui prend le slot au pic, c’est le design des labels — pas le M-series sur l’affiche.
Comportement toolchain selon la doc Apple Xcode ; quels simulateurs dans l’image, selon le Readme runner-images de la semaine — pas une capture de blog de l’an dernier comme source de config.
Runbook semaine de lancement : comment on a basculé
Jour 1 : job d’acceptation PR prod explicite sur xcode-27, garder une sentinelle compat macos-26 (ou génération précédente) — 27 rouge bloque le merge, 26 rouge alerte seulement. Jour 2 : toutes les destinations de test en UDID dynamique, noms marketing hors YAML. Jour 3 : invalider le préfixe cache, forcer un build froid, noter le wall time comme baseline. Jour 4 : splitter le pool self-hosted : ci-pr et ci-release, aucun nœud Intel collé au label 27.
Astreinte quotidienne : Changelog / runner-images pour une nouvelle image, disque runners, ratio queued/run — le jaune plus long que le vert ? Chiffres qui se dégradent : d’abord couper le parallélisme matrix, ensuite ajouter des machines — plus de machines sans séparer les labels ne fait qu’accélérer les mauvais jobs.
xcode-27 hébergé queue déjà plus longtemps que la compile, ou qu’il faut figer une image GM pour notarisation et upload : louer au jour un Mac cloud Apple Silicon en self-hosted coûte souvent moins cher que de jouer à la loterie en file partagée. Nœuds dédiés pour Release et chaîne de certificats ; le volume PR peut rester sur les images preview hébergées comme première porte.
FAQ
Faut-il migrer tout de suite tous les jobs vers xcode-27 ?
Non. Acceptation lancement et builds store sur 27 ; compat ancien OS et hotfixes peuvent rester un temps sur l’image précédente. L’essentiel : labels et branch protection clairs — pas de « un vert n’importe où = merge ».
Xcode 27 vert en local, CI encore rouge — pourquoi ?
Trois checks d’abord : le runner est-il bien arm64 xcode-27, le nom de simulateur existe-t-il, le cache a-t-il hit un vieux DerivedData ? Runtime complet en local, pas forcément dans l’image hébergée.
Self-hosted et hébergé GitHub dans le même workflow ?
Oui, mais jobs et labels distincts. Pas un même tableau runs-on qui matche hébergé et n’importe quel self-hosted — sinon le scheduling n’est pas reproductible.
Le test appareil Phone 18 peut-il remplacer la CI simulateur ?
Non. Appareil : caméra, cellulaire, ressenti perf ; CI : compile, unit tests, régression à chaque PR. Semaine de lancement : les deux — l’appareil pas comme seul gate de merge.
Fenêtre Phone 18 · Astreinte Xcode 27
Besoin d’un Apple Silicon hors loterie de file partagée ?
Figer Release et notarisation sur un Mac cloud dédié ; les PR restent sur xcode-27 hébergé. Valider image et chaîne de certificats au jour — plus serein que de chasser la concurrence le jour du keynote.