Engineering-Guides

Gemeinsame Xcode-Schemes für Cloud-Mac-CI prüfen

Gemeinsame Xcode-Schemes für Cloud-Mac-CI prüfen

Nachdem ein Team sein Projekt auf einen Cloud-Mac ausgecheckt hat, liegt das am häufigsten unterschätzte Problem nicht in einem Compilerfehler. Vielmehr findet die Pipeline das erwartete Scheme gar nicht oder ein gleichnamiges Scheme führt in der entfernten Umgebung andere Ziele aus. Eine lokale Xcode-Installation liest benutzerspezifische Einstellungen aus dem Entwicklerverzeichnis, während ein sauberer CI-Arbeitsbereich nur die im Repository vorhandenen Dateien kennt. Damit der Build-Einstiegspunkt stabil bleibt, müssen Schemes ebenso wie Skripte und Lockdateien für Abhängigkeiten versioniert und geprüft werden.

Schemes als CI-Schnittstelle behandeln

Ein von der Pipeline aufrufbares Scheme definiert mindestens vier Dinge: die zu erstellenden Targets, die verwendete Build Configuration, die auszuführenden Test Bundles und die Konfiguration für Archive. Dass ein Name im Xcode-Menü erscheint, bedeutet noch nicht, dass diese Informationen eingecheckt wurden.

Prüfen Sie zunächst, ob eine freigegebene Datei vorhanden ist:

find . \( -path "*/xcshareddata/xcschemes/*.xcscheme" \
  -o -path "*/xcuserdata/*/xcschemes/*.xcscheme" \) -print

Ein Scheme unter xcuserdata gehört zur Benutzerkonfiguration und eignet sich nicht als CI-Einstiegspunkt. Aktivieren Sie in Xcode unter Manage Schemes die Option Shared und prüfen Sie anschließend, ob die Datei unter einem der folgenden Pfade liegt:

App.xcodeproj/xcshareddata/xcschemes/App.xcscheme
App.xcworkspace/xcshareddata/xcschemes/App.xcscheme

Stellen Sie danach mit git status und git check-ignore -v sicher, dass die Datei verfolgt wird und nicht versehentlich unter eine zu weit gefasste Ignorierregel für *.xcuser* oder xcshareddata fällt.

„Lokal sichtbar“ besagt lediglich, dass die Konfiguration im Verzeichnis des aktuellen Benutzers vorhanden ist. „In CI verwendbar“ muss durch die Befehlsausgabe in einem sauber ausgecheckten Verzeichnis belegt werden.

Workspace, Scheme und Konfiguration festlegen

Die Pipeline darf sich nicht darauf verlassen, dass Xcode automatisch das richtige Projekt auswählt. Bei CocoaPods, zusammengefassten Projekten oder lokalen Packages können .xcodeproj und .xcworkspace zu unterschiedlichen Ergebnissen führen. Tragen Sie die drei Werte für den Einstiegspunkt ausdrücklich als CI-Variablen ein:

WORKSPACE="App.xcworkspace"
SCHEME="App"
CONFIGURATION="Release"

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration "$CONFIGURATION" \
  -list

Die Ausgabe von -list muss das erwartete Scheme enthalten. Prüfen Sie sie anschließend maschinell als JSON, statt sich ausschließlich auf das manuelle Lesen der Protokolle zu verlassen:

xcodebuild -workspace "$WORKSPACE" -list -json > xcode-list.json
python3 - <<'PY'
import json
data = json.load(open("xcode-list.json"))
schemes = data.get("workspace", {}).get("schemes", [])
if "App" not in schemes:
    raise SystemExit("Required Xcode scheme is missing")
PY

Wenn das Repository getrennte Einstiegspunkte für Entwicklung, Staging und Produktion enthält, sollten deren Namen den jeweiligen Zweck erkennen lassen, etwa App-Dev, App-Staging und App-Release. Lassen Sie ein Skript nicht anhand der Listenreihenfolge das erste Scheme auswählen. Nach dem Hinzufügen einer Abhängigkeit kann sich diese Reihenfolge ändern.

Build, Test und Archive einzeln prüfen

Die erfolgreiche Freigabe löst nur das Problem der Sichtbarkeit. Sie belegt noch nicht, dass die Aktionen korrekt definiert sind. Die Prüfung sollte deshalb in drei Ebenen unterteilt werden.

Aufgelöste Build-Einstellungen prüfen

Exportieren Sie zunächst die endgültigen Einstellungen. Prüfen Sie insbesondere PRODUCT_BUNDLE_IDENTIFIER, CONFIGURATION, SDKROOT, SUPPORTED_PLATFORMS und das Ausgabeverzeichnis:

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration "$CONFIGURATION" \
  -showBuildSettings > build-settings.txt

grep -E "PRODUCT_BUNDLE_IDENTIFIER|CONFIGURATION =|SDKROOT|SUPPORTED_PLATFORMS" \
  build-settings.txt

Diese Ausgabe enthält das zusammengeführte Ergebnis aus Scheme, Projekteinstellungen und Befehlszeilenargumenten. Sie entspricht der tatsächlichen Ausführung daher besser als eine direkte Prüfung von project.pbxproj.

Test-Einstiegspunkt validieren

Erstellen Sie in der Testphase zunächst testbare Artefakte und führen Sie erst danach die Tests aus. So lässt sich unterscheiden, ob der Kompilierungs-Einstiegspunkt defekt ist oder die Testausführung fehlschlägt:

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  build-for-testing

Der Simulatorname muss aus der Ausgabe von xcrun simctl list devices available auf dem aktuellen System stammen. Ein Gerät, das nur auf dem persönlichen Rechner eines Entwicklers vorhanden ist, darf nicht fest eingetragen werden. Wenn das Team eine bestimmte Runtime festlegen muss, sollten zusätzlich die Xcode-Version und die Zielversion des Betriebssystems dokumentiert werden.

Archive-Aktion separat prüfen

Archive kann eine andere Konfiguration als Run oder Test verwenden. Prüfen Sie zunächst die Konfiguration von ArchiveAction in .xcscheme und führen Sie danach in einem kontrollierten Job eine echte Archivierung aus:

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration Release \
  -destination "generic/platform=iOS" \
  -archivePath "$PWD/artifacts/App.xcarchive" \
  archive

Ein erfolgreicher gewöhnlicher build ersetzt die Archive-Prüfung nicht. Probleme bei der Ressourcenverarbeitung, in Skriptphasen und in Archivierungseinstellungen treten häufig erst an dieser Stelle zutage.

Lokalen Zustand entfernen und erneut prüfen

Die zuverlässigste Prüfung besteht nicht darin, DerivedData zu löschen, sondern das Repository in ein neues Verzeichnis zu klonen. Dadurch werden nicht eingecheckte Schemes, lokale symbolische Links, nicht verfolgte Konfigurationen und implizite Abhängigkeiten gleichzeitig sichtbar:

ROOT="$(mktemp -d)"
git clone --no-local . "$ROOT/repo"
cd "$ROOT/repo"
git submodule update --init --recursive
xcodebuild -workspace App.xcworkspace -scheme App -list

Wenn das Projekt von einem Generierungsschritt abhängt, muss der entsprechende Befehl vor dem Build ausgeführt werden. Prüfen Sie außerdem, ob das generierte Ergebnis reproduzierbar ist. Eine Anweisung wie „Projekt zunächst einmal in Xcode öffnen“ gehört nicht in die Betriebsdokumentation. Ein solcher Schritt lässt sich nicht unbeaufsichtigt ausführen und kann fehlende Dateien verdecken.

Eine Prüfung in sauberer Umgebung sollte mindestens Folgendes abdecken:

Prüfpunkt Erfolgskriterium
Sichtbarkeit des Schemes xcodebuild -list -json gibt den angegebenen Namen zurück
Dateizugehörigkeit Das Scheme liegt unter xcshareddata und wird von Git verfolgt
Build-Konfiguration Das auf der Befehlszeile aufgelöste Ergebnis entspricht den Erwartungen der Pipeline
Test-Einstiegspunkt build-for-testing kann Testartefakte erzeugen
Archivierungs-Einstiegspunkt Für ein generisches iOS-Ziel lässt sich ein .xcarchive erzeugen
Nicht interaktive Ausführung Xcode muss weder geöffnet noch ein persönliches Verzeichnis gelesen werden

Abweichungen am Einstiegspunkt vor dem Merge blockieren

Schemes sind XML-Dateien. Merge-Konflikte werden deshalb häufig wie gewöhnliche Textkonflikte behandelt, wodurch zwar der Name erhalten bleiben kann, Testable oder BuildActionEntry jedoch verloren gehen. Ergänzen Sie Merge Requests um eine einfache Prüfung, die das Vorhandensein der freigegebenen Datei bestätigt, Commits von xcuserdata verhindert und xcodebuild -list -json ausführt.

Beachten Sie außerdem die Pre-actions und Post-actions des Schemes. Verweist ein Skript auf absolute Pfade, interaktive Shell-Konfigurationen oder Werkzeuge, die nur auf dem Rechner eines bestimmten Entwicklers installiert sind, schlägt die entfernte Ausführung weiterhin fehl. Skripte sollten Dateien über Build-Variablen wie SRCROOT auffinden und bei fehlenden Abhängigkeiten mit einer eindeutigen Fehlermeldung beendet werden.

Das abschließende Erfolgskriterium ist einfach: Wird das Repository in ein leeres Verzeichnis abgerufen und stehen nur die dokumentierte Xcode-Version und die angegebenen Befehle zur Verfügung, müssen sich die Schemes auflisten, die Einstellungen auflösen, Testartefakte erstellen und die Archivierung abschließen lassen. Erst dann führt der Cloud-Mac bei G-Mini den im Repository definierten Einstiegspunkt aus, anstatt den zufälligen Zustand eines Entwicklerrechners nachzubilden.

Häufig gestellte Fragen

Warum findet Cloud-Mac-CI ein lokal funktionierendes Xcode-Scheme nicht?

Das Scheme liegt wahrscheinlich unter xcuserdata und fehlt deshalb im sauberen CI-Klon. Es muss unter xcshareddata/xcschemes gespeichert und zusammen mit dem Projekt in Git eingecheckt werden.

Garantiert ein gemeinsam genutztes Scheme einen erfolgreichen Archive-Lauf?

Nein. Die Freigabe stellt nur die Sichtbarkeit her. Release-Konfiguration, Archive-Ziel und vorbereitende Aktionen müssen separat geprüft und durch einen echten Archive-Lauf bestätigt werden.

Exklusiver physischer Knoten

Cloud-Mac für die nächste Build-Warteschlange vorbereiten

Vergleichen Sie zwei M4-Konfigurationen an fünf Standorten und wählen Sie die passende Tages-, Wochen-, Monats- oder Quartalsmiete für Ihren Arbeitszyklus.

Cloud-Mac-Tarif auswählen