How to Configure Xcode Cloud

Xcode Cloud klingt für uns Entwickler wirklich grossartig. Zumindest klingt es für mich toll, denn ich bin ein Fan von integrierten Lösungen, an denen ich nicht selbst herumbasteln muss. Denn diese bedeuten meist auch zusätzlichen Administrationsaufwand.

Die Vorgeschichte

Bei allem Sonnenschein solcher integrierten Lösungen steckt auch hier der Teufel - wie immer - im Detail. Denn unter bestimmten Umständen kann die Konfiguration etwas knifflig, zumindest aber auf den ersten Blick nicht ganz klar sein. Für ein reibungsloses Funktionieren von Xcode Cloud ist das Xcode Projekt selbst, also dessen Einrichtung, nicht ganz unwichtig.

Der Ist-Zustand

Das Projekt, an dem wir in der Firma arbeiten, ist ein Multiplattform-Projekt. Sprich, es gibt eine Code-Basis für iOS (iPhone & iPad) sowie macOS bei zwei Targets (iOS und macOS). Meine Kollegen haben es ca. im Herbst 2021 komplett neu begonnen und wir verwenden dafür (bisher) ausschließlich SwiftUI. Ich bin im März 2022 neu zum Projekt hinzugekommen, und es war mir von Anfang an wichtig, dass wir ein funktionierendes System für CI/CD verwenden. Nach anfänglichen Versuchen und esten Erfolgen mit GitHub Actions haben wir uns dann aber entschieden, die Zeit bis zur WWDC zu warten, und auf Xcode Cloud zu setzen.

In der Woche der WWDC wurde Xcode Cloud für Alle freigeschalten, und ich habe mich gleich ans Einrichten gemacht.

Unsere Projektstruktur

Unser Projekt ist ein .xcodeproj File. Wir haben im Prinzip den kompletten Code in eigene Swift-Packages ausgelagert, welche auf GitHub in privaten Repositories liegen. In Xcode integriert wurden diese über die "Add Local..." Funktion.

Unser Projekt hat dabei ungefähr folgende Struktur:

Cusstomer/
	Package1/
	Package2/
	Package3/
	OurApplication/
		App/
			OurApplication.xcodeproj
		Docs/
		...

Sowohl Package1, Package2, Package3 als auch OurApplication liegen dabei in eigenen, privaten Repositories auf GitHub.

Lokales Swift Package hinzufügen

Über diesen Weg legt Xcode im Projekt-Navigator automatisch eine neue Gruppe "Packages" an. Lokal hinzugefügte Swift-Packages erscheinen dann in dieser Gruppe.

Das hat bisher bei uns super funktioniert, denn alle Entwickler haben, bezogen auf die Projekte, die gleiche Filesystem-Struktur. Doch wird ein solches Projekt zu Xcode Cloud geladen, dann wird das ganz sicher fehlschlagen. Und so war es auch bei mir. Woher soll Xcode Cloud auch wissen, wie es an den benötigten Quellcode der privaten Swift Packages kommen soll?

Was ich nicht wusste war, dass ich in Xcode für ein und dasselbe Package auch mehrere Quellen angeben kann. Einmal lokal und einmal über eine URL, zum Beispiel von GitHub. Verarbeitet werden dabei sowohl https://... als auch git@github.com:... URLs. Das lokal eingebundene Package funktioniert dabei wie eine "Schatten-Referenz". Es überdeckt die Version, welche via URL eingebunden wurde. Auf diese Art und Weise kann ich lokal sowohl mit als auch am Package entwickeln, und nach einem Push ins Repository erkennt Xcode Cloud die URL-Referenz, und nimmt dann diese zum Compilieren. Wie praktisch, wenn man es weiß. 🤓

Auf diese versteckte Funktion von Xcode brachte mich Anders Bertelrud, ein Apple Engineer, nachdem ich im WWDC22 Slack eine Frage zu diesem Problem gestellt hatte. Er verwies mich in seiner Antwort auf die passende Developer Dokumentation.

Doch aus irgendeinem Grund funktionierte es bei mir trotzdem nicht. Ich musste irgendetwas übersehen haben. Also habe ich mir die oben erwähnte Dokumentation noch einmal ganz genau durchgelesen.

Und... Bingo! Absatz 3 beschreibt es eigentlich ganz genau.

Select the Swift package’s folder in Finder and drag it into the Project navigator.
Apple Documentation

"Drag into the Project navigator"! - Das war nicht das, was ich getan hatte. Ich hatte, wie oben beschrieben, die Xcode Funktion "Add Local..." verwendet. Aber warum - und hier stelle ich die Frage direkt an Apple - WARUM verhalten sich diese beiden Arten ein Package einzubinden so verschieden? Wozu gibt es überhaupt den einen und den anderen Weg? Das steht in keiner Doku, nirgends. 🙄

Also nochmal drei Schritte zurück, kurz nachdenken und die Packages neu einbinden. Das waren meine nächsten Aktionen:

  1. Alle Referenzen zu den drei Packages aus dem Projekt entfernen. Lokal und via URL.

  2. Alle drei Packages via Xcode (Screenshot oben) über ihre GitHub URL einbinden. Weil es private Repositories sind, müssen die git@github.com:... URL, und nicht die https://... URL verwendet werden.

  3. Dann alle drei Packages, wie in der Doku beschrieben, vom Finder via Drag & Drop in den Projekt-Navigator ziehen. Wir erinnern uns, ich hatte oben erwähnt, dass unser Projekt ein .xcodeproj File ist. Beim Drag & Drop stellt Xcode nun die Frage, ob alles in einem neuen Workspace gespeichert werden soll. Okay, das wollen wir tun.

Jetzt nochmal alles auf GitHub gepushed und Xcode Cloud beobachtet. Tattaa... Alles Grün! 🎉😃

Fazit

Ich bin gespannt, wie sich Xcode Cloud im täglichen Einsatz bewähren wird. Wir dürfen nicht vergessen, dass es sich noch immer im Beta-Stadium befindet. Also können wir die eine oder andere Ungereimtheiten und Bugs erwarten.

Für diese Ersteinrichtung möchte ich mich noch einmal ganz herzlich bei Anders Bertelrud bedanken. Diese WWDC Q&A Sessions sind wirklich eine lohnende Sache. Und ich bin froh, dass Apple sich hier geöffnet hat, und diese nun auch via Slack anbietet. 👍🏼


© Woodbytes