3 Git-Hooks für Continuous Integration

Erfahre, wie du mit Git-Hooks unter anderem saubere Builds auf Feature Branches durchsetzen kennst.

Sarah Goff-Dupont Sarah Goff-Dupont

Wenn du Git schon eine Weile nutzt, sind dir Git-Hooks wahrscheinlich ein Begriff. Vielleicht hast du sogar schon ein bisschen mit ihnen experimentiert. Im Kontext der Continuous Integration sind Git-Hooks super praktisch. Deshalb gehe ich in diesem Artikel auf drei Anwendungsfälle ein und zeige dir vorkonfigurierte Hooks, die du deinem Workflow hinzufügen kannst. Falls Git-Hooks für dich Neuland sind, keine Sorge: Wir fangen mit den Grundlagen an.

Grundlegendes zu Git-Hooks

Hooks sind der native Mechanismus, über den in Git vor und nach Vorgängen wie "Commit" und "Merge" benutzerdefinierte Skripte ausgelöst werden. Sie sind quasi das Plug-in-System von Git. Wenn du das .git-Verzeichnis eines Git-Repositorys öffnest, siehst du ein Verzeichnis namens "hooks", das eine Reihe von Hook-Beispielskripten enthält.

.git/hooks

Die Installation von Git-Hooks ist einfach und gut dokumentiert, daher werde ich hier nicht darauf eingehen.

Hooks können in zwei allgemeine Klassen unterteilt werden: client- und serverseitig. Clientseitige Hooks werden auf deiner lokalen Workstation ausgeführt, serverseitige Hooks hingegen auf deinem Git-Server.

Du kannst Hooks auch als "pre-" oder "post-" klassifizieren. Pre-receive-Hooks werden vor bestimmten Git-Vorgängen aufgerufen. Es besteht die Option, einen Vorgang bei Bedarf abzubrechen. Sie fungieren als "Türsteher", die dein Repository schützen, indem sie verhindern, dass du oder deine Teamkollegen fehlerhaften Code committen. Post-receive-Hooks werden nach Abschluss eines Vorgangs ausgeführt. Daher besteht nicht die Option zum Abbruch. Stattdessen werden mit Post-receive-Hooks Teile des Entwicklungs-Workflows automatisiert.

#Git-Hooks sind wie kleine Helferlein, die jeden deiner Befehle ausführen.

Git-Hooks automatisieren unter anderem Folgendes:

  • Verifizieren, dass du deiner Commit-Nachricht den verknüpften Jira-Vorgangsschlüssel hinzugefügt hast
  • Durchsetzen der Voraussetzungen für Zusammenführungen
  • Senden von Benachrichtigungen an den Chatraum deines Teams
  • Einrichten deines Arbeitsbereichs nach dem Wechsel zu einem anderen Branch

Durchsetzen sauberer Builds auf Feature Branches

Serverseitige Pre-Receive-Hooks sind im Bereich der Continuous Integration besonders nützlich, da sie die Übertragung von Code an den Main verhindern können, wenn der Code bestimmte Bedingungen nicht erfüllt – sie sind sozusagen die Leibwächter des Main-Branch.

In der Regel sind Entwickler gewissenhaft genug, keine Merge-Vorgänge mit dem Main durchzuführen, wenn bei Tests auf ihrem Branch Fehler aufgetreten sind. Manchmal vergessen wir aber, die Testergebnisse durchzugehen. Wenn mehrere Nutzer auf einen Branch zugreifen, kann es auch mal passieren, dass seit der letzten Prüfung des Branch-Builds weitere Änderungen vorgenommen wurden – so etwas kommt vor.

Du kannst einen serverseitigen Hook hinzufügen, der nach eingehenden Merges mit dem Main sucht. Wenn er fündig wird, prüft das Skript den neuesten Build auf dem Branch. Sollten Testfehler vorhanden sein, wird der Merge abgelehnt. Mein Kollege und Atlassian Developer Advocate Tim Petterson hat für diesen Fall ein Hook-Skript für Bamboo geschrieben und auf Bitbucket verfügbar gemacht. Du kannst es einfach herunterladen, anpassen und deinem Repository hinzufügen.

Absichern der Codeabdeckung

Ein Aspekt, mit dem viele Teams Probleme haben, ist die Aufrechterhaltung der Codeabdeckung. Oft muss die Codebasis rückwirkend mit Tests abgedeckt werden. Wenn neue Funktionen hinzukommen, fehlen aber häufig die entsprechenden Tests, sodass die mühevoll errungene Abdeckung zugrunde geht, was sehr frustrierend sein kann. Deshalb hat Tim einen serverseitigen Pre-Receive-Hook programmiert, der verhindert, dass der Main die Codeabdeckung verweigert.

Auch dieser Hook sucht nach eingehenden Merges mit dem Main. Dann ruft er den Continuous-Integration-Server ab, um die aktuelle Codeabdeckung auf dem Main und die Abdeckung auf dem Branch zu prüfen. Ist die Abdeckung auf dem Branch schlechter, wird der Merge abgelehnt.

Die meisten Continuous-Integration-Server stellen keine Codeabdeckungsdaten über ihre Remote-APIs bereit. Daher wird der Codeabdeckungsbericht durch das Skript abgerufen. Dazu muss der Build dafür konfiguriert sein, den Bericht auf dem Main- und auf dem Branch-Build als freigegebenes Artefakt zu veröffentlichen. Nach der Veröffentlichung kannst du den neuesten Abdeckungsbericht vom Main abrufen, indem du den Continuous-Integration-Server aufrufst. Den Bericht für die Branch-Abdeckung kannst du vom neuesten Build oder von Builds abrufen, die mit dem zusammengeführten Commit verknüpft sind.

Die Voraussetzung für all dies ist jedoch, dass überhaupt eine Codeabdeckung vorhanden ist. Zur Ausführung dieser Vorgänge sucht der Hook in deinen Build-Ergebnissen nach Abdeckungsdaten. Auch dieser Hook kann standardmäßig mit Bamboo sowie mit Clover (Atlassian-Tool zur Codeabdeckung für Java und Groovy) verwendet werden. Er kann aber auch für die Integration in andere Build-Server- oder Codeabdeckungstools angepasst werden.

Überprüfen des Status von Branch-Builds

Verhindere, dass fehlerhafte Branches ausgecheckt werden.

Hier ist eine Möglichkeit, mit clientseitigen Git-Hooks herumzuprobieren: ein Post-Checkout-Hook-Skript, das den Branch-Build-Status direkt in deinem Terminalfenster verfügbar macht – ebenfalls von Tim. Das Skript ruft die Head-Revisionsnummer des Branchs aus deiner lokalen Kopie ab und fragt dann beim Continuous-Integration-Server an, ob die Revision schon erstellt wurde und ob der Build erfolgreich war.

Angenommen, du möchtest ausgehend vom Main einen Branch erstellen. Dieser Hook zeigt dir, ob der Head-Commit auf dem Main erfolgreich war. Ist dies der Fall, kannst du von diesem Commit aus bedenkenlos einen Feature-Branch erstellen. Oder angenommen, der Build einer Überarbeitung ist laut dem Hook fehlgeschlagen, obwohl das Wallboard deines Teams einen "grünen" Build für den Branch anzeigt (oder umgekehrt). Dies bedeutet, deine lokale Kopie ist veraltet. Du musst nun entscheiden, ob du die Updates abrufst oder weiterhin mit deiner lokalen Kopie arbeitest.

Dieser Hook hat den Entwicklern bei Atlassian schon viele Probleme erspart. Wenn du dein Team nicht zur Einführung der oben erläuterten serverseitigen Hooks überreden kannst, installiere wenigstens diesen Hook auf deiner lokalen Workstation. Du wirst es nicht bereuen.

Alle hier genannten Git-Hooks für Continuous Integration funktionieren bei Bamboo, Clover und Bitbucket standardmäßig. Da Git-Hooks anbieterneutral sind, kannst du sie aber in jedem Fall so anpassen, dass sie zu deinem individuellen Tool-Stack passen. Automatisierung gewinnt!