3
.
5
.
2018

Inkrementelle Builds mit Bazel - Teil 1: Java

OMG oder NBD?

EINLEITUNG

Eigentlich wollte ich einen BlogPost über das Angular Package Format schreiben, habe wie immer recherchiert, auch mal manuell eine APF Build Chain gebaut, viele Videos angesehen, in denen schlaue Menschen schlaue Dinge sagen und wäre schon fast eingeschlafen, aber dann fiel beiläufig der Satz “We at google build with Bazel, and actually Angular itself is built with bazel and we will release Angular CLI build support powered by bazel soon …“. Daher wird sich Teil 2 der BlogPost Serie diesem Thema widmen.

Die Frage ist aber erstmal: Ist Bazel OMG (oh my gosh) oder NBD (no big deal)?. Da Bazel sprachunabhängig ist und wir uns dem Thema erstmal vorsichtig nähern wollem betrachten wir in Teil 1 einen Java Build mit Bazel.

OMG oder NBD?
‍OMG oder NBD?

 

WAS IST BAZEL?

Was ist überhaupt Bazel? Kurz gesagt ein Build Tool, das sprachunabhängig ist und prinzipell alles bauen kann, wenn man ihm zeigt wie. Kernfeatures sind superschnelle inkrementelle Builds, deterministische Ergebnisse und noch so manch Anderes. Dies kann sich der wahrhaft Interessierte selbst anlesen.

Da Google dieses Tool anscheinend intern für alles verwendet und es eben auch bald offiziell für Angular Builds auf uns zu kommt, sollte man sich die Basics mal anschauen. Denn der Wunsch nach einem einzigen Tool für Full-Stack Builds ist definitiv vorhanden.

 

AUSGANGSLAGE: MAVEN JAVA PROJEKT

Damit wir Bazel kennenlernen bauen wir ein “Fat-Jar” eines Java Projekts.

Wir brauchen ein bestehendes Java Projekt und nutzen daür ein sehr simples Maven Projekt eines Commandline Tools. Der Code liegt auf GitHub:

Ausgangslage ist die existierende pom.xml die ein paar Test-Dependencies und Commons-Cli als Runtime-Dependency enthält. Genutzt wird das Maven-Assembly-Plugin für den “Fat-Jar” Build (jar-with-dependencies). Wissen über Apache Maven und Assembly-Plugin wird im Folgenden vorausgesetzt.

github:4c6a10aff6649aefafcd5773068c9e4a
Maven Projekt mit Assembly Plugin
‍Maven Projekt mit Assembly Plugin

Wir können uns die Dependencies auch als häßlichen Graph darstellen lassen. Aber immerhin mit serifenloser Schrift.

shell:mvn dependency:tree -DoutputType=dot -DoutputFile=/tmp/deps.dot
shell:dot -Tpng -Nfontname=Roboto -Nfontsize=10 -Efontname=Roboto -Efontsize=10 < /tmp/deps.dot > ~/Desktop/deps.png
Maven Dependencies
‍Maven Dependencies

 

BAZEL IN ACTION: MAVEN PROJEKT MIGRIEREN

Wir folgen grob dem Bazel Java Tutorial weichen aber teilweise davon ab. Das Finale Projekt lässt sich hier einsehen:

Folgendes Schaubild zeigt eigentlich alles, was es zu wissen gibt. Wir brauchen die zwei Dateien WORKSPACE und BUILD.

Bazel Projekt Aufbau
‍Bazel Projekt Aufbau

Das sieht erstmal kompliziert aus, aber es ergibt Sinn wenn man es genauer betrachtet.

Meine Erfahrung beim Migrieren von Maven zu Bazel:

  • (1) Alle Konvertierungs-Tool Projekte sind irgendwie kaputt, daher lieber per Hand.
  • (2) Transitive Dependencies müssen manuell angegeben werden. Das führt zu mehr Sicherheit, einem “Locking” der Depenendencies und somit zu deterministischen Build Results.
  • (3) Ich hatte bisher eine JUnit TestRule für mit einem Custom SecurityManager, der System.exit() verhindert. Diesen braucht es nicht mehr, da Bazel bereits einen solchen per default mitbringt.
  • (4) Ich musste eine TestAll-Testklasse anlegen, welche alle weiteren Tests per @SuiteClasses({MainTest.class, XmlGrepperTest.class}) ausführt. Bazel scheint einen zentralen Einstiegspunkt für Tests zu benötigen.
  • (5) Testresourcen: Mein Programm liest XML Dateien ein und parsed diese. Dazu liegt in ‘/src/test/resources/’ eine Testdatei. Bei einem Maven-Test-Run lassen sich die Dateien einfach aus dem Dateisystem laden. Bei Bazel wird eine ‘test.jar’ erzeugt und ich musste die Testdateien während des Testlaufs in temporäre Dateien auf dem Dateisystem extrahieren. Aber das ist so oder eine saubere Sache :)
  • (6) Fat-jar Build funktioniert out-of-the-box mittels ‘_deploy’ Suffix.
  • (7) ‘.gitignore’ braucht ‘bazel-*’ Regel, damit die ganzen Bazel Verzeichnisse nicht eingecheckt werden.

Das ist alles ziemlich cool und tat nicht groß weh, aber richtig cool wird es erst bei inkrementellen Builds.

 

BAZEL IN ACTION: INKREMENTELLE BUILDS MIT TEST-WATCHER

Eigentlich führen wir ja tests mittels bazel test :tests aus, aber das lässt den Test einmal durchlaufen, beim nächstenmal schneller, wegen inkrementellen Builds, aber der Lazy-Developer will es noch bequemer.

Mittels bazel-watcher lassen sich Tests im Watchmodus ausführen. Sprich man kann Code schreiben und währenddessen werden die Tests automatisch ausgeführt.

Die Installation war etwas tricky, da man erstmal in irgendeinem GitHub Issue suchen muss wie es geht, hier die Kurzfassung der bazel-watcher Installation auf macOS.

(1) Klonen und bauen

shell:cd ~/ && git clone https://github.com/bazelbuild/bazel-watcher.git && cd bazel-watcher && bazel build //ibazel

(2) Zeile in die ‘.bash_profile’ hinzufügren (Pfad muss je nach Ausgabe angepaasst werden)

shell:echo 'export PATH="$PATH:$HOME/git/bazel-watcher/bazel-bin/ibazel/darwin_amd64_pure_stripped/"' >> ~/.bash_profile

Fertig. Nun lässt sich ibazel ausführen und startet den Watchmodus. Für unsere Tests heißt das:

shell:ibazel test :tests

Rufen wir das auf und ändern etwas code sieht das wie folgt aus:

Bazel Projekt Aufbau
‍Bazel Projekt Aufbau

Ich finde das ziemlich awesome!

 

FAZIT

Es erscheint alles solide, gut dokumentiert und jedes OpenSource Projekt hinter dem eine große Firma steht, hat es leichter einen “Hype” auch zu überleben und sich permament zu etablieren. Da Google dieses Tool nun schon mehrere Jahre intern im Einsatz hat, sind wohl auch alle Kinderkrankheiten ausgebügelt. Ich bin gespannt auf Bazel builds für Angular. Vor allem von der Geschwindigkeit bin ich sehr beeindruckt. Darüber hinaus für mich positiv sind die explizit zu definierenden transitiven Dependencies. Letztlich ist der IDE Support in vielen bekanntne IDEs bereits gegeben. Daher gibt es von mir ein klares OMG! Und wenn erst noch Bazel builds für Angular kommen, dann haben wir endlich das eine Tool für den FullStackBuild :)

Bernhard
Software Engineer - Java, JVM