Angular professionell bauen, testen und ausliefern

Grundkurs Angular: Professionell bauen, testen und ausliefern mit GitLab CI und Docker
Keine Kommentare

Der Einsatz eines Continuous-Integration-(CI-)Servers ist im Backend-Bereich schon lange eine etablierte Best Practice. Mit der Zunahme von Komplexität und Umfang von modernen Web-Frontends nimmt der Bedarf an Techniken professioneller Entwicklung auch hier zu. Dazu gehört die Arbeit mit Test-driven Development, CI-Servern und automatisierten Abläufen.

Angular professionell

In diesem Artikel beschäftigen wir uns am Beispiel von Angular und GitLab CI damit, wie die Build-Automatisierung umgesetzt werden kann.

Wer noch keinen CI-Server einsetzt, sollte sich die Vorteile vor Augen führen:

  • Schnelles, automatisches Feedback für alle Codeänderungen
  • Reproduzierbare Build-Ergebnisse durch eine neutrale Umgebung
  • Alle Änderungen können automatisch für den Test durch Kunden oder Fachabteilung in einer Testumgebung bereitgestellt werden

GitLab entstand ursprünglich als reines Git Repository und wurde später um einen CI-Server erweitert. Der Vorteil bei dieser integrierten Lösung liegt auf der Hand: GitLab weiß, wann sich Änderungen am Code ergeben und kann dann direkt einen Build starten. Eine aufwendige Integration von Versionsverwaltung und Build-Server entfällt somit. GitLab CI folgt dem Trend, die Build-Konfiguration zusammen mit dem zu bauenden Artefakt zu versionieren. Das Vorgehen, wie in diesem Beitrag vorgestellt, lässt sich entsprechend einfach auch auf andere Build-Server übertragen, da die Mechanismen ähnlich sind. In der Umsetzung erwartet GitLab CI eine .gitlab-ci.yml-Datei, in der im YAML-Format die einzelnen Build-Schritte beschrieben sind. Das hat den Vorteil, dass bei jedem Branch eine andere Build-Konfiguration verwendet werden kann. Die recht schlichte Syntax verleitet nicht dazu, besonders komplexe und außerhalb des Build-Servers kaum nachstellbare Builds zu konzipieren. In der Regel sind die einzelnen Build-Schritte einfache Aufrufe von Shellskripten.

Zur Ausführung der Builds unterstützt GitLab CI Docker Images. Damit ist auch die Frage danach beantwortet, wie der Build-Server an benötigte Werkzeuge, wie npm oder Maven, und Ablaufumgebungen, beispielsweise Node.js oder eine Java-Umgebung, gelangt. GitLab CI kann neben dem zum Build verwendeten Docker-Container auch weitere Service-Container starten, um damit für Tests benötigte Umsysteme wie eine Datenbank oder Backend-Systeme bereitzustellen. Die eigentliche Ausführung übernehmen sogenannte Runner: Diese Build-Agenten können auf separaten Maschinen oder in der Cloud gestartet werden und kommunizieren mit dem GitLab-CI-Server über ein API. Damit lässt sich die Build-Infrastruktur gut skalieren und dem jeweiligen Bedarf an Ressourcen anpassen.

International PHP Conference

Testing React Applications

by Hans-Christian Otto (Suora GmbH)

Building a Robo-Army with Angular

by Sebastian Witalec (Progress)

JavaScript Days 2019

JavaScript Testing in der Praxis (Teil 1 + 2)

mit Dominik Ehrenberg (Crosscan) und Sebastian Springer (MaibornWolff)

Progressive Web App Bootcamp 1/2: Grundlagen

mit Peter Kröner (‚Webtechnologie-Erklärbär‘)

GitLab CI Pipeline

GitLab CI bezeichnet eine Build-Konfiguration als Pipeline. Das Konfigurationsformat ist YAML und gliedert sich in sogenannte Stages. Per Default werden die Stages build, test und deploy definiert. Eigene Stages sind jedoch ebenfalls möglich. Innerhalb einer Stage werden Jobs definiert. Alle Jobs einer Stage können parallel ausgeführt werden, um die Performance zu verbessern. Jeder Job kann eine script-Anweisung definieren, die innerhalb des Jobs ausgeführt wird, siehe zum Beispiel Listing 1. Sollen mehrere Anweisungen ausgeführt werden, so müssen diese als Array unterhalb von script definiert werden. Die einzelnen Schritte werden sukzessive sequentiell ausgeführt. Die Arraysyntax wird in den folgenden Listings auch an mehreren Stellen verwendet.

job1:
  script: "execute-script-for-job1"

job2:
  script: "execute-script-for-job2"

Wird ein Job keiner Stage zugeordnet, wird standardmäßig die test-Stage verwendet. Es ist auch möglich, Jobs nur auszuführen, wenn der Build für einen Branch oder Tag erfolgt. Damit lassen sich beispielsweise gezielt Release- oder Deploymentjobs definieren. Durch einen regulären Ausdruck lässt sich sogar konfigurieren, dass Jobs nur für Tags oder Branches ausgeführt werden, die einem gewissen Namensschema entsprechen. Vor dem eigentlichen Skript auszuführende Kommandos können pro Job oder global als before_script definiert werden. Das kann zum Beispiel ein Aufruf des Dependency Manager sein, um benötigte Libraries herunterzuladen. Wird zur Ausführung ein spezieller Runner benötigt, kann dieser über am Job deklarierte Tags selektiert werden.

Das wichtigste Ergebnis eines Jobs sind Artefakte. So deklarierte Dateien oder Verzeichnisse werden von GitLab CI in nachfolgenden Stages bereitgestellt oder können als Dateien für einen konkreten Build heruntergeladen werden. Nicht als Artefakt deklarierte Dateien und Ordner stehen in anderen Jobs nicht zur Verfügung. Ein weiteres wichtiges Element von Builds sind Variablen. Mit Variablen lassen sich Builds parametrisieren und beispielsweise Passwörter extern verwalten.

Angular Build mit einer GitLab CI Pipeline

Angular-Projekte können mit npm als Dependency Manager und Angular CLI als Build-Abstraktion über webpack gebaut werden. Dieses Setup wird auch den Rahmen unseres Beispiels bilden. Nachdem mit Angular CLI ein Angular-Projekt erstellt wurde, wird dies normalerweise mit ng build gebaut. In einer CI-Umgebung müssen noch Abhängigkeiten durch npm installiert werden, in neueren npm-Versionen wird statt npm install besser npm ci verwendet, damit eine exakt reproduzierbare Versionsauflösung stattfindet. Für den Build wird eine Node.js-Umgebung benötigt und das Angular-CLI-Werkzeug. Der einfachste Weg, diese Umgebung für einen Build-Server bereitzustellen, ist durch geeignete Docker-Container. Für Angular verwenden wir das trion/ng-cli Image, das Node.js, npm und das Angular-CLI bereitstellt. Für Tests existieren ebenfalls passende Images, dazu später mehr.

In GitLab CI kann für einen Job ein Docker-Container als Ablaufumgebung spezifiziert werden. Dazu werden lediglich der Parameter image und ein geeignetes Docker Image angegeben. Falls zur Auswahl eines Docker-fähigen Runners noch Tags benötigt werden, so müssen diese ebenfalls im Job angegeben werden. Ein Beispiel für einen Angular-Job ist in Listing 2 zu sehen. Neben dem eigentlichen Build wird das Verzeichnis dist als Artefakt deklariert, das bis zu einen Tag lang aufbewahrt werden soll. Das dist-Verzeichnis ist das Ergebnis eines Angular CLI Build und enthält die fertige Anwendung. In später folgenden Jobs wird dieses Ergebnis typischerweise für das Deployment verwendet.

Nutzt das Projekt das frei verfügbare gitlab.com, kann für den CI Build einer der sogenannten Shared Runners verwendet werden. Diese Runners werden von GitLab zur allgemeinen Verwendung zur Verfügung gestellt. Man sollte hierbei jedoch im Hinterkopf behalten, dass diese Runners von allen anderen Nutzern mitgenutzt werden, sodass man keine sensiblen Daten wie etwa private Keys nutzen sollte. Neben diesen Shared Runners können auch eigene Runners verwendet werden, dies auch unabhängig davon, ob man GitLab selbst betreibt oder die gehostete Version verwendet.

Jeder Runner kann mit Tags markiert werden, die angeben, welche Fähigkeiten ein bestimmter Runner hat. Mit den Tags kann dann auch gesteuert werden, auf welchem Runner ein Job ausgeführt werden soll. In Listing 2 werden nur solche Runners ausgewählt, die eine Docker-Umgebung besitzen.

build:
  stage: build
  image: trion/ng-cli
  before_script:
    - npm ci
  script: 
    - ng build --prod
  artifacts:
    expire_in: 1 day
    paths:
      - dist/
  tags:
    - docker

Tests mit Karma und Protractor

Bei Angular gibt es drei Ebenen von Tests: Unit-Tests für reinen TypeScript- und JavaScript-Code, Komponententests für Angular Components und sogenannte Ende-zu-Ende-(E2E-)Tests für die gesamte Anwendung. Unit-Tests und Komponententests nutzen Karma als JavaScript-Laufzeit. Karma liegt das Konzept zugrunde, auf jeden Fall eine echte JavaScript-Umgebung aus einem Browser zu verwenden. Nur so lassen sich das tatsächliche Verhalten prüfen und potentielle Fehler identifizieren. In einer CI-Umgebung steht meist keine grafische Oberfläche zur Verfügung, um darin einen Browser laufen zu lassen. Darum wurde früher oft PhantomJS verwendet, was jedoch nicht selten zu dem Effekt geführt hat, dass Fehler nicht gefunden wurden, die in einem echten Browser entstehen, oder Fehler gemeldet wurden, die lediglich auf PhantomJS zurückzuführen waren. Neuere Browser unterstützen einen sogenannten Headless-Modus, um auch ohne grafische Oberfläche gestartet zu werden. Damit lassen sich dann prinzipiell Tests in CI-Umgebungen ausführen. Eine andere Variante ist die Verwendung einer grafischen Oberfläche, die in einen Framebuffer rendert und sich so auch in beliebigen Umgebungen starten lässt. Beide Varianten haben Ihre Vor- und Nachteile, sodass keine pauschale Empfehlung für eine der Varianten gegeben werden kann. Soll mit möglichst geringem Konfigurationsaufwand sowohl im Angular-Projekt als auch auf dem Buildserver gearbeitet werden, bietet sich der Einsatz eines Docker-Containers an. Das trion/ng-cli-karma-Image bringt alles mit, um einen Chrome-Browser mit Framebuffer oder Headless zu betreiben und darin die Karma-Tests auszuführen. Ein Beispiel für einen entsprechenden Job ist in Listing 3 gezeigt.

variables:
  CLI_VERSION: 6.2.1

test:karma:
  stage: test
  image: trion/ng-cli-karma:${CLI_VERSION}
  allow_failure: false
  script:
  - ng test --progress false --watch false
  tags:
  - docker

Noch mehr Abhängigkeiten werden für die E2E-Tests benötigt: Protractor setzt auf dem WebDriver-Projekt auf, das wiederum aus dem Selenium-Projekt hervorgegangen ist. WebDriver benötigt eine Java-Laufzeitumgebung und natürlich einen Webbrowser, der die Kommandos aus WebDriver ausführt. Die zusätzliche Java-Abhängigkeit kann wiederum mit einem passenden Docker Image abgebildet werden, zum Beispiel trion/ng-cli-e2e. Werden in einem Projekt E2E-Tests eingesetzt, so kann das Docker Image an allen Stellen verwendet werden, da sowohl die Karma- als auch die Angular-CLI-Abhängigkeiten enthalten sind. Ein Beispiel für einen Testjob mit E2E-Tests findet sich im Listing 4.

test:e2e:
  stage: test
  image: trion/ng-cli-e2e:${CLI_VERSION}
  allow_failure: false
  script:
  - ng e2e
  tags:
  - docker

Anders als beispielsweise bei Java-Anwendungen können bei Angular viele Schritte parallelisiert werden. So setzen die Tests keinen separaten Artefakt-Build voraus. In GitLab CI werden alle Jobs einer Stage parallel ausgeführt, was eine test-Stage ermöglicht, die alle Testarten parallel bearbeitet und so schnelles Feedback geben kann. Entsprechend haben die Beispiele zur Testausführung alle die Stage test definiert.

Qualitätsmetrik: Code Coverage

Wie gut eine Software getestet wird, lässt sich durch Metriken beschreiben. Dadurch kann ausgedrückt werden, wie viel Prozent des Codes durch Tests geprüft wurde. Was auf den ersten Blick recht einfach klingt, ist in der Praxis relativ komplex: Durch Bedingungen und Schleifen kann es notwendig sein, eine Stelle mehrfach mit unterschiedlichen Anwendungszuständen prüfen zu müssen. Eine grundsätzlicher Indikator ist die einfachste Metrik, nämlich wie viele Zeilen des Codes überhaupt durch Tests erfasst werden. Sowohl Angular CLI als auch GitLab CI unterstützen eine solche Auswertung. Entwicklern hilft diese Transparenz, abzuschätzen, wie sich die Qualität einer Anwendung im Laufe der Zeit entwickelt. Gerade beim Thema Wartung ist eine hohe Testabdeckung unabdingbar, da sie das Sicherheitsnetz bildet, um Refactoring oder Erweiterungen mit hoher Zuverlässigkeit durchführen zu können. Um die Testabdeckung zu ermitteln und an GitLab CI zu kommunizieren, müssen folgende Schritte unternommen werden:

  1. In conf.js muss im Abschnitt reports die text-summary ergänzt werden. Im Ergebnis stellt sich das so dar: reports: [‚html‘, ‚lcovonly‘, ‚text-summary‘ ],
  2. Bei der Testausführung muss der Parameter –code-coverage gesetzt werden.
  3. GitLab CI muss die Testabdeckung durch einen regulären Ausdruck aus der Ausgabe ermitteln.

Der vollständige Build-Job ist in Listing 5 zu sehen. GitLab CI wertet die Testabdeckung aus und kann diese dann in der Job- und Pipeline-Ansicht anzeigen, wie in Abbildung 1 zu sehen. GitLab CI stellt zusätzlich URLs zur Verfügung, mit denen Badges abgerufen werden können, um den Build-Status und die Testabdeckung in anderen Webseiten oder Wiki-Dokumenten einzubetten. Die URL-Struktur sieht dabei wie folgt aus: https://example.gitlab.com/<namespace>/<project>/badges/<branch>/coverage.svg

Abb. 1: Code-Coverage-Auswertung aus Karma-Tests in GitLab CI

test:karma:
  stage: test
  image: trion/ng-cli-karma
  allow_failure: false
  script:
    - ng test --code-coverage --progress false --watch false
  coverage: '/Lines \W+: (\d+\.\d+)%.*/'
  artifacts:
    paths:
      - coverage/
  tags:
    - docker

In Abbildung 2 ist ein Badge für die Testabdeckung zu sehen. Die Farbe des Badges ändert sich über Orange zu Rot, falls die Testabdeckung unter gewisse Schwellenwerte sinkt. So ist schnell ein Eindruck über den Status zu gewinnen.

Abb. 2: Code-Coverage-Badge von GitLab CI zur Einbettung in Webseiten

Abb. 2: Code-Coverage-Badge von GitLab CI zur Einbettung in Webseiten

Statische Analyse mit dem Angular Linter

Neben Tests hat sich im TypeScript-Umfeld, wie auch bei Java-, .NET- oder in aktuellen PHP-Umgebungen, die statische Codeanalyse bewährt. Dabei untersucht ein Programm Quelltext anhand des strukturellen Aufbaus und eventuell vorhandener Typinformationen. Bei Angular ist es dank TypeScript somit bei richtiger Verwendung des Typsystems möglich, viele Fehler im Vorfeld zu vermeiden. Ein Klassiker ist beispielsweise der Zugriff auf ein falsch deklariertes oder auch falsch geschriebenes Property. Der TypeScript Linter kann durch Plug-ins erweitert werden, um etwa Angular-Spezifika wie Lifecycle Hooks besser untersuchen zu können, und ist dann vergleichbar mit FindBugs (bzw. SpotBugs) im Java-Umfeld. Code Smells wie Variablenverdeckung oder Verletzungen des Codestyles werden angezeigt und helfen damit, frühzeitig potentielle Wartungsprobleme zu erkennen und zu vermeiden. Der Linter kann parallel zu den Tests ausgeführt werden, ein Beispiel ist in Listing 6 zu sehen.

test:nglint:
  stage: test
  image: trion/ng-cli:${CLI_VERSION}
  script:
  - ng lint
  tags:
  - docker

Tiefenanalyse mit SonarQube

Neben Lintern sind spezielle Werkzeuge zur statischen Analyse gekoppelt mit einer Trendauswertung entstanden. Darüber lassen sich dann auch Qualitätsgrenzwerte festlegen, zum Beispiel: „Ein Commit darf die Testabdeckung nicht um mehr als 2 Prozent verschlechtern.“ Auch wenn die absolute Abdeckung weiterhin in einem akzeptablen Bereich ist, fallen durch Trendanalysen so frühzeitig Risiken auf und können angegangen werden. Ein solches Werkzeug ist SonarQube, das Open Source und als SaaS-Cloud-Lösung bereitsteht. Da das Setup den Rahmen dieses Beitrags sprengen würde, wird im Folgenden angenommen, dass entweder bereits eine Sonar-Instanz bereit steht oder die Cloud-Lösung zum Einsatz kommt. Die Anbindung der Cloud-Lösung wird in Listing 7 beispielhaft gezeigt.

lint:sonar:
  stage: test
  image: trion/ng-cli:${CLI_VERSION}
  script:
  - npm install -g sonarqube-scanner
  - >
    sonar-scanner
    -Dsonar.projectKey=demo
    -Dsonar.organization=everflux-github
    -Dsonar.host.url=https://sonarcloud.io
    -Dsonar.login=covfefe
    -Dsonar.typescript.lcov.reportPaths=coverage/lcov/lcov.info
    -Dsonar.sourceEncoding=UTF-8
    -Dsonar.sources=src/app
    -Dsonar.exclusions=**/node_modules/**,**/*.spec.ts
    -Dsonar.tests=src/app
    -Dsonar.test.inclusions=**/*.spec.ts

SonarQube nutzt die Ergebnisse aus anderen Werkzeugen, wie die Testabdeckung von Karma, und kann diese auswerten. Außerdem bietet SonarQube eigene Ansichten, um eine Übersicht über alle gesammelten Metriken zu bekommen (Abb. 3). In Abbildung 4 ist darüber hinaus zu sehen, wie SonarQube seine eigenen Ergebnisse präsentiert, in diesem Beispiel wird etwa eine redundante Arrayinitialisierung angemerkt.

Abb. 3: Übersicht über die von SonarQube gesammelten Metriken

Abb. 3: Übersicht über die von SonarQube gesammelten Metriken

 

Abb. 4: Beispiel für die Meldung eines Bugs bzw. Code Smell durch SonarQube

Abb. 4: Beispiel für die Meldung eines Bugs bzw. Code Smell durch SonarQube

Deployment von klassisch bis Cloud

Eine Webanwendung wird dem User typischerweise durch einen Webserver, beispielsweise nginx, zur Verfügung gestellt. Normalerweise werden mindestens zwei Umgebungen betrieben: Die produktive Liveumgebung und eine vorproduktive Umgebung, um manuelle Tests und Verifikationen durchzuführen.

Das Deployment der Anwendung in eine Umgebung kann ebenso wie der Build aus der CI-Umgebung heraus erfolgen. Der Vorteil bei einer entsprechenden Automatisierung liegt auf der Hand: weniger Fehler durch manuelle Tätigkeiten und Dokumentation der Abläufe. Das Deployment selbst kann auf unterschiedliche Arten gelöst werden: Zum einen können die Build-Artefakte direkt, z. B. per rsync, auf dem Zielserver platziert werden. Zum anderen kann die Anwendung als Docker-Container bereitgestellt werden. Der Container kann dann auf dem Zielserver einfach ausgeführt werden. Letztere Variante hat vor allem den Vorteil, dass sowohl das Rollout als auch ein möglicher Rollback auf einfache Weise durch eine standardisierte, handhabbare Einheit vorgenommen werden können. Dazu kommt, dass die Deployment-Umgebung nichts außer einer Container-Runtime wie Docker bereitstellen muss. In Listing 8 ist dargestellt, wie aus einem CI-Job heraus, der selbst in einem minimalen Alpine-Container läuft, rsync zunächst installiert wird und anschließend das Deployment per rsync vorgenommen wird.

deploy:
  image: alpine
  stage: deploy
  script:
    - apk add --no-cache rsync openssh
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
    - chmod 600 ~/.ssh/id_dsa
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
    - rsync -rav --delete dist/ user@server:/web/path/

Als Build-Ergebnis wird ein Docker Image gebaut (Listing 9) und anschließend in eine Registry transportiert. Bei einem passenden Basis-Image kann das zugehörige Dockerfile sehr minimalistisch ausfallen, wie in Listing 10 gezeigt. Das Ausbringen in die Zielumgebung aus der Registry kann dann mit beliebigen Verfahren erfolgen, je nachdem, welche Containerorchestrierung zum Einsatz kommt. Das kann ein einfaches docker-compose sein, das im simpelsten Fall per SSH aus dem Build-Job heraus getriggert wird, oder ein Hook an der Registry, der auf einen Push reagiert. Denkbar ist auch die Verwendung von Kubernetes mit Aktualisierung eines zugehörigen Deployment-Objekts. Da typischerweise der Docker Daemon nicht innerhalb von GitLab-CI-Jobs genutzt werden kann, selbst wenn der Job innerhalb von Docker umgesetzt ist, wird ein Docker Daemon als zusätzlicher Service bereitgestellt, um damit das Image zu bauen (Listing 11).

variables:
  IMAGE: kakulty/angular-sample

build-image:
  stage: build-image
  image: docker
  before_script: []
  script:
    - docker build -t $IMAGE .
    - docker push $IMAGE
  tags:
    - docker
FROM trion/nginx-angular
COPY dist/ /usr/share/nginx/html/
variables:
  DIST_DIR: dist/angular-quality
  IMAGE: registry.heroku.com/angular-quality/web

deploy:
  stage: deploy
  image: docker:stable
  services:
  - docker:dind
  variables:
  DOCKER_HOST: tcp://docker:2375/
   DOCKER_DRIVER: overlay
  before_script: ['cd angular-quality']
  script:
  - docker build -t $IMAGE .
  - docker login --username=_ --password=$HEROKU_API_KEY registry.heroku.com
  - docker push $IMAGE
  - IMAGE_ID=$(docker inspect ${IMAGE} --format={{.Id}})
  - apk add curl
  - >
    curl -Ssl -X PATCH https://api.heroku.com/apps/angular-quality/formation
    -d "{ \"updates\": [ {
      \"type\": \"web\",
      \"docker_image\": \"${IMAGE_ID}\" } ] }"
    -H "Content-Type: application/json"
    -H "Authorization: Bearer ${HEROKU_API_KEY}"
    -H "Accept: application/vnd.heroku+json; version=3.docker-releases"
  tags:
  - docker

Deployment auf Heroku mit Docker

Um die Beispiele einfach nachvollziehen zu können, wird für das Deployment über ein Docker Image noch Heroku vorgestellt. Dazu reicht ein kostenloser Heroku-Account, mit dem sich bereits ein einzelner Docker-Container betreiben lässt. Man erzeugt einfach eine neue App – der Name entspricht dem später zu deployenden Image. Der zum Deployment erforderliche API Key findet sich unter Account Settings. Als Besonderheit bei Heroku muss beachtet werden, dass der zu verwendende Port für den Webserver durch Heroku erst zur Laufzeit vorgegeben wird. Entsprechend wird die Umgebungsvariable Port verwendet, um die Konfiguration des nginx-Webservers beim Start anzupassen. Listing 12 zeigt das zugehörige Dockerfile. Die für nginx verwendete Konfiguration default.conf wird beim Start mit sed angepasst.

FROM trion/nginx-angular
COPY dist/angular-quality /usr/share/nginx/html/

CMD sed -i "s/listen 8080/listen ${PORT:-8080}/" /etc/nginx/conf.d/default.conf && exec nginx -g "daemon off;"

Damit das gebaute Image auch bei Heroku in der Produktionsumgebung deployt wird, ist dort ein zusätzlicher API-Aufruf notwendig. Das ist mit dem Vorgehen in Kubernetes vergleichbar, bei dem ebenfalls das Kubernetes API die Möglichkeit bereitstellt, ein Deployment zu aktualisieren. Damit der Buildserver auf das Heroku API zugreifen kann, wird ein API Key benötigt. Dieser sollte als Secret angelegt werden und nicht als Variable im Build-Skript, damit der Wert nicht in der normalen Versionsverwaltung landet. Der API-Aufruf kann mit curl erfolgen, das zu dem Zweck als Paket im Docker-Container installiert wird. Alternativ kann ein passendes Basis-Image verwendet werden.

Fazit

Eine vollständige Build Pipeline gemeinsam mit der Anwendung zu versionieren, ist ein etabliertes Best Practice und wird von vielen CI-Servern unterstützt. Wie am Beispiel GitLab CI zu sehen ist, sind Builds dank Containertechnologie leicht nachvollziehbar und reproduzierbar zu spezifizieren. Weiterhin kann die Build-Konfiguration auf diese Weise dynamisch erfolgen, also etwa pro Branch, und jede Änderung an der Buildkonfiguration kann von anderen am Projekt beteiligten Entwicklern überprüft werden, z. B. via Pull Request. Eine CI Pipeline führt durch automatische Tests und die Erhebung von Qualitätsmetriken zu mehr Transparenz im Entwicklungsprozess und einer gesteigerten Sensibilität für gute Codequalität.

Falls das im Artikel gezeigte CD (Continuous Deployment) nicht gewünscht ist, sondern ein Release etwa nur zu einem definierten Zeitpunkt als spezieller Release-Build erfolgen soll, so ist auch das mit einer CI Pipeline möglich, beispielsweise über Git-Tags. Das ist als Ausbau dieses Artikels leicht umzusetzen.

Mit der Anwendung versionierte CI Pipelines sind nicht nur mit GitLab CI abbildbar, sondern auch mit anderen Werkzeugen, wie zum Beispiel Jenkins mit einem Jenkinsfile. Auch hier bietet Docker die oben gezeigten Vorteile sowohl bei Build, Test als auch Deployment. Die hier dargestellten Konzepte und Zusammenhänge visualisiert die Infografik auf der folgenden Seite noch einmal.

Ein Demoprojekt für diesen Artikel findet sich auf GitLab unter https://gitlab.com/trion-development/frontend-quality.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu:
X
- Gib Deinen Standort ein -
- or -