top of page

Konsistent hohe Code-Qualität durch das pre-commit Framework

Das pre-commit Framework


Unser Data Scientist Matthias Jansen gibt ihnen heute einen thematischen Einblick zur Sicherung der Code-Qualität beim Programmieren:


1. Einführung


Hohe Code-Qualität ist für jedes Software-Unternehmen essentiell. Um diese sicherzustellen gibt es eine Vielzahl von Tools, die sich um verschiedene Teilaspekte dieser Qualität kümmern: Linter, Formatter, Test-Tools, usw.

Doch das ständige manuelle Anstoßen dieser Werkzeuge kann leicht vergessen werden. Das führt noch im besten Fall zu unfokussierten Code Reviews, in denen es um Formatierung statt um Inhalt geht. Bugs, welche sich durch zu seltenes Ausführen der Tests einschleichen, sind da schon viel ärgerlicher und kosten Zeit und Geld.

Diese Probleme können verhindert werden, indem man dem altbekannten Software-Mantra "Automate it" folgt. git stellt dafür einen Mechanismus in Form von Hooks bereit, der vor jedem Commit beliebigen Code ausführt. Das Schreiben dieser Bash Skripte ist jedoch nicht jedermanns Sache (das Verwalten, Aktualisieren, usw. nicht zu Vergessen!) und hier kommt das pre-commit Framwork ins Spiel.

Das pre-commit Framework (https://pre-commit.com/) vereinfacht das Aufsetzen der Hooks, da die gewünschten Tools lediglich in einer .pre-commit.yml Datei aufgelistet werden müssen (diese Datei sollte dann sinnvollerweise im das Projekt-Repository für jedes Teammitglied zugänglich und verwaltbar gemacht werden). Die Installation und das Einbinden in git geschieht im Hintergrund. pre-commit ist Open-Source Software und wird aktiv weiterentwickelt. Ein weiterer wichtiger Aspekt von pre-commit ist die Sprachunabhängigkeit: obwohl in Python geschrieben können Werkzeuge aus beliebigen Sprachen für die verschiedenen Überprüfungen verwendet werden.

2. Installieren & Einrichten


Zur Installation wird lediglich Python und der zugehörige Paketmanager pip benötigt.


- Installation: pip install pre-commit


- Installation prüfen: pre-commit --version


Die Installation von pre-commit ist so für jedes Projekt verfügbar, welches das Python Executable nutzt, unter dem es installiert wurde.


Um pre-commit mit einer zuvor angelegten pre-commit-config.yml in einem konkreten Projekt zu nutzen, muss noch der Befehl pre-commit install im Hauptverzeichnis des Projekts ausgeführt werden.


3. Hooks


Die Hooks, die von uns eingesetzt werden, lassen sich generell in drei Kategorien einteilen. Die konkret genannten Hooks lassen sich in Python-Projekten nutzen.


Code auf Korrektheit prüfen:

Dies ist sicherlich der klassische Anwendungsfall für git pre-commit Hooks. Zum einen wird der Code mittels Lintern auf statische Korrektheit geprüft (flake8), für die Einhaltung einer einheitlichen Formatierung wird ein Code Formatter (black) durchlaufen. Zum anderen wird der Code auch inhaltlich auf Korrektheit geprüft indem bei jedem Commit die Unit-Tests erfolgreich bestanden werden müssen.

Das Linting gibt es mittlerweile auch für DevOps Tools wie Dockerfiles und Ansible Playbooks.


Dinge, die man schnell vergisst:

Sehr nützlich sind pre-commit Hooks für "Hygieneaufgaben". Da wir für das Beschreiben von Python APIs OpenAPI (früher: Swagger) verwenden, wird bei jeder Veränderung in der openapi.yml (bzw. swagger.yml) die API Dokumentation neu generiert. Für das Verwalten von Abhängigkeiten verwenden wir u.a. pip-tools. Werden neue Abhängigkeiten in der requirements.in eingetragen wird automatisch das Generieren der requirements.txt mit gepinnten Versionen angestoßen, sodass die installierten Abhängigkeiten reproduzierbar bleiben.


weitere Tools:


Diese Schritte in der pre-commit Pipeline gehen über das Prüfen der reinen Funktionalität des Codes hinaus und überprüfen beispielsweise die importierten Pakete auf bekannte Sicherheitslücken (mit SafetyDB) und testen den Code auf sicherheitsrelevante Schwachstellen (bandit). Außerdem wird ungenutzer Code mit dead aufgespürt.

Es gibt eine Vielzahl weiterer möglicher Überprüfungen, hier (https://pre-commit.com/hooks.html) sind einige aufgelistet.


4. Beispielkonfiguration


Eine Beispielkonfiguration ist unter https://github.com/clarifydata/pre-commit-examples verfügbar.


5. Funktionsweise


pre-commit geht bei der Prüfung effizient vor. So arbeiten die Hooks standardmäßig nur auf den Codeabschnitten die sich gerade in der Staging-Area befinden (also Teil des nä. Commits werden sollen). Die Code-Änderungen, die nicht comittet werden sollen, werden für die Zeit der Überprüfung gestasht und danach wiederhergestellt.

Anhand der Dateiendung wird außerdem erkannt, ob bestimmte Hooks Teil der Überprüfung sein sollen oder komplett ignoriert werden können. Sollen bspw. nur Änderungen an einem Dockerfile comittet werden, können die Python Code Checker übersprungen werden. So wird sichergestellt, dass das Durchlaufen der Hooks schnell geht und nicht als zeitraubend/lästig empfunden wird.


6. Nützliche Befehle


git commit <div. Parameter> --no-verify


Manchmal möchte man einen Commit, trotz eines oder mehrerer fehlgeschlagener Hooks, durchlassen. Dies kann beispielsweise aufgrund einer Linterwarnung, die man als vorübergehend vernachlässigbar einstuft, oder deren Behebung mehr Arbeit erfordert, passieren. In diesem Fall gibt es das --no-verify, bzw. kurz -n Flag, welches das Validieren der Patches für diesen Commit ausschaltet.


pre-commit run --all-files


Stößt man während der Entwicklung auf einen neuen Hook, der von nun an in dem Projekt genutzt werden soll, sollte man diesen zunächst einmal auf allen (relevanten) Dateien ausführen, da während der normalen Ausführung der Hooks nur gestagte Änderungen und Dateien geprüft werden (s.o.). Mit dem Befehl pre-commit run --all-files werden alle Hooks auf allen für sie geeigneten Dateien (konfigurierbar in der .pre-commit-config.yml ausgeführt, sodass anschließend die Codebasis auf einem einheitlichen Stand sein sollte.


7. Ausblick


Neben dem namensgebendem Use-Case pre-commit Hooks zu verwalten können auch andere Ereignisse das Durchlaufen von Hooks triggern (post-commit, pre-merge-commit, pre-push, …).

Es gäbe noch viel mehr zu sagen, beispielsweise gibt es sehr viele Parameter, um die Hooks zu steuern, mit eigenen Konfigurationsdateien zu versorgen, usw.

Comments


bottom of page