Ich habe mich die letzte Zeit viel mit Grunt herumgeschlagen. Grunt ist ein umfangreiches und mächtiges Build-Werkzeug für Node, dennoch hatte ich stets das Gefühl, dass die Konfiguration umständlicher als der wirkliche Nutzen ist. Ich habe daher mit einem Build-Script auf Bash-Basis begonnen, welches vom Nutzer spezifizierte Aufgaben nacheinander ausführt. Diese frühe Version unterstützt Coffeescript-Kompilierung, Testausführung und Dateisystemüberwachung, welche die anderen Tasks bei jeder Änderung automatisch ausführt. Nach dem Speichern bekommt man so stets die direkte Rückmeldung, ob die Unittests erfolgreich waren.
Boilerplate: Task-Abarbeitung
Auszuführende Aufgaben werden aus den Argumenten in ein Array tasks
übernommen. Jede atomare Task Aufgabe hat eine Funktion (im Beispiel mytask()
), welche die entsprechenden Operationen ausführt.
Die Abarbeitung selbst ist in process_tasks()
definiert, was auch den Startpunkt des Scripts darstellt. Hier wird über das Aufgabenarray iteriert und anhand des Names die passende Funktion ausgeführt.
tasks=("${@:1}") mytask() { # ... } # ... process_tasks() { while [[ ${#tasks[@]} > 0 ]]; do local task=${tasks[0]} unset tasks[0] tasks=("${tasks[@]}") case "$task" in 'mytask') mytask ;; # ... esac done } process_tasks
Testausführung mit Desktop-Benachrichtigungen
Die Funktion notify
nimmt eine Nachricht und einen Typ (Erfolg oder Fehler) und stellt sie auf dem Desktop dar. Entsprechend des Typs wird ein Icon gewählt. Dieser Teil ist leider plattformabhängig. Für Linux habe ich notify-send
gewählt.
Vom Unittest-Script wird hier in der Funktion run_tests
erwartet, dass bei fehlgeschlagenen Tests auch ein Fehlercode, also ungleich 0, zurückgegeben wird. Ist dies nicht der Fall, muss hier die Ausgabe überwacht werden.
notify() { local message=$1 # the message to be sent local message_type=$2 # "error" || "success" || undefined if hash "notify-send" 2> /dev/null; then local icon="face-plain" if [[ "$message_type" == "error" ]]; then icon="error" elif [[ "$message_type" == "success" ]]; then icon="face-smile-big" fi notify-send -u low -t 500 -i "$icon" "$message" fi } run_tests() { $application_launcher $build_directory/test/precompiler.spec.js if [[ $? > 0 ]]; then notify "One or more tests failed!" "error" else notify "All tests passed." "success" fi }
Watch: Dateisystem überwachen
Anwendung
Die Watchtask führt alle ihr nachfolgenden Tasks immer wieder aus, wenn sich im überwachten Verzeichnis etwas ändert.
./build.sh t1 t2 watch t3 t4
Die Aufgaben t1 und t2 werden direkt ausgeführt, ab watch wird gewartet. Mit jeder Änderung werden t3 und t4 ausgeführt. Ein sinnvolles Beispiel wäre somit:
./build.sh test watch test
Die Task test beinhaltet auch den Build. Der Aufruf führt die Tests zu Beginn und nach jeder Änderung aus.
Umsetzung
Das Dateisystem wird von inotifywait auf Änderungen überwacht. Es blockiert die Abarbeitung, bis eine Änderung vorgenommen wird. Hiernach werden die restlichen Tasks aus der Liste ausgeführt. Damit das Script dann nicht terminiert, wird die Taskliste um eine weitere Watch-Task und sich selbst ergänzt. So entsteht eine Endlosschleife.
watch() { tasks=("${tasks[@]}" "watch" "${tasks[@]}") inotifywait -rqe close_write,moved_to,create ./lib ./test }
Code auf Github
Das Script kann als Vorlage für eigene Build-Scripts verwendet werden. Es steht unter der üblichen Für-alle-außer-Microsoft-und-Apple-Lizenz und ist auf Github zu finden: