Grunt – Sebastians Blog https://sgaul.de Neues aus den Softwareminen Thu, 13 Mar 2014 20:34:45 +0000 de-DE hourly 1 https://wordpress.org/?v=6.1.1 https://sgaul.de/wp-content/uploads/2019/02/cropped-sgaul-2-1-32x32.jpg Grunt – Sebastians Blog https://sgaul.de 32 32 Bash-Build-Script mit Desktop-Nachrichten und Dateiüberwachung https://sgaul.de/2013/04/07/bash-build-script-mit-desktop-nachrichten-und-dateiuberwachung/ Sun, 07 Apr 2013 12:43:30 +0000 https://sgaul.de/?p=2079 Bash-Build-Script mit Desktop-Nachrichten und Dateiüberwachung weiterlesen]]> 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.

Bash-Build-Script für Node
Bash-Build-Script für Node

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:

Node-Build-Script auf Github

]]>
Live-Unittest-Entwicklungsumgebung für Node https://sgaul.de/2013/03/24/live-unittest-entwicklungsumgebung-fur-node/ Sun, 24 Mar 2013 15:01:48 +0000 https://sgaul.de/?p=2031 Live-Unittest-Entwicklungsumgebung für Node weiterlesen]]> Und wieder mal mehr Zeit in die Arbeitsvorbereitung als in die eigentliche Arbeit gesteckt. Eigentlich wollte ich in einem bestehenden Node-Projekt auch mit Coffee-Script arbeiten können. Herausgekommen ist eine Entwicklungsumgebung, in der man jede auf Node basierende Sprache wie eben Coffee- oder auch Type-Script verwenden kann, eine die Änderungen in Echtzeit deployt, die Unittests ausführt und eventuelle Fehler via Desktop-Benachrichtigung anzeigt. Das Ganze funktioniert unabhängig vom verwendeten Editor bzw. verwendeter IDE. Wer in Sublime Text noch Strg+B drückt, macht es sich zu kompliziert…

Unittest-Ergebnisse bei jedem Speichern
Unittest-Ergebnisse bei jedem Speichern

Die Node-Applikation

Die einzurichtende Node-App ist nichts besonderes: Ein Express-Webserver aus Javascript und Coffescript. Getestet wird das Ganze mit Jasmine-Node, der Node-Variante des beliebten Testframeworks.

Der Javascript-Task-Runner Grunt

Grunt
Grunt

Die Grundlage für die Übersetzung und Echtzeitfunktionen bietet das Javascript-Build-Tool Grunt. Wie man ein Projekt damit anlegt ist auf der Seite Getting Started recht gut beschrieben (genau genommen finde ich die Beschreibung gar nicht so doll, habe aber keine Lust es besser zu machen).

Von Haus aus kann Grunt in etwa gar nichts, alles ist streng modular und muss manuell hinzugefügt werden. Ich brauche die folgenden Plugins:

grunt-contrib-copy

Mit Copy verschiebe ich reine Javascript-Dateien und andere Resourcen vom Source- ins Buildverzeichnis.

grunt-contrib-coffee

Mit der Coffee-Task schiebe ich Coffee-Dateien vom Source- ins Buildverzeichnis. Statt sie nur zu kopieren, werden sie dabei auch direkt in Javascript umgewandelt.

grunt-contrib-jasmine-node

Dieser Task dient dazu, nach dem Build auch Jasmine-Node-Unittests ausführen zu können (nicht mit grunt-contrib-jasmine für Frontend-Tests zu verwechseln). Tatsächlich nutze ich dieses Plugin nicht direkt, da ich eine Modifikation benötige (mehr dazu gleich).

grunt-contrib-watch

Dieses Modul überwacht ein angegebenes Verzeichnis auf Änderungen und startet jeweils eine spezifizierte Task. In meinem Fall ist das der Build (Copy und Coffee) sowie die Unittests.

Im Wesentlichen war es das auch schon: Die App wird bei jedem Speichern gebaut und automatisch getestet. Nur doof, dass man für die Ergebnisse ins Terminal gucken muss.

Testergebnisse als Desktop-Benachrichtigung

Hier konnte ich keinen wirklich eleganten Ansatz finden, der folgende Weg macht aber was wir wollen. Statt grant-contib-jasmine-node zu verwenden, kopieren wir uns die Task-Registrierung direkt in unser Gruntfile. Hier modifizieren wir die folgende Zeile:

var write = function(data) { process.stdout.write(data.toString()); }

Bevor die Write-Funktion die Nachricht in den Stdout schreibt, müssen wir analysieren, ob es sich um unsere Unittest-Ergebnisse handelt. Sieht die Nachricht etwa wie „x tests, y assertions, z failures“ aus, können wir Test- und Fehlerzahl direkt herausholen.

Nun, da wir unsere Ergebnisse extrahiert haben, müssen wir sie auf dem Desktop ausgeben. Ich nutze hierfür Notify-Send, welches Ubuntus Notify-Send-Benachrichtigungen bedient. Ggf. muss das Paket erst installiert werden. Für proprietäre Systeme gibt es andere Lösungen, die vergleichbar funktionieren.

]]>