Untersuchung zur Integration von Unity Cloud Builds in VSTS

Warum Unity Cloud Build?

Es gibt bereits verschiedene Tutorials, die zeigen, wie man Unity-Builds über Shell/Powershell-Skripte realisieren kann, welche Unity im Batch-Modus betreiben. Unity bietet bereits selbst eine Infrastruktur für solche Builds an in Form von Unity Cloud Builds. Es stellt sich die Frage, wie einfach es ist diese zu integrieren, sodass man Build- und Testresultate direkt in VSTS aufgelistet bekommt. Dabei werde ich versuchen, dass VSTS nur zur Auswertung getriggert wird und die eigentliche Rechenzeit auf dem Unity Cloud Server stattfindet. Damit will ich verhindern, einen Agent im VSTS mit derselben Laufzeit wie des eigentlichen Builds zu betreiben, da man somit auch direkt den Build auf dem Agent selbst ausführen kann.

Der Service ist selbst in der Personal-Lizenz kostenlos mit gewissen Einschränkungen enthalten, welche sich von einem Limit von 1 Build pro Stunde (Personal) bis zu 6 simultanen Builds (Pro) erstreckt.

Unity Cloud Build hat aber auch Nachteile gegenüber den Batch-Skripten. Es werden nicht alle Plattformen unterstützt, beispielsweise werden noch keine UWP-Builds angeboten.

Erstellung eines Unity Cloud Builds

Als erstes benötigt Unity Cloud Build eine Verbindung zu VSTS um sich den aktuellen Repository-Stand ziehen zu können. Die Authentifizierung geschieht über einen SSH-Key, den einer der VSTS-Benutzer im Repository halten muss. Die SSH-git-URL des Repositories verwenden wir als Server-URL und der generierte Key wird im Security-Menü des Benutzers als SSH public key hinzugefügt.

Nun gilt es den Build zu konfigurieren. Man wählt einen Namen, git-Branch, eventuelle Unterordner des Projekts und die gewünschte Unity Version. Die Auto-Build Option könnte man deaktivieren, wenn man den Build über eigenen Trigger in VSTS starten möchte. Es ist erstmal einfach mit dieser Option zu arbeiten, welche bei einem Code-Push in dem gewählten Branch einen Build startet. Mit der Erstellung des Builds startet dieser sich selbst, woraufhin wir ihn direkt wieder stoppen um noch weitere Einstellung vorzunehmen.

In der Konfiguration des erstellten Builds aktivieren wir Unit-Tests und falls gewünscht auch, dass diese den Build fehlschlagen lassen. Die „Unit Test Method Name“-Option ist nur für Unity-Versionen kleiner 5.3.X relevant, da mit 5.6 die Test Tools direkt in Unity integriert sind.

Wir starten unseren Build jetzt zum ersten Mal und nach einigen Minuten können wir uns das Resultat in der Historie anschauen. Es ist wichtig anzumerken, dass der Tests-Tab zum Zeitpunkt dieses Blog-Posts nicht funktioniert und einfach nur eine leere Seite darstellt. Die Tests werden aber ausgeführt und hierfür liegen auch die entsprechenden Resultate in den Artefakten des Builds.

VSTS Integration

VSTS und Unity Cloud Build stellen jeweils verschiedene Rest-APIs und Webhooks zur Verfügung, die es zu verbinden gilt. Verschaffen wir uns erstmal einen Überblick, was wir denn benötigen mit den verschiedenen Schritten des Builds.

Als erstes möchten wir einen Unity Cloud Build starten. Wie bereits beim Erstellen des Build beschrieben, kann dieser sich selbst über einen Code-Push im Branch starten. Alternativ können wir in VSTS einen Service Hook erstellen, der einen Webhook aufruft, welches der Service-Endpunkt zur Erstellung eines Builds ist.

Nach dem Durchlaufen des Builds möchten wir das Resultat auswerten. Unity Cloud Build bietet hier auch die Möglichkeit, einen Webhook zu setzen, der mit den Resultaten beliefert wird. Hier treffen wir auf das erste Problem. Es gibt keine Möglichkeit, diese Rohdaten direkt an VSTS zu senden um eine Auswertung auszulösen. Es bleibt uns also nichts anderes übrig, als einen eigenen Webhook zu erstellen, welcher die Daten abfängt und in einen VSTS Aufruf übersetzt. Um nicht einen eigenen Server aufsetzen zu müssen werde ich Zapier benutzen. Zum Abfangen erstelle ich hier einen neuen Webhook mit der „Catch Raw Hook“ Option und trage die resultierende URL bei den Notifications im Unity Cloud Build ein.

Zum Starten eines Builds in VSTS wird diese Schnittstelle angeboten. Die einzigen Daten die mich hier interessieren sind der Build-Status und die Test-Resultate. Mit dem Parameters-Attribut können wir eigene Daten setzen, die in dem Build dann als Umgebungsvariablen zur Verfügung stehen. In den Basics wird beschrieben, wie ein Access Token erstellt werden kann. In meinem Fall habe ich die Berechnung mit dem Token einmal ausgeführt und den resultierenden String im Skript hardcodiert, da btoa und andere Methoden auf Zapier nicht verfügbar sind.

Der letzte Schritt ist das Auswerten der gesendeten Daten im VSTS. Wir erstellen einen leeren Prozess und fügen ein Powershell-Task hinzu. In diesem Skript führen wir eine einfache Überprüfung von UnityBuildStatus durch und lassen den Build ggf. fehlschlagen. Im vorherigen Schritt hätten wir noch genauere Informationen zum Fehlschlag des Builds hinzufügen können um eine ordentliche Fehlermeldung zu liefern aber dies vernachlässigen wir erstmal.

Die zweite Funktion des Skripts ist das Herunterladen des Test-Artefakts, was ein weiteres Problem mit sich bringt. Unity liefert Test-Resultate im NUnit-XML Format, welches aber nicht vollständig ist. Das Wurzel-Element ist bei Unity „<test-suite>“ aber sollte „<test-run>“ sein. Im Rohzustand kann VSTS die Resultate nicht verarbeiten, also müssen wir die XML-Datei reparieren. Da dies eine sehr einfache Transformation des XML-Dokuments ist, reicht es aus wenn wir das entsprechende Element per Regex-Replace kopieren und in „<test-run …>“ umwandeln. Weiterhin hängen wir noch „</test-run>“ am Ende der Datei an. Die „tmp“ Datei wird im Skript benutzt, da das OutFile von Invoke-RestMethod in einem nicht kompatiblem Encoding gespeichert wird.

Wir brauchen noch einen zweiten Task um unsere eben erstellte „unit_tests.xml“-Datei dem Build hinzuzufügen.

Resultat

Wir feuern unseren Trigger ab indem wir etwas im Repository ändern und lösen unsere Kette aus Webhooks und Builds aus. Nachdem alles abgearbeitet wurde erhalten wir unser Ergebnis eines erfolgreichen Builds mit zusätzlich ausgewerteten Unit-Tests, die zuvor mit NUnit in Unity geschrieben wurden.

Fazit

Es ist uns gelungen die Infrastruktur der Unity Cloud Builds in VSTS zu integrieren und weiterhin die Laufzeit des Builds auszulagern. Der große Nachteil dabei ist, dass wir drei verschiedene Systeme pflegen müssen um die Builds am Laufen zu halten. Es muss außerdem noch mehr Aufwand betrieben werden um Build-Logs, Fehlermeldungen, Build-Artefakte und viele andere wichtige Informationen durch unsere Kette durch zu schleifen. Mit Unity-Batch Skripten bekommt man den größten Teil hier schon mitgeliefert und muss lediglich die Transformation der Unit-Test-Datei durchführen.

Ich empfehle also schlussendlich die Builds doch mit Skripten im VSTS durchzuführen, da der Aufwand einfach um ein vielfaches kleiner ist und man nur ein einziges System warten muss. Ein sehr guter Blog-Eintrag, der genau diesen Weg beschreibt gibt es hier zu finden.