In diesem Beitrag geht es darum, mehrere und unterschiedliche Build Jobs miteinander zu verknüpfen. Je größer eine Build Infrastruktur wird, desto häufiger wird man mit solchen Anforderungen konfrontiert, möchte man nicht einen riesigen Monolithen bauen.
Bei ModuleStudio gibt es beispielsweise mehrere Komponenten, die jeweils komplett unabhängig gebaut und getestet werden. Dennoch muß es für Integrationstests und zum Bauen der fertigen Produkte möglich sein, dass eine neue Version einer Komponente die Jobs für weitere Komponenten startet und somit eine Ausführung deren Workflows nach sich zieht.
Workflows in GitHub Actions verketten
Um mehrere Workflows miteinander in Verbindung zu bringen, sind zwei Seiten zu betrachten:
- Die auslösende Seite muß einen Trigger auslösen und dies ggf. an Bedingungen knüpfen.
- Die reagierende Seite muß diesen Trigger implementieren.
Die auslösende Seite
Nun ist es so, dass GitHub Actions erst einmal keine Build Pipelines in direkter Weise unterstützt, wie man es z. B. von Jenkins kennt. Es gibt aber neben regulären Events, wie Zeitsteuerung, Pushes und Pull Requests, auch die Möglichkeit, dass ein Workflow durch ein extern ausgelöstes Ereignis gestartet wird. Das Stichwort hierfür heißt repository_dispatch. Dies ist ein geeigneter Kandidat für individuelle Trigger. Um diese mittels etwaiger Bedingungen einzuschränken, können - wie bei allen Job-Schritten - beliebige Expressions mit dem Keyword if
angegeben werden. Hier sind beliebige Bedingungen denk- und einsetzbar. Insbesondere interessant sind aber die sogenannten Check-Funktionen, welche das Ergebnis zuvor ausgeführter Job-Schritte auswerten.
Das repository_dispatch
-Event wird über einen POST-Request an die GitHub-API ausgelöst. Damit man das in den Workflows nicht händisch tun bzw. selbst bauen muß, gibt es glücklicherweise es auch eine Action namens repository-dispatch, die zum Auslösen der Trigger eingesetzt werden kann.
Als Beispiel soll hier der Generator von ModuleStudio dienen: wenn die eigentliche Modellierungssprache (DSL) verändert hat, soll der Generator neu gebaut werden. Hierzu wird im Workflow des DSL-Repositories folgender Aufruf verwendet:
|
|
Der gleiche Generator-Workflow wird auch durch das Pushen von Commits ausgelöst. Im folgenden Screenshot ist zu sehen, wie sich beide Varianten im Protokoll darstellen:
Während die Jobs mit dem Titel upstream-build durch einen Repository dispatch ausgelöst wurden, wurden die übrigen durch einen Commit gestartet.
Die reagierende Seite
Damit ein Workflow ausgeführt wird, muß er auf das genannte Event reagieren. Dies wird, wie bei anderen Events auch, durch das Schlüsselwort on
zu Beginn des Workflows angegeben. Hier das Beispiel vom Generator:
|
|
Dieser Workflow wird also bei Push-Events und bei Pull-Requests, aber auch bei zwei eigenen Triggern - durch verschiedene Event-Typen gekennzeichnet - gestartet. Der Typ upstream-build
wird für den oben beschriebenen Fall verwendet, dass eine Komponente A (upstream) eine weitere Komponente B (downstream) triggert. Der zweite Typ manual-build
ist für einen anderen Anwendungsfall gedacht, der weiter unten in diesem Artikel vorgestellt wird.
Variante für Batch-Modus
Wenn der Generator neu gebaut worden ist, sollen mehrere Jobs gestartet werden, die jeweils ein Modul neu generieren und einen Pull Request für etwaige Neuerungen oder Änderungen erzeugen. In so einem Fall wäre es müßig, die gezeigte Action mehrfach hintereinander auszuführen. Statt dessen habe ich mich für diesen Fall für eine kleine Skriptlösung entschieden:
|
|
In dem Shell-Skript wird nun eine Schleife über die gewünschten Repositories durchlaufen und jeweils der Workflow ausgelöst:
|
|
Wie das im Ergebnis aussieht, lässt sich zum Beispiel hier anschauen:
Build Dashboard im Eigenbau
Hat man nun mehrere Komponenten miteinander verbunden, stellt sich noch die Frage, wie man am besten den Überblick behält. Da GitHub Actions immer in einem bestimmten Repository angesiedelt sind, fehlt eine projektübergreifende Gesamtsicht, wie sie in Jenkins auf der Startseite üblich ist.
Der Ansatz
Die Zutaten für solch eine Ansicht sind im Prinzip vorhanden, wir müssen sie nur zusammenfügen.
- Es bietet sich an, die Datei
README.md
eines Haupt-Repositories zu zweckentfremden: in Markdown besteht die Möglichkeit, Dinge in einer Tabelle zu arrangieren. Dies bringt auch die Vorteile mit sich, dass es mit in die Versionierung wandert, nichts explizit programmiert werden muß und jederzeit leicht Änderungen vorgenommen werden können. - Jeder Workflow kann seinen Status mit einem Badge visualisieren (siehe Doku). Das ist dann einfach ein Bild, das typischerweise ohnehin in der Readme-Datei im jeweiligen Repo eingebunden und angezeigt wird. Wir verwenden es aber nun im Haupt-Repository.
- Das wichtigste Element neben dem Status ist ein Build-Knopf. Denn es kann immer vorkommen, dass der Build einer bestimmten Komponente neu gestartet werden muß. Und hier kommt der oben gezeigte, zweite Event-Typ
manual-build
für dasrepository_dispatch
-Event ins Spiel. Die Idee hier ist es, dass jeder Build-Knopf auf ein Skript verlinkt und die benötigten Parameter (im Prinzip nur das Repo, ggf. noch die Art des Workflows) via GET an dieses Skript übergibt.
Die Tabelle
Das Markdown ist relativ einfach aufgebaut:
|
|
Der Play-Knopf wird über das Emoji ▶️ (: arrow_forward :
) dargestellt. Wer ein anderes Symbol bevorzugt, wird sicherlich auf dieser Übersicht fündig.
Skript für einfaches Dispatching
Das Skript dispatchJob.php
ist ebenfalls keine Raketenwissenschaft. Hier die wichtigsten Auszüge:
|
|
Das eigene Dashboard
Das Ergebnis der (doch sehr überschaubaren) Bemühungen sieht so aus: