Was ist eine Hook?
Hooks sind Skripte, die Git vor oder nach bestimmten Ereignissen wie commit, push oder receive ausführt. Beispielskripts finden sich im Repository unter .git/hooks/. Mit diesen Skripten kann jeder erdenklicher Task erledigt werden, z.B. könnten Tests ausgeführt oder E-Mail-Benachrichtigungen versendet werden.
Achtung: da die Hooks im lokalen .git/-Ordner liegen, der nie in ein Remote-Repository gepusht wird, können diese Skripte nicht ohne Umwege teamintern ausgetauscht und für alle Team-Mitglieder einheitlich gehalten werden. In Node.js-Anwendungen ist dieses Problem mittels einer Library gelöst, wie wir weiter unten sehen werden.
Weiterführende Links:
https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
Welche Anwendungsfälle gibt es in Node.js-Anwendungen?
Es gibt viele denkbare Möglichkeiten, Hooks in der Entwicklung von Node.js-Anwendungen einzusetzen. Hier kommt es letztlich auf die Besonderheiten des Projektes an. In unserer täglichen Arbeit nutzen wir eine Pre-Commit-Hook, also ein Skript, das vor einem Commit ausgeführt wird. Dieses Skript führt für Dateien, die committed werden sollen, zwei Schritte aus: 1) Tests, sofern für die Datei eine entsprechende Test-Datei vorhanden ist; und 2) Formatierung. Dadurch stellen wir sicher, dass teamübergreifend die gleichen Formatierungsstandards genutzt werden, und dass kein Code committed wird, für den vorhandene Tests fehlschlagen. In letzterem Fall wird der Commit automatisch abgebrochen.
Welche Tools kann ich einsetzen?
Für unseren dargestellten Zweck nutzen wir eine Kombination zweier Libraries: husky und lint-staged. Husky macht das Verwalten von Git-Hooks sehr komfortabel und hat nur einen kleinen Fußabdruck. Lint-staged enthält ein Skript, das Shell-Tasks gegen eine (möglicherweise mit Glob-Muster gefilterte) Liste von gestageden Dateien ausführt.
Husky legt bei der Installation im Repository einen Ordner .husky/ an, der ein Shell-Skript und eine Beispielhook enthält, und setzt in der .git/config-Datei den Pfad für Hooks (hooksPath) entsprechend:
Nun können Hooks mit dem Befehl add hinzugefügt werden, z.B. npx husky add pre-commit „npm test“. Diese werden als ausführbare Shell-Skripte im Ordner .husky/ angelegt.
Die erste Zeile der neu angelegten Hook verweist auf das Husky-Kernskript. Darunter können nun eigene Befehle hinzugefügt werden:
Für unseren oben beschriebenen Einsatzzweck fügen wir in der pre-commit-Hook einen Verweis auf lint-staged ein:
Nun können wir in unserer package.json die Befehle hinzufügen, die lint-staged ausführen soll:
Für die Tests setzen wir die Flag –findRelatedTests um sicher zu stellen, dass auch Testdateien ausgeführt werden, die selbst nicht gestaged sind.
Und das war es auch schon: wenn wir nun ein git commit ausführen, führt Git die entsprechende Datei in unserem .husky-Ordner aus. Diese wiederum ruft lint-staged auf und lint-staged wendet die gegebenen Befehle auf alle Dateien an, die gestaged sind und dem Glob-Muster entsprechen. Wenn ein vorhandener Test fehlschlägt wird unser Commit abgebrochen.
Da der .husky-Ordner nicht von Git ignoriert wird können wir ihn in unser Remote-Repository pushen und somit sicherstellen, dass unser gesamtes Team die gleichen Skripte ausführt.
Sonderfall Node.js-App im Unterordner
Standardmäßig muss husky install im gleichen Ordner ausgeführt werden, in dem sich auch der .git/-Ordner befindet. Unsere Hooks werden von Git in eben jenem Ordner ausgeführt. Wenn wir eine Ordnerstruktur haben, bei der unsere Node-App in einem Unterordner liegt, müssen wir einige wenige Anpassungen vornehmen.
Zunächst ändern wir unser npm prepare-Skript, um husky install im übergeordneten Ordner auszuführen, in dem sich der .git/-Ordner befindet:
Dann fügen wir in unserer pre-commit-Hook einen entsprechenden Zwischenschritt ein, um in unseren Node-App-Ordner zu wechseln:
Abschließend kontrollieren wir in unserer .git/config, ob die Variable hooksPath in unseren Node-App-Ordner verweist, und ändern diese ggf. ab:
Damit ist alles erledigt und unsere pre-commit-Hook sollte nun auch aus unserem untergeordneten App-Ordner funktionieren.
Fazit
Git-Hooks sind ein mächtiges Werkzeug, um Entwicklern repetitive Tasks abzunehmen und können dabei helfen, teaminterne Standards umzusetzen und robusteren Code zu pushen. Für Node.js-Anwendungen stehen komfortable Libraries zur Verfügung, um Hooks in die Toolchain zu integrieren.
Dieser quiTeq-Tipp kommt aus Berlin.