From 13dd6bfa904232150ea098d0e5f3d9c12798c29b Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 24 Jun 2021 10:10:37 +0200 Subject: [PATCH 01/78] test --- _posts/2021-06-24-example.md | 165 +++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 _posts/2021-06-24-example.md diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md new file mode 100644 index 000000000..2c3a755f6 --- /dev/null +++ b/_posts/2021-06-24-example.md @@ -0,0 +1,165 @@ +--- +layout: [post, post-xml] +title: "Konvertierung einer REST-API zu einer SOAP-Schnittstelle mithilfe von Kong" +date: 2021-06-18 16:00 +modified_date: 2021-06-18 16:00 +author: DanielKraft +author: jo2 +categories: [Softwareentwicklung] +tags: [Kong, SOAP, REST, Lua] +--- + +Welche Möglichkeiten haben wir, wenn neben einer REST-API auch eine SOAP-Schnittstelle zur Verfügung stehen soll? +In diesem Artikel wird eine Methode vorgestellt, wie man diese Anforderung mit Hilfe von Kong umsetzen kann. + +# Motivation +Wie bereist beschrieben, kann es manchmal gewollt sein, dass eine Schnittstelle über REST und SOAP erreichbar ist. +Hier stellt sich nun die Frage wie man diese Anforderung realisiert. + +Eine intuitive Herangehensweise wäre es, für den Service die zwei Schnittstellen getrennt zu implementieren. +Diese Lösung hat allerdings den Nachteil, dass die Schnittstellen sich durch die getrennte Implementierung unterschiedlich verhalten könnten. +Außerdem müssen bei einer Änderung des Service beide Schnittstellen verändert werden, womit zusätzlicher Arbeitsaufwand verbunden wäre. + +Um diese Probleme zu vermeiden, könnten wir für den Service nur eine Schnittstelle implementieren, zum Beispiel eine REST-API, da diese heutzutage häufig verwendet wird. +Die SOAP-Schnittstelle hingegen könnten wir anschließend aus der REST-API generieren. + +# Vorstellung der Architektur +Für die Realisierung beider Schnittstellen wird ein [Kong API Gateway](https://konghq.com/kong/) mit dem Kong Plugin [soap2rest](https://github.com/adessoAG/kong-plugin-soap2rest) sowie ein REST-Service benötigt. + +![Architektur Skizze](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Architektur.png) + +Die Abbildung zeigt, wie die einzelnen Komponenten miteinander verknüpft sind. +Das Kong API Gateway verwaltet den Zugriff auf den REST-Service. +Für den Fall, dass wir eine Anfrage über die REST-Schnittstelle stellen, wird diese Anfrage an den Service weitergeleitet und bearbeitet. + +Für die Verarbeitung von SOAP-Anfragen wird das Kong Plugin soap2rest verwendet. +Das Plugin benötigt zur Konfiguration zwei Dateien. +Damit das Plugin die SOAP-Anfragen richtig verarbeiten kann, benötigt es die WSDL der SOAP-Schnittstelle. +Und um die Konvertierung von SOAP zu REST Anfragen korrekt durchzuführen, wird zusätzlich die OpenAPI-Spezifikation der REST-API benötigt. + +# Funktionsablauf des Plugins +![Funktionsablauf des Plugins](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Ablauf.png) + +Diese Abbildung zeigt den Fall, dass eine Anfrage über die SOAP-Schnittstelle gestellt wird. +Sobald Kong eine Anfrage über die Route der SOAP-Schnittstelle registriert, wird das Plugin soap2rest ausgeführt. +Das Plugin konvertiert die Anfrage in eine gültige REST-Anfrage und sendet diese an den REST-Service. +Nachdem der REST-Service geantwortet hat, wird die Antwort in eine gültige SOAP-Antwort übersetzt und zurückgegeben. + +Anhand des folgenden Beispiels lässt sich der Ablauf näher verdeutlichen. +Angenommen, folgende Anfrage wird an die SOAP-Schnittstelle gestellt. + +```xml + + + + + 1 + + + +``` + +Aus dieser Anfrage lassen sich verschiedene Informationen ableiten. +Zum einen wird mit dieser Anfrage die SOAP-Action `GetPetByPetid` ausgeführt. +Zusätzlich beinhaltet die Anfrage den Parameter `petId` mit dem Wert `1`. +Anhand dieser Informationen kann die Anfrage der passenden REST Anfrage zugeordnet werden. +In diesem Fall entspricht die Anfrage dem Pfad `/pet/1`. + +Nachdem das Plugin die generierte Anfrage an die REST-API gestellt hat, bekommt es folgende Antwort: + +```json +{ + "id": 1, + "name": "doggie", + "photoUrls": [], + "tags": [], + "status": "available" +} +``` + +Anschließend wird diese Antwort vom Plugin in gültiges XML umgewandelt und in eine SOAP-Antwort eingesetzt, welche anschließend zurückgegeben wird. + +```xml + + + + + + 1 + doggie + + + available + + + + +``` + +# Besonderheiten des Kong Plugins soap2rest +## Analyse der Schnittstellen-Spezifikationen +Die Analyse der WSDL und der OpenAPI ist ein wichtiger Bestandteil des Plugins. +Sie wird nur einmal vor der ersten Anfrage an die SOAP-Schnittstelle ausgeführt, um die Schnittstelle zu konfigurieren. +Dadurch verzögert sich die Antwort der ersten Anfrage im Durchschnitt um 200 Millisekunden. +Anschließend wird diese Konfiguration für die Verarbeitung aller folgenden Anfragen verwendet. + +Bei der Analyse der WSDL werden wichtige Merkmale der SOAP-Schnittstelle ausgelesen. +Dazu gehören zum Beispiel das Auslesen der verschiedenen Operationen und ihrer zugehörigen Rückgabetypen und Faults. +Es wird besonders die Struktur der Rückgabetypen betrachtet, damit das Plugin später gültige SOAP-Antworten generieren kann. + +Nachdem die WSDL analysiert wurde, wird die Konfiguration des Plugins mit der OpenAPI-Spezifikation der REST-API vervollständigt. +Dabei werden den SOAP-Operationen die passenden Pfade der REST-API automatisiert zugeordnet. +Außerdem werden jeder Operation die passenden Content-Types zugeordnet, damit die HTTP-Header bei der Weiterleitung der Anfragen an die REST-API korrekt gesetzt werden können. + +## Request und Response Konvertierung +Bei der Konvertierung von eingehenden SOAP-Anfragen, werden diese in den meisten Fällen direkt von XML in JSON überführt. +Manchmal müssen davor aber noch andere Verarbeitungsschritte durchgeführt werden. +Zum Beispiel werden sämtliche SOAP-Header in HTTP-Header überführt. +Außerdem werden Dateiuploads in Multipart Bodys überführt und den Dateien wird mit Hilfe einer Mime Type Analyse der richtige Content-Type zugeordnet. + +Auch bei der Konvertierung der REST-Antworten werden verschiedene Zwischenschritte benötigt. +Wenn die REST-API nicht den Statuscode 200 zurückgibt, wird die Antwort in ein gültiges SOAP-Fault umgewandelt. + +Bei der Umwandlung der Antwort in XML wird besonders darauf geachtet, dass die Reihenfolge der Attribute des Rückgabetyps mit der Reihenfolge in der WSDL übereinstimmen. +Dafür wird die automatisch generierte Konfiguration des Plugins verwendet. + +# Auswirkungen auf die Verfügbarkeit +Damit der Einsatz des Plugins sich lohnt, sollte die Verfügbarkeit der Schnittstelle nicht unter dem Einsatz des Plugins leiden. +Um die Auswirkungen des Plugins auf die Verfügbarkeit der Schnittstelle zu testen, wurde ein Performance- und ein Lasttest vorgenommen. + +## Durchführung eines Performancetests +Der Performancetest besteht aus vier verschiedenen Anfragen, welche jeweils 10-mal wiederholt wurden. +Zwei der vier Anfragen liefern nur einen HTTP Status Code von 200 und 300 zurück. +Die dritte Anfrage sendet mit einem HTTP POST ein kleines JSON Objekt an die Schnittstelle. +Und die vierte Anfrage versucht die Grenzen der Schnittstelle auszuloten, indem eine Datei an die Schnittstelle gesendet wird. + +Die nachfolgende Grafik zeigt links die Ergebnisse des Performancetests auf die REST-API und rechts die Ergebnisse der SOAP-Schnittstelle. + +![Vergleich der Anfragezeiten](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Performancetest.png) + +Im direkten Vergleich fällt auf, dass die Performance nur beim Senden von Dateien leidet. +Die Performance aller andern Anfragen verändert sich nur geringfügig. + +Der Anstieg der Antwortzeit ist darauf zurückzuführen, dass bei SOAP-Anfragen deutlich mehr Daten an die Schnittstelle gesendet werden müssen. + +## Durchführung eines Lasttests +Im Gegensatz zum Performancetest wurden die vier Anfragen 250-mal parallel ausgeführt. +Um ein aussagekräftiges Ergebnis zu erhalten wurde dieser 10-mal wiederholt. + +Die folgende Grafik zeigt die Ergebnisse des Lasttests. + +![Lasttest](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Lasttest.png) + +Auf den ersten Blick fällt auf, dass die SOAP-Schnittstelle bei vielen parallelen Anfragen längere Antwortzeiten aufweist, als die REST-API. +Vor allem das Senden von Dateien führt zu einem deutlichen Anstieg der Antwortzeit. +Der Kommunikationsaufwand in Verbindung mit den vielen gleichzeitigen Anfragen auf die Schnittstelle ist für die langsamere Antwortzeit verantwortlich. + +# Fazit +Zusammenfassend lässt sich sagen, dass die Nutzung dieses Kong Plugins den Vorteil hat, dass nicht beide Schnittstellen implementiert werden müssen. +Ein Nachteil ist die zusätzliche Wartezeit auf die Antwort der Schnittstelle, da sich hinter jeder SOAP-Anfrage eine Anfrage auf die REST-API verbirgt. +Diese Verzögerung kann allerdings vernachlässigt werden, da erst bei vielen parallelen Anfragen ein deutlich längere Wartezeit entsteht. +Im Großen und Ganzen überwiegen die Vorteile des Plugins die Nachteile. From 09031f14dae7f6f3894649f42d28d92f44a17b58 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 24 Jun 2021 10:36:36 +0200 Subject: [PATCH 02/78] fix --- _posts/2021-06-24-example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md index 2c3a755f6..d3b7d9329 100644 --- a/_posts/2021-06-24-example.md +++ b/_posts/2021-06-24-example.md @@ -1,7 +1,7 @@ --- layout: [post, post-xml] title: "Konvertierung einer REST-API zu einer SOAP-Schnittstelle mithilfe von Kong" -date: 2021-06-18 16:00 +date: 2021-06-24 16:00 modified_date: 2021-06-18 16:00 author: DanielKraft author: jo2 From 25625f8e0c5e52a3c3e61dea8d27495822f04259 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 24 Jun 2021 11:06:40 +0200 Subject: [PATCH 03/78] fix --- _posts/2021-06-24-example.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md index d3b7d9329..21e0e849f 100644 --- a/_posts/2021-06-24-example.md +++ b/_posts/2021-06-24-example.md @@ -1,8 +1,8 @@ --- layout: [post, post-xml] -title: "Konvertierung einer REST-API zu einer SOAP-Schnittstelle mithilfe von Kong" +title: "Testartikel" date: 2021-06-24 16:00 -modified_date: 2021-06-18 16:00 +modified_date: 2021-06-24 16:00 author: DanielKraft author: jo2 categories: [Softwareentwicklung] From 259cebe39dae784cffd68ce9b7c3880c299727bb Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 8 Jul 2021 11:19:17 +0200 Subject: [PATCH 04/78] Update 2021-06-24-example.md --- _posts/2021-06-24-example.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md index 21e0e849f..1b5832a18 100644 --- a/_posts/2021-06-24-example.md +++ b/_posts/2021-06-24-example.md @@ -3,8 +3,7 @@ layout: [post, post-xml] title: "Testartikel" date: 2021-06-24 16:00 modified_date: 2021-06-24 16:00 -author: DanielKraft -author: jo2 +author: [DanielKraft, jo2] categories: [Softwareentwicklung] tags: [Kong, SOAP, REST, Lua] --- From 168f009d6295c09b544c848e916d45ebd751facf Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 8 Jul 2021 11:23:22 +0200 Subject: [PATCH 05/78] Update 2021-06-24-example.md --- _posts/2021-06-24-example.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md index 1b5832a18..f44670050 100644 --- a/_posts/2021-06-24-example.md +++ b/_posts/2021-06-24-example.md @@ -4,6 +4,7 @@ title: "Testartikel" date: 2021-06-24 16:00 modified_date: 2021-06-24 16:00 author: [DanielKraft, jo2] +author_ids: [DanielKraft, jo2] categories: [Softwareentwicklung] tags: [Kong, SOAP, REST, Lua] --- From fc23bff42456fb28d0fcf695af83f44cdaa86512 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 8 Jul 2021 11:29:53 +0200 Subject: [PATCH 06/78] Update feed.xml --- feed.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/feed.xml b/feed.xml index a6628bd84..82bc20201 100644 --- a/feed.xml +++ b/feed.xml @@ -11,6 +11,16 @@ layout: null {{ site.time | date_to_rfc822 }} {{ site.time | date_to_rfc822 }} Jekyll v{{ jekyll.version }} + {% assign author = site.data.authors[post.author] %} + {% if author %} + + {{ author.name }} + + {% else %} + + {{ post.author }} + + {% endif %} {% for post in site.posts limit:10 %} {{ post.title | xml_escape }} From 0dcd4f75382f423bbf353b8571a3627bce474bdc Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 8 Jul 2021 11:31:06 +0200 Subject: [PATCH 07/78] Update feed.xml --- feed.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/feed.xml b/feed.xml index 82bc20201..a6628bd84 100644 --- a/feed.xml +++ b/feed.xml @@ -11,16 +11,6 @@ layout: null {{ site.time | date_to_rfc822 }} {{ site.time | date_to_rfc822 }} Jekyll v{{ jekyll.version }} - {% assign author = site.data.authors[post.author] %} - {% if author %} - - {{ author.name }} - - {% else %} - - {{ post.author }} - - {% endif %} {% for post in site.posts limit:10 %} {{ post.title | xml_escape }} From 558c8347fde87d0e57bb5c70244a9010d0c261f0 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 8 Jul 2021 11:32:34 +0200 Subject: [PATCH 08/78] Update feed.xml --- feed.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feed.xml b/feed.xml index a6628bd84..8fd0b8649 100644 --- a/feed.xml +++ b/feed.xml @@ -24,6 +24,9 @@ layout: null {% for cat in post.categories %} {{ cat | xml_escape }} {% endfor %} + {% for cat in post.author_ids %} + {{ author_id | xml_escape }} + {% endfor %} {% endfor %} From 1bf17b56ffb7db129e60ba9022972eb944ba132d Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 8 Jul 2021 11:52:38 +0200 Subject: [PATCH 09/78] Update _config.yml --- _config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_config.yml b/_config.yml index 388d120fb..f35963ffe 100644 --- a/_config.yml +++ b/_config.yml @@ -44,6 +44,9 @@ kramdown: encoding: "utf-8" markdown_ext: "markdown,mkdown,mkdn,mkd,md" +feed: + path: feed.xml + # Konfiguration für das Erstellen der Bilder mini_magick: fullScreen_1600: From e065e190a4cd4c5486546bf6ee567987dd0fdcf9 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 12:08:50 +0200 Subject: [PATCH 10/78] fix feed --- feed.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feed.xml b/feed.xml index 8fd0b8649..3f51458e5 100644 --- a/feed.xml +++ b/feed.xml @@ -24,7 +24,7 @@ layout: null {% for cat in post.categories %} {{ cat | xml_escape }} {% endfor %} - {% for cat in post.author_ids %} + {% for author_id in post.author_ids %} {{ author_id | xml_escape }} {% endfor %} From d1911be1bd9307dda011c7254d535e06f50ad4c4 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 12:11:06 +0200 Subject: [PATCH 11/78] update post --- _posts/2021-06-24-example.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md index f44670050..39da7c502 100644 --- a/_posts/2021-06-24-example.md +++ b/_posts/2021-06-24-example.md @@ -3,7 +3,9 @@ layout: [post, post-xml] title: "Testartikel" date: 2021-06-24 16:00 modified_date: 2021-06-24 16:00 -author: [DanielKraft, jo2] +author: + - jo2 + - DanielKraft author_ids: [DanielKraft, jo2] categories: [Softwareentwicklung] tags: [Kong, SOAP, REST, Lua] From 84761a9382b72177c88675d057993c7fc6ed0133 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 12:13:55 +0200 Subject: [PATCH 12/78] update post --- _posts/2021-06-24-example.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md index 39da7c502..901179e4e 100644 --- a/_posts/2021-06-24-example.md +++ b/_posts/2021-06-24-example.md @@ -3,9 +3,7 @@ layout: [post, post-xml] title: "Testartikel" date: 2021-06-24 16:00 modified_date: 2021-06-24 16:00 -author: - - jo2 - - DanielKraft +author: DanielKraft author_ids: [DanielKraft, jo2] categories: [Softwareentwicklung] tags: [Kong, SOAP, REST, Lua] From 96e33c592170f3385c3cb27f613a6cd7ef0f5855 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 12:18:06 +0200 Subject: [PATCH 13/78] update jekyll --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 53ca8e39e..d80a138dd 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,7 @@ ruby RUBY_VERSION # # This will help ensure the proper Jekyll version is running. # Happy Jekylling! -gem "jekyll", "~> 3.5.0" +gem "jekyll", "~> 4.2.0" gem "liquid", "~> 4.0.0" @@ -21,7 +21,7 @@ gem "liquid", "~> 4.0.0" # If you have any plugins, put them here! group :jekyll_plugins do - gem "jekyll-feed", "~> 0.6" + gem "jekyll-feed", "~> 0.15.1" gem "jekyll-paginate-v2" gem "jekyll-sitemap","~> 1.0" gem "jekyll-gist","~> 1.4" From fbd0fa4044a4dbb52ebb8436bf3ed980de9d91b8 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 12:43:43 +0200 Subject: [PATCH 14/78] undo --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index d80a138dd..53ca8e39e 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,7 @@ ruby RUBY_VERSION # # This will help ensure the proper Jekyll version is running. # Happy Jekylling! -gem "jekyll", "~> 4.2.0" +gem "jekyll", "~> 3.5.0" gem "liquid", "~> 4.0.0" @@ -21,7 +21,7 @@ gem "liquid", "~> 4.0.0" # If you have any plugins, put them here! group :jekyll_plugins do - gem "jekyll-feed", "~> 0.15.1" + gem "jekyll-feed", "~> 0.6" gem "jekyll-paginate-v2" gem "jekyll-sitemap","~> 1.0" gem "jekyll-gist","~> 1.4" From 1872d485245522ab2ec3e9afb533db2479dc8784 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 12:58:24 +0200 Subject: [PATCH 15/78] edit post-xml --- _layouts/post-xml.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_layouts/post-xml.xml b/_layouts/post-xml.xml index eba4d1efb..e908c8ae1 100644 --- a/_layouts/post-xml.xml +++ b/_layouts/post-xml.xml @@ -42,6 +42,9 @@ + {% for id in page.author_ids %} + + {%- endfor -%} From 83d914f06c1848cdf02765459998ede060204601 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 13:08:12 +0200 Subject: [PATCH 16/78] remove unused fields --- _layouts/post-xml.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/_layouts/post-xml.xml b/_layouts/post-xml.xml index e908c8ae1..c78460429 100644 --- a/_layouts/post-xml.xml +++ b/_layouts/post-xml.xml @@ -39,13 +39,9 @@ {%- endif -%} --> - - - {% for id in page.author_ids %} - + {%- endfor -%} - From 7cb33a786266ee76a00b2c32b083bf1c610c84c8 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 13:14:50 +0200 Subject: [PATCH 17/78] remove comment --- _layouts/post-xml.xml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/_layouts/post-xml.xml b/_layouts/post-xml.xml index c78460429..19c4aea8f 100644 --- a/_layouts/post-xml.xml +++ b/_layouts/post-xml.xml @@ -27,17 +27,6 @@ {{page.date | date: "%s%L"}} {%- endif -%} ]]> - - {% for id in page.author_ids %} From 9b3b8b60a59bad37b6063334a7e50316f15c1087 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 8 Jul 2021 13:30:52 +0200 Subject: [PATCH 18/78] update html --- _includes/author-information.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/_includes/author-information.html b/_includes/author-information.html index ddaeb1b53..8dd3edd53 100644 --- a/_includes/author-information.html +++ b/_includes/author-information.html @@ -1,5 +1,6 @@ -{% assign author = site.data.authors[page.author] %}
+ {% for author_id in page.author_ids %} + {% assign author = site.data.authors[author_id] %}
@@ -11,6 +12,7 @@ {% endif %}
+ {% endfor %}
@@ -45,4 +47,4 @@
-
\ No newline at end of file + From 9e4b12147b2033d61da67ee0092d81c522ea7b46 Mon Sep 17 00:00:00 2001 From: jekyll2cms Date: Thu, 19 Aug 2021 10:16:23 -0500 Subject: [PATCH 19/78] =?UTF-8?q?ADD=20assets/first-spirit-xml/2021-06-24/?= =?UTF-8?q?2021-06-24-example.xml=20ADD=20assets/first-spirit-xml/2021-08-?= =?UTF-8?q?19/2021-08-19-functional-kotlin-eine-einf=C3=BChrung.xml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-01-25-tracing-mit-spring-cloud-sleuth.xml | 6 - ...kunftswebservice-einer-JEE-Applikation.xml | 6 - .../2018-03-26-owasp-dependency-check.xml | 6 - .../2018-06-04-brms-basisc-with-drools.xml | 6 - ...6-15-microservice-kommunikationsmuster.xml | 6 - .../2018-07-16/2018-07-16-Wicked-Charts.xml | 6 - .../2018-08-10-Azure-Functions-Security.xml | 6 - ...erwachung-mit-Spring-Boot-HealthChecks.xml | 6 - .../2018-09-06-adesso-testing-day-2018.xml | 6 - .../2018-09-28/2018-09-28-docxstamper.xml | 6 - .../2018-10-19-Die-Nacht-der-Tentakel.xml | 6 - .../2018-11-08/2018-11-08-kafka-streaming.xml | 6 - ...12-distributed-execution-mit-hazelcast.xml | 6 - ...blick-in-die-welt-der-graphdatenbanken.xml | 6 - ...-Dinge-fuer-nichttechnische-Leute-DBMS.xml | 6 - .../2019-01-08-Intro_zu_Kubernetes.xml | 6 - ...icklung-eines-modernen-GitHub-Crawlers.xml | 6 - ...Computing-Betrieb_wirklich_ohne_Server.xml | 6 - .../2019-02-18/2019-02-18-Micronaut.xml | 6 - .../2019-03-01-cep-and-ci-with-drools.xml | 6 - ...2019-05-31-Studieren-am-ITC-mit-adesso.xml | 6 - ...klung-mit-vuejs-f\303\274r-einsteiger.xml" | 6 - ...019-06-28-typisierte-angular-formulare.xml | 6 - ...bei-Single-Page-Application-Frameworks.xml | 6 - ...ebsockets-leichtgemacht-stompjs-spring.xml | 6 - ...19-08-12-Alte-Geschichte-neu-schreiben.xml | 6 - ...-your-spring-tests-with-junit-insights.xml | 6 - .../2019-08-28-Open-Source-Lizenzen.xml | 6 - .../2020-01-07-adesso-testing-day-2019.xml | 6 - ...es-arbeiten-mit-mehreren-arbeitskopien.xml | 6 - ...ying-Keras-models-to-production-easily.xml | 6 - ...03-02-serverless-architekturen-mit-aws.xml | 6 - ...-Dependency-Injection-mit-Google-Guice.xml | 6 - ...2020-03-23-Meine-App-ist-sicher-sicher.xml | 6 - ...kiste-Eine-Toolchain-f\303\274r-React.xml" | 6 - .../2020-04-01-mehraufwand-reduzieren.xml | 6 - ...asis-von-Tactical-Domain-Driven-Design.xml | 6 - ...-ein-it-projektteam-unterstuetzen-kann.xml | 6 - ...ration-nach-der-chicken-little-methode.xml | 6 - ...ust-f\303\274r-Java-Entwickler-Teil-1.xml" | 6 - ...ion-mittels-der-chicken-little-methode.xml | 6 - ...ust-f\303\274r-Java-Entwickler-Teil-2.xml" | 6 - ...05-22-Optimierung-von-Queries-in-neo4j.xml | 6 - ...t-und-automatierte-Tests-mit-Seed-Test.xml | 6 - ...de-und-strategien-fuer-cloud-migration.xml | 6 - .../2020-07-08-adesso-testing-day-2020.xml | 6 - ...ftsprozesse-in-einer-Microservice-Welt.xml | 6 - ...t-flexibler,-das-Ende-von-RESTful-APIs.xml | 6 - ...0-08-17-GitHub-Actions-im-Java-Projekt.xml | 6 - ...ame-Skizzen-in-UI-Prototypen-umwandeln.xml | 6 - ...orderungen_in_der_Domaenenmodellierung.xml | 6 - ...setzung-von-Architekturvorgaben-testen.xml | 6 - ...0-09-Mobile-Cross-Platform-Entwicklung.xml | 6 - ...ation-mit-der-rearchitecting-strategie.xml | 6 - ...-durch-RPA-und-Microsoft-PowerPlatform.xml | 6 - .../2020-10-30-Produktiver-mit-Firebase.xml | 6 - .../2020-11-13-Phishining_Kampagne_ZDF.xml | 6 - ...2-03-Testautomatisierung-in-der-Praxis.xml | 6 - ...keit-von-software-teil-1-dokumentation.xml | 6 - ...effentliche-Schluessel-mit-Apache-MINA.xml | 6 - ...2021-03-01-Passworthashing_Aber_Sicher.xml | 6 - ...u-should-use-WebAssembly-to-build-your.xml | 6 - ...-wartbarkeit-von-software-teil-2-tests.xml | 6 - .../2021-03-15-Intelligenz-vererben.xml | 6 - ...-bis-zur-DB-eines-Monolithen-mit-JUnit.xml | 6 - ...09-CleanCode_Schulung_Neu-Konzipierung.xml | 6 - ...-04-30-wartbarkeit-von-software-teil-3.xml | 6 - ...-Diverstaet-in-der-Softwareentwicklung.xml | 6 - ...orderungen_in_der_Domaenenmodellierung.xml | 6 - ...r-SOAP-Schnittstelle-mithilfe-von-Kong.xml | 6 - .../2021-06-24/2021-06-24-example.xml | 192 +++++++++ ...-am-Beispiel-von-Spring-Cloud-Contract.xml | 6 - ...-Posts-Exploring-Rust-For-AWS-Lambda-1.xml | 6 - ...ctional-kotlin-eine-einf\303\274hrung.xml" | 389 ++++++++++++++++++ 74 files changed, 581 insertions(+), 432 deletions(-) create mode 100644 assets/first-spirit-xml/2021-06-24/2021-06-24-example.xml create mode 100644 "assets/first-spirit-xml/2021-08-19/2021-08-19-functional-kotlin-eine-einf\303\274hrung.xml" diff --git a/assets/first-spirit-xml/2018-01-25/2018-01-25-tracing-mit-spring-cloud-sleuth.xml b/assets/first-spirit-xml/2018-01-25/2018-01-25-tracing-mit-spring-cloud-sleuth.xml index 77910c261..c98d817d2 100644 --- a/assets/first-spirit-xml/2018-01-25/2018-01-25-tracing-mit-spring-cloud-sleuth.xml +++ b/assets/first-spirit-xml/2018-01-25/2018-01-25-tracing-mit-spring-cloud-sleuth.xml @@ -23,13 +23,7 @@ umzusetzen.

- - - - - - diff --git a/assets/first-spirit-xml/2018-03-06/2018-03-06-NodeJS-als-Auskunftswebservice-einer-JEE-Applikation.xml b/assets/first-spirit-xml/2018-03-06/2018-03-06-NodeJS-als-Auskunftswebservice-einer-JEE-Applikation.xml index 953669c2c..aaff83316 100644 --- a/assets/first-spirit-xml/2018-03-06/2018-03-06-NodeJS-als-Auskunftswebservice-einer-JEE-Applikation.xml +++ b/assets/first-spirit-xml/2018-03-06/2018-03-06-NodeJS-als-Auskunftswebservice-einer-JEE-Applikation.xml @@ -17,13 +17,7 @@ Dieser Beitrag stellt dar, wie beide Technologien zusammenspielen können.

- - - - - - diff --git a/assets/first-spirit-xml/2018-03-26/2018-03-26-owasp-dependency-check.xml b/assets/first-spirit-xml/2018-03-26/2018-03-26-owasp-dependency-check.xml index 7c768a918..84d59ad55 100644 --- a/assets/first-spirit-xml/2018-03-26/2018-03-26-owasp-dependency-check.xml +++ b/assets/first-spirit-xml/2018-03-26/2018-03-26-owasp-dependency-check.xml @@ -23,13 +23,7 @@ automatisieren. In diesem Blog-Eintrag möchte ich gerne zeigen wie das funktion - - - - - - diff --git a/assets/first-spirit-xml/2018-06-04/2018-06-04-brms-basisc-with-drools.xml b/assets/first-spirit-xml/2018-06-04/2018-06-04-brms-basisc-with-drools.xml index 13590f231..c3cdd35f9 100644 --- a/assets/first-spirit-xml/2018-06-04/2018-06-04-brms-basisc-with-drools.xml +++ b/assets/first-spirit-xml/2018-06-04/2018-06-04-brms-basisc-with-drools.xml @@ -18,13 +18,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2018-06-15/2018-06-15-microservice-kommunikationsmuster.xml b/assets/first-spirit-xml/2018-06-15/2018-06-15-microservice-kommunikationsmuster.xml index 74f22e511..dbb854454 100644 --- a/assets/first-spirit-xml/2018-06-15/2018-06-15-microservice-kommunikationsmuster.xml +++ b/assets/first-spirit-xml/2018-06-15/2018-06-15-microservice-kommunikationsmuster.xml @@ -18,13 +18,7 @@ zwischen verteilten Services.

- - - - - - diff --git a/assets/first-spirit-xml/2018-07-16/2018-07-16-Wicked-Charts.xml b/assets/first-spirit-xml/2018-07-16/2018-07-16-Wicked-Charts.xml index 49ef37b02..3b8491174 100644 --- a/assets/first-spirit-xml/2018-07-16/2018-07-16-Wicked-Charts.xml +++ b/assets/first-spirit-xml/2018-07-16/2018-07-16-Wicked-Charts.xml @@ -18,13 +18,7 @@ In diesem Artikel wird dazu beispielhaft gezeigt, wie ein einfaches Liniendiagra - - - - - - diff --git a/assets/first-spirit-xml/2018-08-10/2018-08-10-Azure-Functions-Security.xml b/assets/first-spirit-xml/2018-08-10/2018-08-10-Azure-Functions-Security.xml index f91e778c0..e46caa2f8 100644 --- a/assets/first-spirit-xml/2018-08-10/2018-08-10-Azure-Functions-Security.xml +++ b/assets/first-spirit-xml/2018-08-10/2018-08-10-Azure-Functions-Security.xml @@ -18,13 +18,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2018-08-22/2018-08-22-Systemueberwachung-mit-Spring-Boot-HealthChecks.xml b/assets/first-spirit-xml/2018-08-22/2018-08-22-Systemueberwachung-mit-Spring-Boot-HealthChecks.xml index cf07e99e3..2b6b9b85e 100644 --- a/assets/first-spirit-xml/2018-08-22/2018-08-22-Systemueberwachung-mit-Spring-Boot-HealthChecks.xml +++ b/assets/first-spirit-xml/2018-08-22/2018-08-22-Systemueberwachung-mit-Spring-Boot-HealthChecks.xml @@ -21,13 +21,7 @@ anfangs noch nicht so stabilen Integrations- und Testsystemen gelingt, vermeidet - - - - - - diff --git a/assets/first-spirit-xml/2018-09-06/2018-09-06-adesso-testing-day-2018.xml b/assets/first-spirit-xml/2018-09-06/2018-09-06-adesso-testing-day-2018.xml index f9041cc2c..ccd7cc2ab 100644 --- a/assets/first-spirit-xml/2018-09-06/2018-09-06-adesso-testing-day-2018.xml +++ b/assets/first-spirit-xml/2018-09-06/2018-09-06-adesso-testing-day-2018.xml @@ -14,13 +14,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2018-09-28/2018-09-28-docxstamper.xml b/assets/first-spirit-xml/2018-09-28/2018-09-28-docxstamper.xml index fbaf59cac..0d97b1fa7 100644 --- a/assets/first-spirit-xml/2018-09-28/2018-09-28-docxstamper.xml +++ b/assets/first-spirit-xml/2018-09-28/2018-09-28-docxstamper.xml @@ -19,13 +19,7 @@ Templates erzeugt oder manuell nachbearbeitet werden. Dieser Artikel zeigt, wie - - - - - - diff --git a/assets/first-spirit-xml/2018-10-19/2018-10-19-Die-Nacht-der-Tentakel.xml b/assets/first-spirit-xml/2018-10-19/2018-10-19-Die-Nacht-der-Tentakel.xml index a07338d51..67598f6c8 100644 --- a/assets/first-spirit-xml/2018-10-19/2018-10-19-Die-Nacht-der-Tentakel.xml +++ b/assets/first-spirit-xml/2018-10-19/2018-10-19-Die-Nacht-der-Tentakel.xml @@ -19,13 +19,7 @@ In diesem humoristischen Artikel wird beschrieben, wie ich in einer langen Hotel - - - - - - diff --git a/assets/first-spirit-xml/2018-11-08/2018-11-08-kafka-streaming.xml b/assets/first-spirit-xml/2018-11-08/2018-11-08-kafka-streaming.xml index 76922da06..9f6508b3f 100644 --- a/assets/first-spirit-xml/2018-11-08/2018-11-08-kafka-streaming.xml +++ b/assets/first-spirit-xml/2018-11-08/2018-11-08-kafka-streaming.xml @@ -23,13 +23,7 @@ In diesem Blog wird der Einsatz von Kafka als Message-Queue und Streaming-Plattf - - - - - - diff --git a/assets/first-spirit-xml/2018-11-12/2018-11-12-distributed-execution-mit-hazelcast.xml b/assets/first-spirit-xml/2018-11-12/2018-11-12-distributed-execution-mit-hazelcast.xml index 3189e1f33..5d553627e 100644 --- a/assets/first-spirit-xml/2018-11-12/2018-11-12-distributed-execution-mit-hazelcast.xml +++ b/assets/first-spirit-xml/2018-11-12/2018-11-12-distributed-execution-mit-hazelcast.xml @@ -17,13 +17,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2018-11-21/2018-11-21-neo4j-ein-einblick-in-die-welt-der-graphdatenbanken.xml b/assets/first-spirit-xml/2018-11-21/2018-11-21-neo4j-ein-einblick-in-die-welt-der-graphdatenbanken.xml index cc3621c3c..dfffccabc 100644 --- a/assets/first-spirit-xml/2018-11-21/2018-11-21-neo4j-ein-einblick-in-die-welt-der-graphdatenbanken.xml +++ b/assets/first-spirit-xml/2018-11-21/2018-11-21-neo4j-ein-einblick-in-die-welt-der-graphdatenbanken.xml @@ -17,13 +17,7 @@ Letztere, wie Neo4j, bieten viele Vorteile gegenüber von relationalen Datenbank - - - - - - diff --git a/assets/first-spirit-xml/2018-12-05/2018-12-05-Technische-Dinge-fuer-nichttechnische-Leute-DBMS.xml b/assets/first-spirit-xml/2018-12-05/2018-12-05-Technische-Dinge-fuer-nichttechnische-Leute-DBMS.xml index 63fd66d57..9381699aa 100644 --- a/assets/first-spirit-xml/2018-12-05/2018-12-05-Technische-Dinge-fuer-nichttechnische-Leute-DBMS.xml +++ b/assets/first-spirit-xml/2018-12-05/2018-12-05-Technische-Dinge-fuer-nichttechnische-Leute-DBMS.xml @@ -15,13 +15,7 @@ Dazu kläre ich auf, wie Datenbankmanagementsysteme dazu verwendet werden könne - - - - - - diff --git a/assets/first-spirit-xml/2019-01-08/2019-01-08-Intro_zu_Kubernetes.xml b/assets/first-spirit-xml/2019-01-08/2019-01-08-Intro_zu_Kubernetes.xml index 52530cebe..0bf9324b2 100644 --- a/assets/first-spirit-xml/2019-01-08/2019-01-08-Intro_zu_Kubernetes.xml +++ b/assets/first-spirit-xml/2019-01-08/2019-01-08-Intro_zu_Kubernetes.xml @@ -17,13 +17,7 @@ Grund genug, sich einmal näher mit Kubernetes und den Konzepten dahinter zu bes - - - - - - diff --git a/assets/first-spirit-xml/2019-01-30/2019-01-30-GitIntel-Entwicklung-eines-modernen-GitHub-Crawlers.xml b/assets/first-spirit-xml/2019-01-30/2019-01-30-GitIntel-Entwicklung-eines-modernen-GitHub-Crawlers.xml index c9989bc2a..890106540 100644 --- a/assets/first-spirit-xml/2019-01-30/2019-01-30-GitIntel-Entwicklung-eines-modernen-GitHub-Crawlers.xml +++ b/assets/first-spirit-xml/2019-01-30/2019-01-30-GitIntel-Entwicklung-eines-modernen-GitHub-Crawlers.xml @@ -18,13 +18,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2019-02-13/2019-02-13-Serverless_Computing-Betrieb_wirklich_ohne_Server.xml b/assets/first-spirit-xml/2019-02-13/2019-02-13-Serverless_Computing-Betrieb_wirklich_ohne_Server.xml index 4c2680ac7..503e157d6 100644 --- a/assets/first-spirit-xml/2019-02-13/2019-02-13-Serverless_Computing-Betrieb_wirklich_ohne_Server.xml +++ b/assets/first-spirit-xml/2019-02-13/2019-02-13-Serverless_Computing-Betrieb_wirklich_ohne_Server.xml @@ -21,13 +21,7 @@ Dieser Artikel beschreibt die Idee hinter FaaS und zeigt, wie man Funktionen mit - - - - - - diff --git a/assets/first-spirit-xml/2019-02-18/2019-02-18-Micronaut.xml b/assets/first-spirit-xml/2019-02-18/2019-02-18-Micronaut.xml index 0cbfc9efe..27a1ba5c5 100644 --- a/assets/first-spirit-xml/2019-02-18/2019-02-18-Micronaut.xml +++ b/assets/first-spirit-xml/2019-02-18/2019-02-18-Micronaut.xml @@ -20,13 +20,7 @@ Danach vergleichen wir die beiden Ansätze und schauen, wo welches Framework üb - - - - - - diff --git a/assets/first-spirit-xml/2019-03-01/2019-03-01-cep-and-ci-with-drools.xml b/assets/first-spirit-xml/2019-03-01/2019-03-01-cep-and-ci-with-drools.xml index a234366bc..4987e72af 100644 --- a/assets/first-spirit-xml/2019-03-01/2019-03-01-cep-and-ci-with-drools.xml +++ b/assets/first-spirit-xml/2019-03-01/2019-03-01-cep-and-ci-with-drools.xml @@ -19,13 +19,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2019-05-31/2019-05-31-Studieren-am-ITC-mit-adesso.xml b/assets/first-spirit-xml/2019-05-31/2019-05-31-Studieren-am-ITC-mit-adesso.xml index 6a695fc26..27f198b42 100644 --- a/assets/first-spirit-xml/2019-05-31/2019-05-31-Studieren-am-ITC-mit-adesso.xml +++ b/assets/first-spirit-xml/2019-05-31/2019-05-31-Studieren-am-ITC-mit-adesso.xml @@ -16,13 +16,7 @@ In diesem Artikel stelle ich das Studium am IT-Center vor und teile meine Erfahr - - - - - - diff --git "a/assets/first-spirit-xml/2019-06-18/2019-06-18-frontend-entwicklung-mit-vuejs-f\303\274r-einsteiger.xml" "b/assets/first-spirit-xml/2019-06-18/2019-06-18-frontend-entwicklung-mit-vuejs-f\303\274r-einsteiger.xml" index 7e3c6e8b0..8c25cbc7d 100644 --- "a/assets/first-spirit-xml/2019-06-18/2019-06-18-frontend-entwicklung-mit-vuejs-f\303\274r-einsteiger.xml" +++ "b/assets/first-spirit-xml/2019-06-18/2019-06-18-frontend-entwicklung-mit-vuejs-f\303\274r-einsteiger.xml" @@ -16,13 +16,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2019-06-28/2019-06-28-typisierte-angular-formulare.xml b/assets/first-spirit-xml/2019-06-28/2019-06-28-typisierte-angular-formulare.xml index f0bbaab79..e5f35dbfb 100644 --- a/assets/first-spirit-xml/2019-06-28/2019-06-28-typisierte-angular-formulare.xml +++ b/assets/first-spirit-xml/2019-06-28/2019-06-28-typisierte-angular-formulare.xml @@ -16,13 +16,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2019-07-19/2019-07-19-Die-Qual-der-Wahl-bei-Single-Page-Application-Frameworks.xml b/assets/first-spirit-xml/2019-07-19/2019-07-19-Die-Qual-der-Wahl-bei-Single-Page-Application-Frameworks.xml index cf266c673..685de2745 100644 --- a/assets/first-spirit-xml/2019-07-19/2019-07-19-Die-Qual-der-Wahl-bei-Single-Page-Application-Frameworks.xml +++ b/assets/first-spirit-xml/2019-07-19/2019-07-19-Die-Qual-der-Wahl-bei-Single-Page-Application-Frameworks.xml @@ -20,13 +20,7 @@ So unterschiedlich die Ansätze der Frameworks untereinander sind, ist das gemei - - - - - - diff --git a/assets/first-spirit-xml/2019-08-08/2019-08-08-Websockets-leichtgemacht-stompjs-spring.xml b/assets/first-spirit-xml/2019-08-08/2019-08-08-Websockets-leichtgemacht-stompjs-spring.xml index 3c26a56f3..6a9de8e75 100644 --- a/assets/first-spirit-xml/2019-08-08/2019-08-08-Websockets-leichtgemacht-stompjs-spring.xml +++ b/assets/first-spirit-xml/2019-08-08/2019-08-08-Websockets-leichtgemacht-stompjs-spring.xml @@ -20,13 +20,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2019-08-12/2019-08-12-Alte-Geschichte-neu-schreiben.xml b/assets/first-spirit-xml/2019-08-12/2019-08-12-Alte-Geschichte-neu-schreiben.xml index 81ac36c83..657cdb5b0 100644 --- a/assets/first-spirit-xml/2019-08-12/2019-08-12-Alte-Geschichte-neu-schreiben.xml +++ b/assets/first-spirit-xml/2019-08-12/2019-08-12-Alte-Geschichte-neu-schreiben.xml @@ -19,13 +19,7 @@ Operationen vorgestellt mit denen du deine Historie aufräumen kannst.

- - - - - - diff --git a/assets/first-spirit-xml/2019-08-20/2019-08-20-identify-bottlenecks-in-your-spring-tests-with-junit-insights.xml b/assets/first-spirit-xml/2019-08-20/2019-08-20-identify-bottlenecks-in-your-spring-tests-with-junit-insights.xml index d6888e301..f125ba381 100644 --- a/assets/first-spirit-xml/2019-08-20/2019-08-20-identify-bottlenecks-in-your-spring-tests-with-junit-insights.xml +++ b/assets/first-spirit-xml/2019-08-20/2019-08-20-identify-bottlenecks-in-your-spring-tests-with-junit-insights.xml @@ -19,13 +19,7 @@ This is especially true when using continuous integration to automatically check - - - - - - diff --git a/assets/first-spirit-xml/2019-08-28/2019-08-28-Open-Source-Lizenzen.xml b/assets/first-spirit-xml/2019-08-28/2019-08-28-Open-Source-Lizenzen.xml index 3688f9ca3..068f8102c 100644 --- a/assets/first-spirit-xml/2019-08-28/2019-08-28-Open-Source-Lizenzen.xml +++ b/assets/first-spirit-xml/2019-08-28/2019-08-28-Open-Source-Lizenzen.xml @@ -17,13 +17,7 @@ Dieser Blogpost soll dabei helfen, die richtige Lizenz für das eigene Projekt z - - - - - - diff --git a/assets/first-spirit-xml/2020-01-07/2020-01-07-adesso-testing-day-2019.xml b/assets/first-spirit-xml/2020-01-07/2020-01-07-adesso-testing-day-2019.xml index bf163c9b0..30d12656b 100644 --- a/assets/first-spirit-xml/2020-01-07/2020-01-07-adesso-testing-day-2019.xml +++ b/assets/first-spirit-xml/2020-01-07/2020-01-07-adesso-testing-day-2019.xml @@ -15,13 +15,7 @@ Beim adesso testing day handelt es sich um eine adesso-interne Konferenz zum Aus - - - - - - diff --git a/assets/first-spirit-xml/2020-01-14/2020-01-14-git-worktree-effizientes-arbeiten-mit-mehreren-arbeitskopien.xml b/assets/first-spirit-xml/2020-01-14/2020-01-14-git-worktree-effizientes-arbeiten-mit-mehreren-arbeitskopien.xml index 8418c903c..7ee4f250a 100644 --- a/assets/first-spirit-xml/2020-01-14/2020-01-14-git-worktree-effizientes-arbeiten-mit-mehreren-arbeitskopien.xml +++ b/assets/first-spirit-xml/2020-01-14/2020-01-14-git-worktree-effizientes-arbeiten-mit-mehreren-arbeitskopien.xml @@ -17,13 +17,7 @@ In diesem Blog-Beitrag betrachten wir den nicht weit verbreiteten git-Befehl git - - - - - - diff --git a/assets/first-spirit-xml/2020-02-04/2020-02-04-Deploying-Keras-models-to-production-easily.xml b/assets/first-spirit-xml/2020-02-04/2020-02-04-Deploying-Keras-models-to-production-easily.xml index 5c7e3ac37..1c11f2910 100644 --- a/assets/first-spirit-xml/2020-02-04/2020-02-04-Deploying-Keras-models-to-production-easily.xml +++ b/assets/first-spirit-xml/2020-02-04/2020-02-04-Deploying-Keras-models-to-production-easily.xml @@ -18,13 +18,7 @@ After endless research I’m most glad to serve you an easy to execute guide for - - - - - - diff --git a/assets/first-spirit-xml/2020-03-02/2020-03-02-serverless-architekturen-mit-aws.xml b/assets/first-spirit-xml/2020-03-02/2020-03-02-serverless-architekturen-mit-aws.xml index 45c95be73..751998eae 100644 --- a/assets/first-spirit-xml/2020-03-02/2020-03-02-serverless-architekturen-mit-aws.xml +++ b/assets/first-spirit-xml/2020-03-02/2020-03-02-serverless-architekturen-mit-aws.xml @@ -22,13 +22,7 @@ Services geschickt zu Anwendungen zusammengesetzt werden können.

- - - - - - diff --git a/assets/first-spirit-xml/2020-03-18/2020-03-18-Dependency-Injection-mit-Google-Guice.xml b/assets/first-spirit-xml/2020-03-18/2020-03-18-Dependency-Injection-mit-Google-Guice.xml index a0275cae5..bece9e2d7 100644 --- a/assets/first-spirit-xml/2020-03-18/2020-03-18-Dependency-Injection-mit-Google-Guice.xml +++ b/assets/first-spirit-xml/2020-03-18/2020-03-18-Dependency-Injection-mit-Google-Guice.xml @@ -16,13 +16,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2020-03-23/2020-03-23-Meine-App-ist-sicher-sicher.xml b/assets/first-spirit-xml/2020-03-23/2020-03-23-Meine-App-ist-sicher-sicher.xml index 614df6888..762734b39 100644 --- a/assets/first-spirit-xml/2020-03-23/2020-03-23-Meine-App-ist-sicher-sicher.xml +++ b/assets/first-spirit-xml/2020-03-23/2020-03-23-Meine-App-ist-sicher-sicher.xml @@ -17,13 +17,7 @@ Tatsächlich enthält die durchschnittliche Webanwendung jedoch stolze 33 Lücke - - - - - - diff --git "a/assets/first-spirit-xml/2020-03-25/2020-03-25-Griff-in-die-Werkzeugkiste-Eine-Toolchain-f\303\274r-React.xml" "b/assets/first-spirit-xml/2020-03-25/2020-03-25-Griff-in-die-Werkzeugkiste-Eine-Toolchain-f\303\274r-React.xml" index f6e893e0a..f3113b7e3 100644 --- "a/assets/first-spirit-xml/2020-03-25/2020-03-25-Griff-in-die-Werkzeugkiste-Eine-Toolchain-f\303\274r-React.xml" +++ "b/assets/first-spirit-xml/2020-03-25/2020-03-25-Griff-in-die-Werkzeugkiste-Eine-Toolchain-f\303\274r-React.xml" @@ -17,13 +17,7 @@ Dabei schauen wir uns Komponenten einer Toolchain an und erfahren wie wir diese - - - - - - diff --git a/assets/first-spirit-xml/2020-04-01/2020-04-01-mehraufwand-reduzieren.xml b/assets/first-spirit-xml/2020-04-01/2020-04-01-mehraufwand-reduzieren.xml index fb9a9b2a7..3d55c8e5b 100644 --- a/assets/first-spirit-xml/2020-04-01/2020-04-01-mehraufwand-reduzieren.xml +++ b/assets/first-spirit-xml/2020-04-01/2020-04-01-mehraufwand-reduzieren.xml @@ -20,13 +20,7 @@ Daneben gibt es das Tolerant Reader Pattern, dass den Mehraufwand, eine Schnitts - - - - - - diff --git a/assets/first-spirit-xml/2020-04-08/2020-04-08-Architekturanalyse-sowie-Refactoring-auf-Basis-von-Tactical-Domain-Driven-Design.xml b/assets/first-spirit-xml/2020-04-08/2020-04-08-Architekturanalyse-sowie-Refactoring-auf-Basis-von-Tactical-Domain-Driven-Design.xml index e72049fc8..7de67eddc 100644 --- a/assets/first-spirit-xml/2020-04-08/2020-04-08-Architekturanalyse-sowie-Refactoring-auf-Basis-von-Tactical-Domain-Driven-Design.xml +++ b/assets/first-spirit-xml/2020-04-08/2020-04-08-Architekturanalyse-sowie-Refactoring-auf-Basis-von-Tactical-Domain-Driven-Design.xml @@ -22,13 +22,7 @@ Dieses Werkzeug ist in Verbindung mit meiner Bachelorarbeit an der Hochschule Da - - - - - - diff --git a/assets/first-spirit-xml/2020-04-20/2020-04-20-wie-alexa-ein-it-projektteam-unterstuetzen-kann.xml b/assets/first-spirit-xml/2020-04-20/2020-04-20-wie-alexa-ein-it-projektteam-unterstuetzen-kann.xml index e8c54cd09..1a9a5a54e 100644 --- a/assets/first-spirit-xml/2020-04-20/2020-04-20-wie-alexa-ein-it-projektteam-unterstuetzen-kann.xml +++ b/assets/first-spirit-xml/2020-04-20/2020-04-20-wie-alexa-ein-it-projektteam-unterstuetzen-kann.xml @@ -17,13 +17,7 @@ Wie aber sehen die Entwicklungen und Einsatzmöglichkeiten im Unternehmenskontex - - - - - - diff --git a/assets/first-spirit-xml/2020-04-27/2020-04-27-inkrementelle-softwaremigration-nach-der-chicken-little-methode.xml b/assets/first-spirit-xml/2020-04-27/2020-04-27-inkrementelle-softwaremigration-nach-der-chicken-little-methode.xml index 908f2ee58..3e96b720c 100644 --- a/assets/first-spirit-xml/2020-04-27/2020-04-27-inkrementelle-softwaremigration-nach-der-chicken-little-methode.xml +++ b/assets/first-spirit-xml/2020-04-27/2020-04-27-inkrementelle-softwaremigration-nach-der-chicken-little-methode.xml @@ -20,13 +20,7 @@ Diese Methode beschreibt die Migration solcher Legacy Software in mehreren Schri - - - - - - diff --git "a/assets/first-spirit-xml/2020-05-04/2020-05-04-Rust-f\303\274r-Java-Entwickler-Teil-1.xml" "b/assets/first-spirit-xml/2020-05-04/2020-05-04-Rust-f\303\274r-Java-Entwickler-Teil-1.xml" index e486cb565..8a6bf6b45 100644 --- "a/assets/first-spirit-xml/2020-05-04/2020-05-04-Rust-f\303\274r-Java-Entwickler-Teil-1.xml" +++ "b/assets/first-spirit-xml/2020-05-04/2020-05-04-Rust-f\303\274r-Java-Entwickler-Teil-1.xml" @@ -18,13 +18,7 @@ In diesem Artikel wollen wir uns Einblick in die (noch junge) Programmiersprache - - - - - - diff --git a/assets/first-spirit-xml/2020-05-08/2020-05-08-frontend-migration-mittels-der-chicken-little-methode.xml b/assets/first-spirit-xml/2020-05-08/2020-05-08-frontend-migration-mittels-der-chicken-little-methode.xml index d2a9f71f0..b4000754e 100644 --- a/assets/first-spirit-xml/2020-05-08/2020-05-08-frontend-migration-mittels-der-chicken-little-methode.xml +++ b/assets/first-spirit-xml/2020-05-08/2020-05-08-frontend-migration-mittels-der-chicken-little-methode.xml @@ -25,13 +25,7 @@ Als Zieltechnologie für die Migration dient in diesem Beispiel das Sing - - - - - - diff --git "a/assets/first-spirit-xml/2020-05-13/2020-05-13-Rust-f\303\274r-Java-Entwickler-Teil-2.xml" "b/assets/first-spirit-xml/2020-05-13/2020-05-13-Rust-f\303\274r-Java-Entwickler-Teil-2.xml" index 77f2dcda5..2beeeefac 100644 --- "a/assets/first-spirit-xml/2020-05-13/2020-05-13-Rust-f\303\274r-Java-Entwickler-Teil-2.xml" +++ "b/assets/first-spirit-xml/2020-05-13/2020-05-13-Rust-f\303\274r-Java-Entwickler-Teil-2.xml" @@ -18,13 +18,7 @@ In diesem Teil der Serie möchte ich auf zwei weitere, wichtige Aspekte des Fram - - - - - - diff --git a/assets/first-spirit-xml/2020-05-22/2020-05-22-Optimierung-von-Queries-in-neo4j.xml b/assets/first-spirit-xml/2020-05-22/2020-05-22-Optimierung-von-Queries-in-neo4j.xml index bde6a144a..7ec27675e 100644 --- a/assets/first-spirit-xml/2020-05-22/2020-05-22-Optimierung-von-Queries-in-neo4j.xml +++ b/assets/first-spirit-xml/2020-05-22/2020-05-22-Optimierung-von-Queries-in-neo4j.xml @@ -18,13 +18,7 @@ In diesem Blogbeitrag werfen wir einen genaueren Blick auf die Graphdatenbank Ne - - - - - - diff --git a/assets/first-spirit-xml/2020-05-26/2020-05-26-Behaviour-Driven-Development-und-automatierte-Tests-mit-Seed-Test.xml b/assets/first-spirit-xml/2020-05-26/2020-05-26-Behaviour-Driven-Development-und-automatierte-Tests-mit-Seed-Test.xml index 5d9d52ab3..08e6794ef 100644 --- a/assets/first-spirit-xml/2020-05-26/2020-05-26-Behaviour-Driven-Development-und-automatierte-Tests-mit-Seed-Test.xml +++ b/assets/first-spirit-xml/2020-05-26/2020-05-26-Behaviour-Driven-Development-und-automatierte-Tests-mit-Seed-Test.xml @@ -18,13 +18,7 @@ Dieser Beitrag zeigt, was sich hinter Cucumber und Behaviour Driven Development - - - - - - diff --git a/assets/first-spirit-xml/2020-06-12/2020-06-12-gruende-und-strategien-fuer-cloud-migration.xml b/assets/first-spirit-xml/2020-06-12/2020-06-12-gruende-und-strategien-fuer-cloud-migration.xml index 1e635106a..c0283c62f 100644 --- a/assets/first-spirit-xml/2020-06-12/2020-06-12-gruende-und-strategien-fuer-cloud-migration.xml +++ b/assets/first-spirit-xml/2020-06-12/2020-06-12-gruende-und-strategien-fuer-cloud-migration.xml @@ -22,13 +22,7 @@ In meinem Blogbeitrag zeige ich, dass sich auch für bestehende Anwendungen der - - - - - - diff --git a/assets/first-spirit-xml/2020-07-08/2020-07-08-adesso-testing-day-2020.xml b/assets/first-spirit-xml/2020-07-08/2020-07-08-adesso-testing-day-2020.xml index b0ca57610..feb4e853b 100644 --- a/assets/first-spirit-xml/2020-07-08/2020-07-08-adesso-testing-day-2020.xml +++ b/assets/first-spirit-xml/2020-07-08/2020-07-08-adesso-testing-day-2020.xml @@ -14,13 +14,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2020-08-03/2020-08-03-Geschaeftsprozesse-in-einer-Microservice-Welt.xml b/assets/first-spirit-xml/2020-08-03/2020-08-03-Geschaeftsprozesse-in-einer-Microservice-Welt.xml index 3929588a4..3eca876d4 100644 --- a/assets/first-spirit-xml/2020-08-03/2020-08-03-Geschaeftsprozesse-in-einer-Microservice-Welt.xml +++ b/assets/first-spirit-xml/2020-08-03/2020-08-03-Geschaeftsprozesse-in-einer-Microservice-Welt.xml @@ -18,13 +18,7 @@ In diesem Blogpost schauen wir uns zwei gängige Architektur-Ansätze an.

- - - - - - diff --git a/assets/first-spirit-xml/2020-08-12/2020-08-12-GraphQL-ist-flexibler,-das-Ende-von-RESTful-APIs.xml b/assets/first-spirit-xml/2020-08-12/2020-08-12-GraphQL-ist-flexibler,-das-Ende-von-RESTful-APIs.xml index 87b40c022..5fc2cfc82 100644 --- a/assets/first-spirit-xml/2020-08-12/2020-08-12-GraphQL-ist-flexibler,-das-Ende-von-RESTful-APIs.xml +++ b/assets/first-spirit-xml/2020-08-12/2020-08-12-GraphQL-ist-flexibler,-das-Ende-von-RESTful-APIs.xml @@ -16,13 +16,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2020-08-17/2020-08-17-GitHub-Actions-im-Java-Projekt.xml b/assets/first-spirit-xml/2020-08-17/2020-08-17-GitHub-Actions-im-Java-Projekt.xml index 2a75c643e..510046de8 100644 --- a/assets/first-spirit-xml/2020-08-17/2020-08-17-GitHub-Actions-im-Java-Projekt.xml +++ b/assets/first-spirit-xml/2020-08-17/2020-08-17-GitHub-Actions-im-Java-Projekt.xml @@ -20,13 +20,7 @@ Abschließend schauen wir uns die automatisierte Release-Erzeugung an.

- - - - - - diff --git a/assets/first-spirit-xml/2020-08-21/2020-08-21-Wireframe-Skizzen-in-UI-Prototypen-umwandeln.xml b/assets/first-spirit-xml/2020-08-21/2020-08-21-Wireframe-Skizzen-in-UI-Prototypen-umwandeln.xml index 5cd9c9854..14f6f0ebe 100644 --- a/assets/first-spirit-xml/2020-08-21/2020-08-21-Wireframe-Skizzen-in-UI-Prototypen-umwandeln.xml +++ b/assets/first-spirit-xml/2020-08-21/2020-08-21-Wireframe-Skizzen-in-UI-Prototypen-umwandeln.xml @@ -18,13 +18,7 @@ In diesem Blog-Post möchte ich einen Ansatz vorstellen, mit dem man diesen Schr - - - - - - diff --git a/assets/first-spirit-xml/2020-09-25/2020-09-25-Herausforderungen_in_der_Domaenenmodellierung.xml b/assets/first-spirit-xml/2020-09-25/2020-09-25-Herausforderungen_in_der_Domaenenmodellierung.xml index b9633b457..b90444ba2 100644 --- a/assets/first-spirit-xml/2020-09-25/2020-09-25-Herausforderungen_in_der_Domaenenmodellierung.xml +++ b/assets/first-spirit-xml/2020-09-25/2020-09-25-Herausforderungen_in_der_Domaenenmodellierung.xml @@ -19,13 +19,7 @@ Diese Sammlung von Werkzeugen ist seitdem unter dem Begriff Domain Driven Design - - - - - - diff --git a/assets/first-spirit-xml/2020-09-28/2020-09-28-Umsetzung-von-Architekturvorgaben-testen.xml b/assets/first-spirit-xml/2020-09-28/2020-09-28-Umsetzung-von-Architekturvorgaben-testen.xml index c70adadf2..f63c1341c 100644 --- a/assets/first-spirit-xml/2020-09-28/2020-09-28-Umsetzung-von-Architekturvorgaben-testen.xml +++ b/assets/first-spirit-xml/2020-09-28/2020-09-28-Umsetzung-von-Architekturvorgaben-testen.xml @@ -19,13 +19,7 @@ Wie dies mit Hilfe von Tool Unterstützung durch ArchUnit sichergestellt werden - - - - - - diff --git a/assets/first-spirit-xml/2020-10-09/2020-10-09-Mobile-Cross-Platform-Entwicklung.xml b/assets/first-spirit-xml/2020-10-09/2020-10-09-Mobile-Cross-Platform-Entwicklung.xml index 80fc47b68..049f4dd87 100644 --- a/assets/first-spirit-xml/2020-10-09/2020-10-09-Mobile-Cross-Platform-Entwicklung.xml +++ b/assets/first-spirit-xml/2020-10-09/2020-10-09-Mobile-Cross-Platform-Entwicklung.xml @@ -20,13 +20,7 @@ Cross-Platform-Frameworks versprechen, die mobile Anwendungsentwicklung zu verei - - - - - - diff --git a/assets/first-spirit-xml/2020-10-19/2020-10-19-cloud-native-migration-mit-der-rearchitecting-strategie.xml b/assets/first-spirit-xml/2020-10-19/2020-10-19-cloud-native-migration-mit-der-rearchitecting-strategie.xml index fed96f3b2..084e3c1b7 100644 --- a/assets/first-spirit-xml/2020-10-19/2020-10-19-cloud-native-migration-mit-der-rearchitecting-strategie.xml +++ b/assets/first-spirit-xml/2020-10-19/2020-10-19-cloud-native-migration-mit-der-rearchitecting-strategie.xml @@ -21,13 +21,7 @@ lauffähige und erweiterbarte Software ausgeliefert werden kann und ich zeige, w - - - - - - diff --git a/assets/first-spirit-xml/2020-10-23/2020-10-23-Zeitersparnis-durch-RPA-und-Microsoft-PowerPlatform.xml b/assets/first-spirit-xml/2020-10-23/2020-10-23-Zeitersparnis-durch-RPA-und-Microsoft-PowerPlatform.xml index a2f348bc4..a461f43ae 100644 --- a/assets/first-spirit-xml/2020-10-23/2020-10-23-Zeitersparnis-durch-RPA-und-Microsoft-PowerPlatform.xml +++ b/assets/first-spirit-xml/2020-10-23/2020-10-23-Zeitersparnis-durch-RPA-und-Microsoft-PowerPlatform.xml @@ -26,13 +26,7 @@ Es geht mir dabei nicht nur um die Optimierung der Netto-Arbeitszeit, die häufi - - - - - - diff --git a/assets/first-spirit-xml/2020-10-30/2020-10-30-Produktiver-mit-Firebase.xml b/assets/first-spirit-xml/2020-10-30/2020-10-30-Produktiver-mit-Firebase.xml index 085df3210..c2c45d389 100644 --- a/assets/first-spirit-xml/2020-10-30/2020-10-30-Produktiver-mit-Firebase.xml +++ b/assets/first-spirit-xml/2020-10-30/2020-10-30-Produktiver-mit-Firebase.xml @@ -18,13 +18,7 @@ Wie fast immer kommen sämtliche Vorteile aber auch mit entsprechenden Nachteile - - - - - - diff --git a/assets/first-spirit-xml/2020-11-13/2020-11-13-Phishining_Kampagne_ZDF.xml b/assets/first-spirit-xml/2020-11-13/2020-11-13-Phishining_Kampagne_ZDF.xml index 2c17763e1..5527d5991 100644 --- a/assets/first-spirit-xml/2020-11-13/2020-11-13-Phishining_Kampagne_ZDF.xml +++ b/assets/first-spirit-xml/2020-11-13/2020-11-13-Phishining_Kampagne_ZDF.xml @@ -17,13 +17,7 @@ Handelt das Opfer nicht korrekt, ist der Klick auf den Link oder Anhang die einz - - - - - - diff --git a/assets/first-spirit-xml/2020-12-03/2020-12-03-Testautomatisierung-in-der-Praxis.xml b/assets/first-spirit-xml/2020-12-03/2020-12-03-Testautomatisierung-in-der-Praxis.xml index af3fcc0ab..14eed816f 100644 --- a/assets/first-spirit-xml/2020-12-03/2020-12-03-Testautomatisierung-in-der-Praxis.xml +++ b/assets/first-spirit-xml/2020-12-03/2020-12-03-Testautomatisierung-in-der-Praxis.xml @@ -20,13 +20,7 @@ In diesem Teil geht es weiter mit der Testautomatisierung, speziell im Bereich d - - - - - - diff --git a/assets/first-spirit-xml/2021-01-07/2021-01-07-wartbarkeit-von-software-teil-1-dokumentation.xml b/assets/first-spirit-xml/2021-01-07/2021-01-07-wartbarkeit-von-software-teil-1-dokumentation.xml index 338d0fb0b..4650643fb 100644 --- a/assets/first-spirit-xml/2021-01-07/2021-01-07-wartbarkeit-von-software-teil-1-dokumentation.xml +++ b/assets/first-spirit-xml/2021-01-07/2021-01-07-wartbarkeit-von-software-teil-1-dokumentation.xml @@ -16,13 +16,7 @@ Im Gegenteil, nun muss sie sich im realen Einsatz bewähren.

- - - - - - diff --git a/assets/first-spirit-xml/2021-01-13/2021-01-13-Authentifizierung-ueber-oeffentliche-Schluessel-mit-Apache-MINA.xml b/assets/first-spirit-xml/2021-01-13/2021-01-13-Authentifizierung-ueber-oeffentliche-Schluessel-mit-Apache-MINA.xml index 370f93d42..6971f2e2c 100644 --- a/assets/first-spirit-xml/2021-01-13/2021-01-13-Authentifizierung-ueber-oeffentliche-Schluessel-mit-Apache-MINA.xml +++ b/assets/first-spirit-xml/2021-01-13/2021-01-13-Authentifizierung-ueber-oeffentliche-Schluessel-mit-Apache-MINA.xml @@ -20,13 +20,7 @@ Anschließend schauen wir uns die Implementierung der Authentifizierung über ö - - - - - - diff --git a/assets/first-spirit-xml/2021-03-01/2021-03-01-Passworthashing_Aber_Sicher.xml b/assets/first-spirit-xml/2021-03-01/2021-03-01-Passworthashing_Aber_Sicher.xml index ded2c5468..929a1d665 100644 --- a/assets/first-spirit-xml/2021-03-01/2021-03-01-Passworthashing_Aber_Sicher.xml +++ b/assets/first-spirit-xml/2021-03-01/2021-03-01-Passworthashing_Aber_Sicher.xml @@ -20,13 +20,7 @@ Illustriert werden die Beispiele in Java und Spring-Security.

- - - - - - diff --git a/assets/first-spirit-xml/2021-03-04/2021-03-04-Why-you-should-use-WebAssembly-to-build-your.xml b/assets/first-spirit-xml/2021-03-04/2021-03-04-Why-you-should-use-WebAssembly-to-build-your.xml index e115508fc..21d714cc4 100644 --- a/assets/first-spirit-xml/2021-03-04/2021-03-04-Why-you-should-use-WebAssembly-to-build-your.xml +++ b/assets/first-spirit-xml/2021-03-04/2021-03-04-Why-you-should-use-WebAssembly-to-build-your.xml @@ -19,13 +19,7 @@ In this article, two identical applications are programmed in WebAssembly and Ja - - - - - - diff --git a/assets/first-spirit-xml/2021-03-08/2021-03-08-wartbarkeit-von-software-teil-2-tests.xml b/assets/first-spirit-xml/2021-03-08/2021-03-08-wartbarkeit-von-software-teil-2-tests.xml index e2a4cc72e..51d02149c 100644 --- a/assets/first-spirit-xml/2021-03-08/2021-03-08-wartbarkeit-von-software-teil-2-tests.xml +++ b/assets/first-spirit-xml/2021-03-08/2021-03-08-wartbarkeit-von-software-teil-2-tests.xml @@ -18,13 +18,7 @@ Dazu beschäftigen wir uns mit den unterschiedlichen Testarten, mit Automatisier - - - - - - diff --git a/assets/first-spirit-xml/2021-03-15/2021-03-15-Intelligenz-vererben.xml b/assets/first-spirit-xml/2021-03-15/2021-03-15-Intelligenz-vererben.xml index f185c63b5..a48190d76 100644 --- a/assets/first-spirit-xml/2021-03-15/2021-03-15-Intelligenz-vererben.xml +++ b/assets/first-spirit-xml/2021-03-15/2021-03-15-Intelligenz-vererben.xml @@ -19,13 +19,7 @@ Falls ausreichende Testdaten nicht zur Verfügung stehen oder aber diese erst zu - - - - - - diff --git a/assets/first-spirit-xml/2021-03-19/2021-03-19-E2E-Tests-vom-Webservice-bis-zur-DB-eines-Monolithen-mit-JUnit.xml b/assets/first-spirit-xml/2021-03-19/2021-03-19-E2E-Tests-vom-Webservice-bis-zur-DB-eines-Monolithen-mit-JUnit.xml index 26fc2049b..ef8676bb9 100644 --- a/assets/first-spirit-xml/2021-03-19/2021-03-19-E2E-Tests-vom-Webservice-bis-zur-DB-eines-Monolithen-mit-JUnit.xml +++ b/assets/first-spirit-xml/2021-03-19/2021-03-19-E2E-Tests-vom-Webservice-bis-zur-DB-eines-Monolithen-mit-JUnit.xml @@ -20,13 +20,7 @@ Dieser Artikel richtet sich an Projektleiter, Architekten oder interessierte Ent - - - - - - diff --git a/assets/first-spirit-xml/2021-04-09/2021-04-09-CleanCode_Schulung_Neu-Konzipierung.xml b/assets/first-spirit-xml/2021-04-09/2021-04-09-CleanCode_Schulung_Neu-Konzipierung.xml index 7ccee092d..69fc6aca0 100644 --- a/assets/first-spirit-xml/2021-04-09/2021-04-09-CleanCode_Schulung_Neu-Konzipierung.xml +++ b/assets/first-spirit-xml/2021-04-09/2021-04-09-CleanCode_Schulung_Neu-Konzipierung.xml @@ -16,13 +16,7 @@ - - - - - - diff --git a/assets/first-spirit-xml/2021-04-30/2021-04-30-wartbarkeit-von-software-teil-3.xml b/assets/first-spirit-xml/2021-04-30/2021-04-30-wartbarkeit-von-software-teil-3.xml index 89c5fde03..01506f27b 100644 --- a/assets/first-spirit-xml/2021-04-30/2021-04-30-wartbarkeit-von-software-teil-3.xml +++ b/assets/first-spirit-xml/2021-04-30/2021-04-30-wartbarkeit-von-software-teil-3.xml @@ -18,13 +18,7 @@ Nachdem wir uns in den ersten beiden Teilen der Reihe “Wartbarkeit von Softwar - - - - - - diff --git a/assets/first-spirit-xml/2021-05-18/2021-05-18-Diverstaet-in-der-Softwareentwicklung.xml b/assets/first-spirit-xml/2021-05-18/2021-05-18-Diverstaet-in-der-Softwareentwicklung.xml index 5a01df3cd..aaa8c5abc 100644 --- a/assets/first-spirit-xml/2021-05-18/2021-05-18-Diverstaet-in-der-Softwareentwicklung.xml +++ b/assets/first-spirit-xml/2021-05-18/2021-05-18-Diverstaet-in-der-Softwareentwicklung.xml @@ -20,13 +20,7 @@ Wie könnte also der vermehrte Einsatz von diesen verschiedenen Merkmalen in Sof - - - - - - diff --git a/assets/first-spirit-xml/2021-06-16/2021-06-16-Adressierung_von_Herausforderungen_in_der_Domaenenmodellierung.xml b/assets/first-spirit-xml/2021-06-16/2021-06-16-Adressierung_von_Herausforderungen_in_der_Domaenenmodellierung.xml index bfac4e939..172837ad8 100644 --- a/assets/first-spirit-xml/2021-06-16/2021-06-16-Adressierung_von_Herausforderungen_in_der_Domaenenmodellierung.xml +++ b/assets/first-spirit-xml/2021-06-16/2021-06-16-Adressierung_von_Herausforderungen_in_der_Domaenenmodellierung.xml @@ -17,13 +17,7 @@ DDD wurde erstmalig durch Eric Evans in seinem Buch Domain Driven Design - T - - - - - - diff --git a/assets/first-spirit-xml/2021-06-18/2021-06-18-Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong.xml b/assets/first-spirit-xml/2021-06-18/2021-06-18-Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong.xml index d6f38a893..b36a1c1ed 100644 --- a/assets/first-spirit-xml/2021-06-18/2021-06-18-Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong.xml +++ b/assets/first-spirit-xml/2021-06-18/2021-06-18-Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong.xml @@ -18,13 +18,7 @@ In diesem Artikel wird eine Methode vorgestellt, wie man diese Anforderung mit H - - - - - - diff --git a/assets/first-spirit-xml/2021-06-24/2021-06-24-example.xml b/assets/first-spirit-xml/2021-06-24/2021-06-24-example.xml new file mode 100644 index 000000000..2ffffc8d8 --- /dev/null +++ b/assets/first-spirit-xml/2021-06-24/2021-06-24-example.xml @@ -0,0 +1,192 @@ + + + + + + Welche Möglichkeiten haben wir, wenn neben einer REST-API auch eine SOAP-Schnittstelle zur Verfügung stehen soll? +In diesem Artikel wird eine Methode vorgestellt, wie man diese Anforderung mit Hilfe von Kong umsetzen kann.

+ +]]>
+ + + + + + + + + + + + + + + + + +

Welche Möglichkeiten haben wir, wenn neben einer REST-API auch eine SOAP-Schnittstelle zur Verfügung stehen soll? +In diesem Artikel wird eine Methode vorgestellt, wie man diese Anforderung mit Hilfe von Kong umsetzen kann.

+ +]]>
+ +
+
+
+

Welche Möglichkeiten haben wir, wenn neben einer REST-API auch eine SOAP-Schnittstelle zur Verfügung stehen soll? +In diesem Artikel wird eine Methode vorgestellt, wie man diese Anforderung mit Hilfe von Kong umsetzen kann.

+ +

Motivation

+

Wie bereist beschrieben, kann es manchmal gewollt sein, dass eine Schnittstelle über REST und SOAP erreichbar ist. +Hier stellt sich nun die Frage wie man diese Anforderung realisiert.

+ +

Eine intuitive Herangehensweise wäre es, für den Service die zwei Schnittstellen getrennt zu implementieren. +Diese Lösung hat allerdings den Nachteil, dass die Schnittstellen sich durch die getrennte Implementierung unterschiedlich verhalten könnten. +Außerdem müssen bei einer Änderung des Service beide Schnittstellen verändert werden, womit zusätzlicher Arbeitsaufwand verbunden wäre.

+ +

Um diese Probleme zu vermeiden, könnten wir für den Service nur eine Schnittstelle implementieren, zum Beispiel eine REST-API, da diese heutzutage häufig verwendet wird. +Die SOAP-Schnittstelle hingegen könnten wir anschließend aus der REST-API generieren.

+ +

Vorstellung der Architektur

+

Für die Realisierung beider Schnittstellen wird ein Kong API Gateway mit dem Kong Plugin soap2rest sowie ein REST-Service benötigt.

+ +

Architektur Skizze

+ +

Die Abbildung zeigt, wie die einzelnen Komponenten miteinander verknüpft sind. +Das Kong API Gateway verwaltet den Zugriff auf den REST-Service. +Für den Fall, dass wir eine Anfrage über die REST-Schnittstelle stellen, wird diese Anfrage an den Service weitergeleitet und bearbeitet.

+ +

Für die Verarbeitung von SOAP-Anfragen wird das Kong Plugin soap2rest verwendet. +Das Plugin benötigt zur Konfiguration zwei Dateien. +Damit das Plugin die SOAP-Anfragen richtig verarbeiten kann, benötigt es die WSDL der SOAP-Schnittstelle. +Und um die Konvertierung von SOAP zu REST Anfragen korrekt durchzuführen, wird zusätzlich die OpenAPI-Spezifikation der REST-API benötigt.

+ +

Funktionsablauf des Plugins

+

Funktionsablauf des Plugins

+ +

Diese Abbildung zeigt den Fall, dass eine Anfrage über die SOAP-Schnittstelle gestellt wird. +Sobald Kong eine Anfrage über die Route der SOAP-Schnittstelle registriert, wird das Plugin soap2rest ausgeführt. +Das Plugin konvertiert die Anfrage in eine gültige REST-Anfrage und sendet diese an den REST-Service. +Nachdem der REST-Service geantwortet hat, wird die Antwort in eine gültige SOAP-Antwort übersetzt und zurückgegeben.

+ +

Anhand des folgenden Beispiels lässt sich der Ablauf näher verdeutlichen. +Angenommen, folgende Anfrage wird an die SOAP-Schnittstelle gestellt.

+ +
<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope
+    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:tns="http://www.w3.org/2001/XMLSchema">
+    <soap:Body>
+        <tns:GetPetByPetid_InputMessage>
+            <tns:petId>1</tns:petId>
+        </tns:GetPetByPetid_InputMessage>
+    </soap:Body>
+</soap:Envelope>
+
+ +

Aus dieser Anfrage lassen sich verschiedene Informationen ableiten. +Zum einen wird mit dieser Anfrage die SOAP-Action GetPetByPetid ausgeführt. +Zusätzlich beinhaltet die Anfrage den Parameter petId mit dem Wert 1. +Anhand dieser Informationen kann die Anfrage der passenden REST Anfrage zugeordnet werden. +In diesem Fall entspricht die Anfrage dem Pfad /pet/1.

+ +

Nachdem das Plugin die generierte Anfrage an die REST-API gestellt hat, bekommt es folgende Antwort:

+ +
{
+  "id": 1,
+  "name": "doggie",
+  "photoUrls": [],
+  "tags": [],
+  "status": "available"
+}
+
+ +

Anschließend wird diese Antwort vom Plugin in gültiges XML umgewandelt und in eine SOAP-Antwort eingesetzt, welche anschließend zurückgegeben wird.

+ +
<?xml version="1.0" encoding="UTF-8"?>
+<soap:Envelope
+  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+  xmlns:tns="http://www.w3.org/2001/XMLSchema">
+  <soap:Body>
+    <tns:GetPetByPetid_OutputMessage>
+        <tns:Pet>
+            <tns:id>1</tns:id>
+            <tns:name>doggie</tns:name>
+            <tns:photoUrls></tns:photoUrls>
+            <tns:tags></tns:tags>
+            <tns:status>available</tns:status>
+        </tns:Pet>
+    </tns:GetPetByPetid_OutputMessage>
+  </soap:Body>
+</soap:Envelope>
+
+ +

Besonderheiten des Kong Plugins soap2rest

+
Analyse der Schnittstellen-Spezifikationen
+

Die Analyse der WSDL und der OpenAPI ist ein wichtiger Bestandteil des Plugins. +Sie wird nur einmal vor der ersten Anfrage an die SOAP-Schnittstelle ausgeführt, um die Schnittstelle zu konfigurieren. +Dadurch verzögert sich die Antwort der ersten Anfrage im Durchschnitt um 200 Millisekunden. +Anschließend wird diese Konfiguration für die Verarbeitung aller folgenden Anfragen verwendet.

+ +

Bei der Analyse der WSDL werden wichtige Merkmale der SOAP-Schnittstelle ausgelesen. +Dazu gehören zum Beispiel das Auslesen der verschiedenen Operationen und ihrer zugehörigen Rückgabetypen und Faults. +Es wird besonders die Struktur der Rückgabetypen betrachtet, damit das Plugin später gültige SOAP-Antworten generieren kann.

+ +

Nachdem die WSDL analysiert wurde, wird die Konfiguration des Plugins mit der OpenAPI-Spezifikation der REST-API vervollständigt. +Dabei werden den SOAP-Operationen die passenden Pfade der REST-API automatisiert zugeordnet. +Außerdem werden jeder Operation die passenden Content-Types zugeordnet, damit die HTTP-Header bei der Weiterleitung der Anfragen an die REST-API korrekt gesetzt werden können.

+ +
Request und Response Konvertierung
+

Bei der Konvertierung von eingehenden SOAP-Anfragen, werden diese in den meisten Fällen direkt von XML in JSON überführt. +Manchmal müssen davor aber noch andere Verarbeitungsschritte durchgeführt werden. +Zum Beispiel werden sämtliche SOAP-Header in HTTP-Header überführt. +Außerdem werden Dateiuploads in Multipart Bodys überführt und den Dateien wird mit Hilfe einer Mime Type Analyse der richtige Content-Type zugeordnet.

+ +

Auch bei der Konvertierung der REST-Antworten werden verschiedene Zwischenschritte benötigt. +Wenn die REST-API nicht den Statuscode 200 zurückgibt, wird die Antwort in ein gültiges SOAP-Fault umgewandelt.

+ +

Bei der Umwandlung der Antwort in XML wird besonders darauf geachtet, dass die Reihenfolge der Attribute des Rückgabetyps mit der Reihenfolge in der WSDL übereinstimmen. +Dafür wird die automatisch generierte Konfiguration des Plugins verwendet.

+ +

Auswirkungen auf die Verfügbarkeit

+

Damit der Einsatz des Plugins sich lohnt, sollte die Verfügbarkeit der Schnittstelle nicht unter dem Einsatz des Plugins leiden. +Um die Auswirkungen des Plugins auf die Verfügbarkeit der Schnittstelle zu testen, wurde ein Performance- und ein Lasttest vorgenommen.

+ +
Durchführung eines Performancetests
+

Der Performancetest besteht aus vier verschiedenen Anfragen, welche jeweils 10-mal wiederholt wurden. +Zwei der vier Anfragen liefern nur einen HTTP Status Code von 200 und 300 zurück. +Die dritte Anfrage sendet mit einem HTTP POST ein kleines JSON Objekt an die Schnittstelle. +Und die vierte Anfrage versucht die Grenzen der Schnittstelle auszuloten, indem eine Datei an die Schnittstelle gesendet wird.

+ +

Die nachfolgende Grafik zeigt links die Ergebnisse des Performancetests auf die REST-API und rechts die Ergebnisse der SOAP-Schnittstelle.

+ +

Vergleich der Anfragezeiten

+ +

Im direkten Vergleich fällt auf, dass die Performance nur beim Senden von Dateien leidet. +Die Performance aller andern Anfragen verändert sich nur geringfügig.

+ +

Der Anstieg der Antwortzeit ist darauf zurückzuführen, dass bei SOAP-Anfragen deutlich mehr Daten an die Schnittstelle gesendet werden müssen.

+ +
Durchführung eines Lasttests
+

Im Gegensatz zum Performancetest wurden die vier Anfragen 250-mal parallel ausgeführt. +Um ein aussagekräftiges Ergebnis zu erhalten wurde dieser 10-mal wiederholt.

+ +

Die folgende Grafik zeigt die Ergebnisse des Lasttests.

+ +

Lasttest

+ +

Auf den ersten Blick fällt auf, dass die SOAP-Schnittstelle bei vielen parallelen Anfragen längere Antwortzeiten aufweist, als die REST-API. +Vor allem das Senden von Dateien führt zu einem deutlichen Anstieg der Antwortzeit. +Der Kommunikationsaufwand in Verbindung mit den vielen gleichzeitigen Anfragen auf die Schnittstelle ist für die langsamere Antwortzeit verantwortlich.

+ +

Fazit

+

Zusammenfassend lässt sich sagen, dass die Nutzung dieses Kong Plugins den Vorteil hat, dass nicht beide Schnittstellen implementiert werden müssen. +Ein Nachteil ist die zusätzliche Wartezeit auf die Antwort der Schnittstelle, da sich hinter jeder SOAP-Anfrage eine Anfrage auf die REST-API verbirgt. +Diese Verzögerung kann allerdings vernachlässigt werden, da erst bei vielen parallelen Anfragen ein deutlich längere Wartezeit entsteht. +Im Großen und Ganzen überwiegen die Vorteile des Plugins die Nachteile.

+ +
+
+
+]]>
+
+
diff --git a/assets/first-spirit-xml/2021-07-15/2021-07-15-Contract-Driven-Development_Hands-On-am-Beispiel-von-Spring-Cloud-Contract.xml b/assets/first-spirit-xml/2021-07-15/2021-07-15-Contract-Driven-Development_Hands-On-am-Beispiel-von-Spring-Cloud-Contract.xml index f634648f2..7b32445d7 100644 --- a/assets/first-spirit-xml/2021-07-15/2021-07-15-Contract-Driven-Development_Hands-On-am-Beispiel-von-Spring-Cloud-Contract.xml +++ b/assets/first-spirit-xml/2021-07-15/2021-07-15-Contract-Driven-Development_Hands-On-am-Beispiel-von-Spring-Cloud-Contract.xml @@ -21,13 +21,7 @@ Dazu bietet sich Contract-Driven Development an, welches wir uns mittels Spring - - - - - - diff --git a/assets/first-spirit-xml/2021-07-22/2021-07-22-A-Series-of-Rust-Blog-Posts-Exploring-Rust-For-AWS-Lambda-1.xml b/assets/first-spirit-xml/2021-07-22/2021-07-22-A-Series-of-Rust-Blog-Posts-Exploring-Rust-For-AWS-Lambda-1.xml index db3858aef..c845106fe 100644 --- a/assets/first-spirit-xml/2021-07-22/2021-07-22-A-Series-of-Rust-Blog-Posts-Exploring-Rust-For-AWS-Lambda-1.xml +++ b/assets/first-spirit-xml/2021-07-22/2021-07-22-A-Series-of-Rust-Blog-Posts-Exploring-Rust-For-AWS-Lambda-1.xml @@ -19,13 +19,7 @@ I take that as well as a bit of my own curiosity as cause for a series of blog p - - - - - - diff --git "a/assets/first-spirit-xml/2021-08-19/2021-08-19-functional-kotlin-eine-einf\303\274hrung.xml" "b/assets/first-spirit-xml/2021-08-19/2021-08-19-functional-kotlin-eine-einf\303\274hrung.xml" new file mode 100644 index 000000000..d1c1ecd34 --- /dev/null +++ "b/assets/first-spirit-xml/2021-08-19/2021-08-19-functional-kotlin-eine-einf\303\274hrung.xml" @@ -0,0 +1,389 @@ + + + + + + In diesem Blogeintrag widmen wir uns der Programmiersprache Kotlin. +Wir werfen einen kurzen Blick auf die Ursprünge der Sprache, wie sie aufgebaut ist und mit welchen Designprinzipien im Hinterkopf sie entworfen wurde. +An Beispielen betrachten wir die Best Practices und stellen uns dabei die Frage: Was hat das mit funktionaler Programmierung zu tun?

+ +]]>
+ + + + + + + + + + + + + +

In diesem Blogeintrag widmen wir uns der Programmiersprache Kotlin. +Wir werfen einen kurzen Blick auf die Ursprünge der Sprache, wie sie aufgebaut ist und mit welchen Designprinzipien im Hinterkopf sie entworfen wurde. +An Beispielen betrachten wir die Best Practices und stellen uns dabei die Frage: Was hat das mit funktionaler Programmierung zu tun?

+ +]]>
+ +
+
+
+

In diesem Blogeintrag widmen wir uns der Programmiersprache Kotlin. +Wir werfen einen kurzen Blick auf die Ursprünge der Sprache, wie sie aufgebaut ist und mit welchen Designprinzipien im Hinterkopf sie entworfen wurde. +An Beispielen betrachten wir die Best Practices und stellen uns dabei die Frage: Was hat das mit funktionaler Programmierung zu tun?

+ +

Kotlin

+ +

Vor zehn Jahren (2011) stellte JetBrains erstmals die Open-Source Programmiersprache Kotlin auf dem JVM Language Summit vor – “Eine Sprache einfach genug für den gewöhnlichen Entwickler und produktiv genug für moderne Anforderungen an Projekte”. +Die Sprache setzt auf der Java Virtual Machine (JVM) auf und erschien 2016 in der ersten Release-Version. +Seit 2017 wird sie von Google offiziell zur Entwicklung von Android-Apps unterstützt und ist seit 2019 Googles bevorzugte Sprache für diese Plattform.

+ +

Im TIOBE-Index1 rangiert Kotlin aktuell (Juli 2021) auf Platz 38 der beliebtesten Programmiersprachen. +Betrachtet man ausschließlich die JVM-spezifischen Sprachen steht Kotlin dort auf Platz 4 (übertrumpft von #36 Scala, #15 Groovy und #2 Java).

+ +

Im PYPL-Index2 belegt Kotlin den 11. Platz.

+ +

Kotlin, eine statisch typisierte Programmiersprache, ist voll interoperabel zu Java-Programmen und -Bibliotheken und kann ohne aufwändige Integration in bereits bestehende Projekte eingepflegt werden.

+ +
Grundlagen
+

Jeder Einstieg in eine Programmiersprache fängt gleich an. +Man muss sich an die Syntax gewöhnen. +Folgendes Beispiel zeigt ein kleines, in Kotlin geschriebenes Programm, welches zuerst das Ergebnis einer Instanzmethode und dann das einer statischen Methode ausgibt:

+
fun main(){
+    val mainClassInstance = MainClass("instanceString")
+    println(mainClassInstance.instanceMethod())
+    println(MainClass.staticMethod(3))
+}
+
+class MainClass(private var member: String){
+    companion object{
+        fun staticMethod(parameter:Int):Int{
+            return parameter*2
+        }
+    }
+    
+    public fun instanceMethod():String{
+        return "A"
+    }
+}
+
+ +

Das companion object ist, wie der Name es andeutet, ein Begleiterobjekt zu dieser Klasse und verhält sich ähnlich der statischen Initialisierung in Java (auch wenn das Begleiterobjekt noch einiges mehr kann, auf das ich hier nicht eingehen werde). +Anders als in Java werden die Rückgabewerte von Methoden am Ende des Methodenkopfs plaziert und auch für Wertdefinitionen und Parameter wird der jeweilige Typ durch einen “:” getrennt auf die rechte Seite gestellt. +Kotlin unterstützt Typinferenz, weswegen die Typdefinitionen in den meisten Fällen auch weggelassen werden können. +Was – anders als bei Java – hier auch auffällt, ist, dass ich die Properties der MainClass direkt hinter den Klassennamen in “( )” definieren kann und sie nicht im Codeblock schreiben muss (, aber auch das könnte ich). +Kotlin generiert für die Variablen Getter- und Setter-Methoden und für die Values nur Getter-Methoden. +Auf den Unterschied komme ich im Abschnitt Immutabilität zu sprechen. +Wie das Beispiel oben auch zeigt, habe ich einen primären Konstruktor für die MainClassgeschrieben, der sich direkt im Header befindet. +Die in den Klammern des Konstruktors angegebenen Properties (hier member) entsprechen direkt einer Deklaration dieser als Teil der Klasse. +Auch die Semikolons können wir in den meisten Fällen weglassen.

+ +
Nullsicherheit
+

Eine Ärgerlichkeit, mit der wir uns im Entwicklungsalltag häufig auseinandersetzen müssen, ist das Behandeln von Nullpointer-Exceptions, also dem Fehlen von Daten an Stellen, an denen das Programm welche erwartet hat. +Tony Hoare, der Erfinder der Null-Referenz, hielt 2009 einen Vortrag und nannte als Grund für dessen Einführung die Einfachheit, mit der sie zu implementieren gewesen sei. +Er bezeichnet seine Entscheidung inzwischen als “Milliarde-Dollar-Fehler”: +(My billion-dollar mistake) +Kotlin behandelt dieses Problem aus meiner Sicht pragmatisch (Null-Safety), indem, wenn nicht anders angegeben, Werte einfach nicht null sein dürfen. +Betrachten wir folgendes kleines Beispiel eines Produkts, für das ein Preis mit Steuer berechnet werden soll.

+
fun main() {
+    val product = Product(4.99)
+    val vat: Double = null
+    product.getConsumerPrice(vat)
+}
+
+class Product(private val price: Double) {
+    fun getConsumerPrice(vat: Double): Double {
+        val tempValue = helperFunction(vat)
+        return tempValue * this.price
+    }
+    ...
+}
+
+

Was tendenziell in Java und vielen anderen Sprachen funktioniert wird hier vom Compiler mit einer Fehlermeldung quittiert, da der Wert val vat: Double als Double mit Wert definiert und null dort nicht erlaubt ist. +So werden wir bei der Entwicklung immer informiert, wenn Daten potentiell undefinierte Zustände annehmen könnten: +"Kotlin: Null can not be a value of a non-null type Double" +Manchmal lässt es sich allerdings auch nicht vermeiden oder ist erwünscht, dass ein null Wert übernommen wird; +Das kann zum Beispiel an Schnittstellen der Fall sein, an denen ein Standardwert keinen Sinn ergibt (auch wenn sich hier wieder darüber streiten lässt, ob ein Standardwert wirklich nicht die bessere Entscheidung ist). +Wir können die Werte mit einem ? markieren, um kenntlich zu machen, dass sie null (nullable) sein dürfen: +val vat: Double? = null +Hier kommt die Arbeit zum Vorschein, die uns der Compiler durch diese kleine Änderung abnimmt: product.getConsumerPrice(vat) wird mit dem Double?aufgerufen, aber getConsumerPrice(vat: Double) erwartet einen Wert, der nicht null ist. +Auch das erkennt der Compiler und gibt Type mismatch: inferred type is Double? but Double was expectedzurück. +So sind wir gezwungen, uns um diesen Fall zu kümmern und entweder vorher sicherzustellen, dass vat nicht null sein kann, oder einen Nullwert als Eingabeparameter zu erlauben, wodurch sich die Fehlermeldung auf nachfolgende Aufrufe von vat verbreitet.

+ +

Ein anderes Beispiel zeigt, wie wir uns beim Programmieren mit Nullwerten in Kotlin viel Boilerplate-Code sparen können. +Dafür schauen wir uns zunächst ein Problem in Java und anschließend eine Lösung in Kotlin an:

+
class Head {
+    public Node next;
+}
+class Node {
+    public Node next;
+    String value = null;
+}
+...
+head.next.next.value;
+
+

Die Suche von value in dem Beispiel kann, wenn einer der Zwischenaufrufe null ist, zu einer NullpointerException führen. +Um dieses Problem zu umgehen, müssen wir zwischen den Aufrufen null-Checks einführen. +Um Platz zu sparen schreibe ich die Prüfungen direkt als ternäre Operationen:

+
Head head = new Head();
+Node nodeA = head.next != null? head.next :null;
+Node nodeB = nodeA.next != null? nodeA.next :null;
+String value = nodeB != null? nodeB.value: null;
+
+

In Kotlin kann bei potentiellen Nullwerten ? eingesetzt werden, um diese zu erlauben:

+
class Head(val next: Node?)
+class Node(val next: Node?, val value: String)
+...
+val head = Head(null) // Bei der Initialisierung muss ich den Wert für 'next' direkt angeben und kann ihn nicht unbestimmt lassen
+val string = head.next?.next?.value
+
+

Dieser Aufruf führt zu keiner NullpointerException, sondern weist string null zu, da bereits der Aufruf von head.next? null zurückgibt. +Der Wert ist dabei implizit vom Typ String?, wodurch auch alle folgenden Aufrufe vom Compiler wieder geprüft werden.

+ +

Alternativ kann der Elvis-Opeator ?: genutzt werden, um in solchen Fällen direkt einen Standardwert zuzuweisen, sodass statt String? der Typ String inferiert wird.

+
val string = head.next?.next?.value?:"default"
+
+ +

So kann sichergestellt werden, dass Nullwerte innerhalb der Anwendung angemessen behandelt werden können.

+ +
Immutabilität
+

In den beiden Beispielen der vorherigenen Sektionen habe ich das val- und das var-Schlüsselwort zur Definition von Werten genutzt. +val wird genutzt um einen zur Laufzeit unveränderlichen Wert zu definieren (anders noch als const, welches für unveränderliche, zur Kompilierzeit bekannte, Werte steht). +Es ist vergleichbar mit final aus Java. +Auf der anderen Seite steht das var-Schlüsselwort mit dem herkömmliche Variablen beschrieben werden können. +Immutabilität hilft während der Entwicklung Nebeneffekte im Code auf ein Minimum zu reduzieren und schafft so Sicherheit vor allem für Parallelität. +Betrachten wir folgendes Beispiel in Java:

+
class SideEffect {
+    public int member = 0;
+
+    public int someCalculation(int input) {
+        int aux = member + 2;
+        int result = member + aux + input;
+        member++;
+        return result;
+    }
+}
+
+

someCalculation nutzt die Variable member für einige Berechnungen. +In einer synchronen Umgebung ist dies problemlos möglich. +Soll die Methode allerdings parallel ausgeführt werden, kann es zu inkonsistentem Verhalten kommen, da member zu verschiedenen Zeitpunkten innerhalb der Ausführung der Methode unterschiedliche Werte annehmen kann. +Besser ist hier eine Lösung, die someCalculation weitestgehend unabhängig vom aktuellen Wert von membermacht. +Denkbar ist:

+
public int someCalculation(int input, int memberVal) {
+    int aux = memberVal + 2;
+    int result = memberVal + aux + input;
+    member++;
+    return result;
+}
+
+

Durch das Verlagern des für die Berechnung genutzten Wertes ist sichergestellt, dass die Methode, selbst wenn sich member zur Laufzeit ändert, innerhalb ihres Ausführungskontextes einen konsistenten Zustand einhält. +An dieser Stelle bediene ich mich zusätzlich an einigen Punkten, auf die man zum Thema Immutabilität im Internet immer wieder trifft:

+
    +
  • Threadsicherheit (Durch Zugriff auf Werte, die sich nicht ändern)
  • +
  • Keine versteckten Nebeneffekte (Es gibt kein Risiko, dass Methoden unbemerkt Werte an anderen Stellen ändern)
  • +
  • Sicherheit vor Nullwerten (Wenn ein Wert einmal überprüft wurde, behält er seine Gültigkeit)
  • +
  • Leichteres Caching (Wenn ein Wert einmal geladen wurde und sich Rahmenbedingungen ändern, ist sichergestellt, dass dieser Wert nach wie vor gültig ist und nicht neu geladen werden muss)
  • +
  • Bessere Kapselung von Methoden und Klassen (Es ist sichergestellt, dass Methoden und Klassen, die untereinander kommunizieren, sich nicht gegenseitig verändern)
  • +
  • Einfacher zu Testen (Durch feste Werte und fehlende Nebeneffekte sind die Punkte, die es bei Fehlern zu überprüfen gilt, weniger und einfacher)
  • +
  • Leichtere Lesbarkeit und Wartbarkeit (Geht einher mit der leichteren Testbarkeit)
  • +
  • Vorhersagbarkeit (Wenn Werte konkret sind, können zuverlässige Annahmen getroffen werden)
  • +
+ +

Diese Auflistung zeigt, dass der Aufwand für Immutabilität im Verältnis zu den Vorteilen in den meisten Fällen gering ausfällt.

+ +

Funktionale Programmierung

+

An dieser Stelle macht es Sinn, die funktionalen Programmierung ins Spiel zu bringen. +Was ist funktionale Programmierung und wie kann sie uns bei unserer Arbeit helfen? +Die funktionale Programmierung ist ein Ansatz der Programmierung, die Verarbeitung von Daten nicht anweisungsgetrieben (imperativ, wie z.B. in Java) zu konzipieren, sondern aus einer mathematischen Perspektive heraus – funktional – zu betrachten. +Also statt dass wir ein Problem aus der Perspektive betrachten, jeden Schritt einzeln durchzugehen, arbeiten wir mit einer Menge von Daten, auf die Operationen angewandt werden und die mitunter eine neue Menge von Daten erzeugt. +Die funktionale Programmierung ist etwas, was in vielen großen Programmiersprachen immer mehr Einzug hält, auch weil die Rechenleistung heutiger Computer so hoch ist, dass die schlechtere Performance, die durch diesen Ansatz erreicht wird, nicht mehr ins Gewicht fällt. +Theoretische Grundlage der funktionalen Programmierung ist das Lambda-Kalkül, welches in den 30er Jahren von Church und Kleene zur Beschreibung von Funktionen eingeführt wurde. +Ein einfacher Lambda-Ausdruck sieht dabei wie folgt aus und beschreibt hier f(x)=x+2:

+
λx.x+2
+
+

Lambda-Ausdrücke kennen wir aus der Entwicklung im Java-Kontext hauptsächlich in Form von Lambda-Ausdrücken (ab Java 8 in 2014). +Collections müssen dazu erst in einen stream konvertiert, transformiert und dann dann wieder zurück konvertiert werden:

+
strings
+  .stream()
+  .filter(s -> s.length() == 5)
+  .collect(Collectors.toList());
+
+

Lambda-Ausdrücke gibt es auch in Kotlin und werden dort viel häufiger verwendet. +Gibt es nur einen Wert im Lambda-Ausdruck der gebunden werden muss, kann der implizite Name it benutzt werden, statt dem Laufwert einen konkreten Namen geben zu müssen.

+
strings.filter { it.length == 5 }
+
+

Auch wenn beide Beispiele hier nur einfache sind, empfinde ich persönlich die Kotlin-seitigen Lösungen häufig intuitiver und kürzer als das bei Java der Fall ist. +Allein der Wegfall der Konvertierungen reduziert den Boilerplate-Code und erleichtert damit die Wartung der Software.

+ +
map, reduce, filter, …
+

Die filter-Methode haben wir gerade eben kennengelernt. +Wie der Name beschreibt, kann sie genutzt werden, um Elemente aus einer Menge an Daten herauszufiltern. +Die zwei wichtigen anderen Methoden, die häufig eingesetzt werden, sind die map- und die reduce-Methode. +map iteriert über jedes Element einer Menge von Daten und wendet eine Funktion auf dieses an. +Heraus kommt dabei eine neue Menge von Daten, die möglicherweise geändert wurden. +(Ich sage möglicherweise, weil die identische Abbildung f(x)=x existiert)

+
productList.map { product -> product.getConsumerPrice(0.19) }
+
+

Obiges Beispiel zeigt, wie eine Liste von Produkten in eine Liste von Preisen konvertiert wird, indem von jedem Produkt-Element der Konsumentenpreis geholt wird. +Die reduce-Methode verhält sich ähnlich zur map-Methode, mit dem Unterschied, dass das Ergebnis ein einzelnes Element ist. +Auch hier wird auf jedes Element der Menge eine Funktion angewandt. +Das folgende Beispiel zeigt, wie aus unserer Preisliste eine Summe über alle Preise gebildet wird. +sum definiert dabei das Akkumulator-Element im ersten Parameter. +price ist die Laufvariable (eher Laufwert) für die einzelnen Preise, über die iteriert wird.

+
priceList.reduce { sum, price -> sum+price }
+
+

Statt uns mit der Iteration beschäftigen zu müssen, erlaubt diese Heransgehensweise uns das eigentliche Problem behandeln zu können. +map, filter und reduce sind Beispiele für sogenannte Funktionen höherer Ordnung, denn sie nehmen nicht nur einfache Werte als Parameter entgegen, sondern erwarten Funktionen, die sie während ihrer Ausführung aufrufen können. +Ihre Flexibilität im Kern, während sie einen klaren Rahmen für die Verarbeitung von Daten in einer bestimmten Art und Weise schaffen, machen sie zu mächtigen Werkzeugen.

+ +
Extension Functions
+ +
inline fun <S, T : S> Iterable<T>.reduce(
+    operation: (acc: S, T) -> S
+): S
+
+

Definition der reduce Extensionfunktion mit Generics

+ +

Zwei Dinge, die an dem obigen Beispiel auffallen, sind der Einsatz von Generics zur Verallgemeinerung der Anwendbarkeit der Funktion; +Und dass es sich hierbei um eine sogenannte Extension-Function handelt, die – in diesem Fall – Iterable um eine Methode erweitert. +Extension-Functions können genutzt werden um Klassen zu erweitern, ohne neue Klassen oder Interfaces definieren zu müssen, die von der Grundklasse erben. +Hier gibt es mehr Informationen zu inline-Funktionen.

+ +

Hier ist ein Beispiel aus einem Projekt in dem ich gearbeitet habe. +Dort haben wir Extension-Functions häufig genutzt, um vor allem die Lesbarkeit unseres Codes zu erhöhen.

+
data class Partner(
+        val name: String,
+        ...
+)
+
+fun Partner.toDto(): PartnerDto = PartnerDto(
+        name,
+        ...
+)
+...
+partner01.toDto()
+
+

Natürlich lässt sich die Konvertierung in ein DTO auch klassisch lösen:

+
fun createPartnerDto(partner:Partner):PartnerDto {
+        return PartnerDto(
+                partner.name,
+                ...
+        )
+}
+
+createPartnerDto(partner01)
+
+

Allerdings erhöht die erste Variante die Lesbarkeit des Codes, wenn es um Methodenverkettung geht (wie oben zu sehen, gibt es dieses Konzept auch in Java).

+ +

Klassische Funktionen:

+
prepareSend(enrichWithData(createFromPartnerDto(partner01), data), destination)
+
+

Extension-Functions:

+
partner01.toDTO().enrichWithData(data).prepareSend(destination)
+
+

Ein anderes Beispiel zeigt, dass wir auch Klassen erweitern können, die wir nicht selber geschrieben haben. +(Das Schlüsselwort suspend kann ignoriert werden. +Bei Interesse empfehle ich die Einführung in Coroutines.) +Hier haben wir String um eine domänenspezifische Funktion erweitert, um zu diesem eine zugehörige Klasse zu finden:

+
private suspend fun String.getCategoryByCategoryId(): Category?
+...
+val category = item.category?.getCategoryByCategoryId()
+
+ +

Funktionales Testen mit Property Based Testing

+ +

Available automated test technics

+ +

Bildquelle

+ +

Nehmen wir das, was wir bis jetzt betrachtet haben, ergeben sich daraus auch neue Möglichkeiten Softwarequalität sicherzustellen. +Die Standardvorgehensweise für das Schreiben von Tests auf unterster Ebene sind die Unit-Tests. +Kleine Blöcke, die die Funktionalität einzelner, isolierter Code-Ausschnitte überprüfen sollen, indem wir feste Vorgabewerte definieren und an die jeweilige Funktion übergeben. +An dieser Stelle tritt das Property based testing aus der funktionalen Programmierung auf den Plan. +Dahinter verbirgt sich die Idee, statt einige feste Werte auf bestimmte Ergebnisse zu überprüfen (und damit Fehlerräume an den Stellen zu lassen, die man nicht testet), gemeinsame Eigenschaften in Gruppen von Eigabeparametern zu finden, die anschließend randomisiert überprüft werden können. +Schauen wir uns für ein besseres Verständnis ein einfaches Beispiel an. +Die folgende Funktion konkateniert zwei Strings miteinander (Man beachte, dass die geschweiften Klammern weggelassen werden können, wenn es sich bei der Funktion um eine einzelne Operation handelt):

+
public fun concatenate(string1: String, string2: String): String = string1 + string2
+
+

In klassischer Herangehensweise würden wir beim Testen neben den Grenzfällen (leerer String, Nullstring), einen “normalen” Methodenaufruf testen. +Eine andere Art und Weise an den Test heranszugehen ist, sich zu überlegen, welche Eigenschaft die Ergebnisse des Methodenaufrufs gemein haben. +Eigenschaften lassen sich dabei nach folgender Form beschreiben:

+ +

Für Werte … gilt, wenn … zutrifft, dass … wahr/falsch ist

+ +

In diesem Fall können wir also sagen:

+ +

Für alle Strings string1 und string2 gilt, dass die Konkatenation von string1 und string2 mit string1 anfängt und mit string2 endet

+ +

In Kotest könnte der Test dann so aussehen:

+
class StringConcatTest: StringSpec({
+   "Alle konkatenierten Strings starten mit string1 und enden mit string2" {
+      forAll<String, String> { string1, string2 -> {
+         val concat = concatenate(string1, string2)
+         return concat.startsWith(string1) && concat.endsWith(string2)
+         }
+      }
+   }
+})
+
+

Kotest würde mit seinem Standardgenerator diesen Test für 1000 Werte durchspielen und die Ergebnisse prüfen. +Selbstverständlich können auch eigene Generatoren geschrieben werden, die an die eigenen Bedürfnisse angepasst sind. +In diesem Beispiel mag der Test trivial sein, da auch die Fachlichkeit sehr simpel ist. +Je komplexer allerdings die Methode, desto schwieriger kann es sein herauszufinden, welche Menge von Daten eigentlich welche Eigenschaften erfüllen soll. +Ein netter Nebeneffekt: +Tests so zu schreiben zwingt uns damit nochmal auf eine andere Art und Weise über die Korrektheit einer Methode nachzudenken.

+ +

Abschluss

+

Für mich persönlich, mit Java-Erfahrung seit 2012, war mein erster praktischer Kontakt mit Kotlin in 2019 wie eine kleine Offenbarung. +Möglicherweise ist es der Gewöhnungseffekt, dass Kotlin für mich in vielen Punkten durchdachter als Java scheint. +Sicherlich wird dabei auch das noch recht junge Alter der Sprache und die Erfahrungen, die in sie hineingeflossen sind, eine Rolle spielen. +Das funktionale Paradigma und Kotlin in seiner Ausprägung, ich habe es schon vorher geschrieben, kommen mir häufig leichtgängiger vor und es bereitet mir viel Freude, so zu programmieren. +Wir sollten uns dabei aber auch immer bewusst sein, dass dies zu einem gewissen Preis geschieht. +Der Preis, den wir hier zahlen, sind Effizienzeinbußen (die in vielen Projekten allerdings vernachlässigbar sein werden) gegenüber zum Beispiel einer optimierten Programmierlösung in C, sowie der Aufwand, den es für uns mit sich bringt, sich an diese neue Art zu denken zu gewöhnen. +Es hat einen Grund, dass sich viele Sprachen heutzutage an funktionaler Programmierung orientieren und diese sehr populär ist. +Ich hoffe, dass ich euch einen kleinen Einblick in Kotlin und die funktionale Welt geben konnte.

+ +

Wenn ihr an dieser Stelle neugierig geworden seid und euch weiter mit der Sprache beschäftigen möchtet, dann empfehle ich ausdrücklich die Kotlin Koans. +Kotlin Koans sind sehr gute offizielle Tutorial-Reihe, die sich unter anderem mit den Inhalten beschäftigt, die wir hier nur oberflächlich betrachten konnten, und auch noch viel weiter in die Details der Sprache eintaucht.

+ +

Im Allgemeinen empfehle ich auch den Kotlin Playground zum schnellen und unkomplizierten herumprobieren und programmieren im Webbrowser eurer Wahl, wenn ihr Kotlin nicht lokal ausführen wollt.

+ +

Ein anderer spannender Blogeintrag zum Thema Kotlin bei adesso zum direkt Weiterlesen: +Kotlin Multiplattform Mobile +oder direkt an der Quelle: +The Kotlin Blog

+ +

Quellen:

+ +
+
    +
  1. +

    TIOBE zählt die gefundenen Ergebnisse zu Programmiersprachen aus verschiedenen Suchmaschinen. 

    +
  2. +
  3. +

    PYPL nutzt Google Trends für Tutorial-Suchanfragen. 

    +
  4. +
+
+ +
+
+
+]]>
+
+
From 42cc27598a206c6b7721b5284e02ff1dd446a2ac Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 23 Aug 2021 17:16:33 +0200 Subject: [PATCH 20/78] add validate-blogpost workflow --- .github/workflows/validate-blogpost.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/validate-blogpost.yml diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml new file mode 100644 index 000000000..8be83ba27 --- /dev/null +++ b/.github/workflows/validate-blogpost.yml @@ -0,0 +1,24 @@ +#Run blogpost-checker in a Docker container to validate the new blogpost +name: convert-blogpost-to-xml + +on: + pull_request: + branches: + - master + +jobs: + pull-and-run-blogpost-checker-image: + # if: github.repository == 'adessoag/devblog' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@master + + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v3.x + + - name: Pull Docker image + run: docker pull jekyll2cms/blogpost-checker:1.0.0 + + - name: Run Docker image + run: docker run --env REPOSITORY_REMOTE_URL='${{ env.GITHUB_REPOSITORY_SLUG }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_REF_SLUG_URL }}' jekyll2cms/blogpost-checker:1.0.0 From 381e7091e2f56ee7d83a8625e6e2d8afef1f7574 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 23 Aug 2021 17:21:42 +0200 Subject: [PATCH 21/78] fix --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 8be83ba27..3ea8bf43d 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -21,4 +21,4 @@ jobs: run: docker pull jekyll2cms/blogpost-checker:1.0.0 - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='${{ env.GITHUB_REPOSITORY_SLUG }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_REF_SLUG_URL }}' jekyll2cms/blogpost-checker:1.0.0 + run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_REF_SLUG_URL }}' jekyll2cms/blogpost-checker:1.0.0 From dee5cc67f9f3a51730f706a9daff02426595f500 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 23 Aug 2021 17:28:01 +0200 Subject: [PATCH 22/78] fix --- .github/workflows/validate-blogpost.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 3ea8bf43d..7cda71297 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -20,5 +20,11 @@ jobs: - name: Pull Docker image run: docker pull jekyll2cms/blogpost-checker:1.0.0 + - name: echo + run: | + echo "Slug variables" + echo "https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}" + echo "${{ env.GITHUB_REF_SLUG_URL }}" + - name: Run Docker image run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_REF_SLUG_URL }}' jekyll2cms/blogpost-checker:1.0.0 From 790af71baf78bda103e1cb89ae5a47b72b75280e Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 23 Aug 2021 17:30:18 +0200 Subject: [PATCH 23/78] fix --- .github/workflows/validate-blogpost.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 7cda71297..72b756d78 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -1,5 +1,5 @@ #Run blogpost-checker in a Docker container to validate the new blogpost -name: convert-blogpost-to-xml +name: validate-blogpost on: pull_request: @@ -14,8 +14,8 @@ jobs: steps: - uses: actions/checkout@master - - name: Inject slug/short variables - uses: rlespinasse/github-slug-action@v3.x +# - name: Inject slug/short variables +# uses: rlespinasse/github-slug-action@v3.x - name: Pull Docker image run: docker pull jekyll2cms/blogpost-checker:1.0.0 From 86af75127fb3e0e827bc75b29799a2e536b65cfc Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 23 Aug 2021 17:34:13 +0200 Subject: [PATCH 24/78] fix --- .github/workflows/validate-blogpost.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 72b756d78..00eb5a106 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -14,8 +14,8 @@ jobs: steps: - uses: actions/checkout@master -# - name: Inject slug/short variables -# uses: rlespinasse/github-slug-action@v3.x + - name: Inject env + uses: rlespinasse/github-slug-action@v3.x - name: Pull Docker image run: docker pull jekyll2cms/blogpost-checker:1.0.0 From c6d343f70022487a130ca8090e2cdf894cd9c665 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 23 Aug 2021 17:35:59 +0200 Subject: [PATCH 25/78] fix --- .github/workflows/validate-blogpost.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 00eb5a106..c06ec6d6f 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -24,7 +24,7 @@ jobs: run: | echo "Slug variables" echo "https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}" - echo "${{ env.GITHUB_REF_SLUG_URL }}" + echo "${{ env.GITHUB_HEAD_REF_SLUG }}" - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_REF_SLUG_URL }}' jekyll2cms/blogpost-checker:1.0.0 + run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' jekyll2cms/blogpost-checker:1.0.0 From af5c4425548ffbceb191423cb7d44b34fc11d872 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 20 Sep 2021 10:19:33 +0200 Subject: [PATCH 26/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index c06ec6d6f..077b91242 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -25,6 +25,12 @@ jobs: echo "Slug variables" echo "https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}" echo "${{ env.GITHUB_HEAD_REF_SLUG }}" + + - name: print context + run: echo "$GITHUB_CONTEXT" + + - name: print env + run: printenv | sort - name: Run Docker image run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' jekyll2cms/blogpost-checker:1.0.0 From cdedf037fc69baa67adfdf88a2aea485c52fc2a0 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 20 Sep 2021 10:42:02 +0200 Subject: [PATCH 27/78] add test post --- _posts/2021-09-20-test-post.md | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 _posts/2021-09-20-test-post.md diff --git a/_posts/2021-09-20-test-post.md b/_posts/2021-09-20-test-post.md new file mode 100644 index 000000000..f52ea579f --- /dev/null +++ b/_posts/2021-09-20-test-post.md @@ -0,0 +1,75 @@ +--- +layout: [post, post-xml] # Pflichtfeld. Nicht ändern! +title: 'Ein Testpost' # Pflichtfeld. Bitte einen Titel für den Blog Post angeben. +date: 2021-09-20 13:00 # Pflichtfeld. Format "YYYY-MM-DD HH:MM". Muss für Veröffentlichung in der Vergangenheit liegen. (Für Preview egal) +modified_date: 2021-09-20 13:00 # Optional. Muss angegeben werden, wenn eine bestehende Datei geändert wird. +author_ids: [jo2] # Pflichtfeld. Es muss in der "authors.yml" einen Eintrag mit diesem Namen geben. +categories: [Softwareentwicklung] # Pflichtfeld. Maximal eine der angegebenen Kategorien verwenden. +tags: [Test] # Bitte auf Großschreibung achten. +--- +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +# Lorem Ipsum +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. +Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. + +Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. + +Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. +Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. +Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. + +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. + +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. +sanctus sea sed takimata ut vero voluptua. +est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. + +Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus. + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. +At vero eos et accusam et justo duo dolores et ea rebum. +Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. +Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. + +Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. + +Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. +Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. +Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo From 7714ddfa7601937c4c9ffee285bcc85eecf40ef7 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 13:54:26 +0200 Subject: [PATCH 28/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 7ed0bcf9f..5b07f7dcb 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -11,8 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master - + - name: find + run: find / -name *.md + - name: Inject env uses: rlespinasse/github-slug-action@v3.x From a4328627253192d0fe206cd8d975a88ed20c9f84 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 15:25:51 +0200 Subject: [PATCH 29/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 5b07f7dcb..9f0be0877 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -11,8 +11,10 @@ jobs: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v2 + - name: find - run: find / -name *.md + run: find / -name _posts/*.md - name: Inject env uses: rlespinasse/github-slug-action@v3.x From f0ac9df62483d5d9cd5213fac1be7bfbc95399a2 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 15:27:49 +0200 Subject: [PATCH 30/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 9f0be0877..f4d9cad84 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - name: find - run: find / -name _posts/*.md + run: find / -name '_posts/*.md' - name: Inject env uses: rlespinasse/github-slug-action@v3.x From 34a7aceecfdede36d2e4fed17e4195fb155be007 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 15:34:42 +0200 Subject: [PATCH 31/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index f4d9cad84..f99d35d2b 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - name: find - run: find / -name '_posts/*.md' + run: find / -name *.md - name: Inject env uses: rlespinasse/github-slug-action@v3.x From deac79e36783b2542e8540b2166d66c7f24e2a19 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 15:58:14 +0200 Subject: [PATCH 32/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index f99d35d2b..90a9cf54a 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - name: find - run: find / -name *.md + run: find -name *.md / - name: Inject env uses: rlespinasse/github-slug-action@v3.x From 701eed183d4622c0a62c87096de62eaf0a4d499d Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 16:03:39 +0200 Subject: [PATCH 33/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 90a9cf54a..f99d35d2b 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - name: find - run: find -name *.md / + run: find / -name *.md - name: Inject env uses: rlespinasse/github-slug-action@v3.x From 585af7b71c8fa67cd5b3f1e5aecaed2e4741965a Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 16:05:38 +0200 Subject: [PATCH 34/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index f99d35d2b..ef51b694f 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - name: find - run: find / -name *.md + run: find / -name '*.md' - name: Inject env uses: rlespinasse/github-slug-action@v3.x From a4341d07e8ddac08932e881263be14b96dda1792 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 16:13:55 +0200 Subject: [PATCH 35/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index ef51b694f..e4ae04cdc 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -11,19 +11,19 @@ jobs: runs-on: ubuntu-latest steps: + - name: print env + run: printenv | sort + - uses: actions/checkout@v2 - name: find - run: find / -name '*.md' + run: find /home/runner/work/devblog -name '*.md' - name: Inject env uses: rlespinasse/github-slug-action@v3.x - name: Pull Docker image run: docker pull jekyll2cms/blogpost-checker:1.0.0 - - - name: print env - run: printenv | sort - name: Run Docker image run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' jekyll2cms/blogpost-checker:1.0.0 From 5ba6a9c52a88b269c9fe897031e40c8ee4e35987 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 16:28:27 +0200 Subject: [PATCH 36/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index e4ae04cdc..ff566740e 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -11,16 +11,19 @@ jobs: runs-on: ubuntu-latest steps: + - name: Inject env + uses: rlespinasse/github-slug-action@v3.x + - name: print env run: printenv | sort - uses: actions/checkout@v2 + + - name: git log + run: cd /home/runner/work/devblog/devblog && git log - name: find run: find /home/runner/work/devblog -name '*.md' - - - name: Inject env - uses: rlespinasse/github-slug-action@v3.x - name: Pull Docker image run: docker pull jekyll2cms/blogpost-checker:1.0.0 From 8ff11b1c4ecf40f5935d272802c65fc66b87852b Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 16:46:49 +0200 Subject: [PATCH 37/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index ff566740e..1f8c03e2f 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -16,12 +16,18 @@ jobs: - name: print env run: printenv | sort - - - uses: actions/checkout@v2 - + - name: git log - run: cd /home/runner/work/devblog/devblog && git log + run: cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' >> $PR_COMMIT + - name: Test + run: echo $PR_COMMIT + + - uses: actions/checkout@v2 + with: + repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} + ref: ${{ PR_COMMIT }} + - name: find run: find /home/runner/work/devblog -name '*.md' From eca9e29f9ca86084896fc31dad5a70e5e434d93f Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 16:57:51 +0200 Subject: [PATCH 38/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 1f8c03e2f..1c85f5037 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v2 with: repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} - ref: ${{ PR_COMMIT }} + ref: ${{ env.PR_COMMIT }} - name: find run: find /home/runner/work/devblog -name '*.md' From cee25e3ecbdfcd55ecce9195b7ecdf06569497ac Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:02:43 +0200 Subject: [PATCH 39/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 1c85f5037..59f828160 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -16,6 +16,11 @@ jobs: - name: print env run: printenv | sort + + - uses: actions/checkout@v2 + + - name: find + run: find /home/runner/work -name '*.md' - name: git log run: cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' >> $PR_COMMIT From 710891135e38b27605b8c12ecf2909d667be2d19 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:11:46 +0200 Subject: [PATCH 40/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 59f828160..8055a3269 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -23,10 +23,11 @@ jobs: run: find /home/runner/work -name '*.md' - name: git log - run: cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' >> $PR_COMMIT + run: cd /home/runner/work/devblog/devblog && echo "##[set-output name=branch;]$(echo git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/')" + id: current_commit - name: Test - run: echo $PR_COMMIT + run: echo steps.current_commit.outputs.commit - uses: actions/checkout@v2 with: From 2acf5b9d4c2932397b72884e5b30a7cea9ef1623 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:18:23 +0200 Subject: [PATCH 41/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 8055a3269..13f61e263 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -23,16 +23,16 @@ jobs: run: find /home/runner/work -name '*.md' - name: git log - run: cd /home/runner/work/devblog/devblog && echo "##[set-output name=branch;]$(echo git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/')" + run: cd /home/runner/work/devblog/devblog && echo "##[set-output name=commit;]$(echo git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/')" id: current_commit - name: Test - run: echo steps.current_commit.outputs.commit + run: echo ${{ steps.current_commit.outputs.commit }} - uses: actions/checkout@v2 with: repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} - ref: ${{ env.PR_COMMIT }} + ref: ${{ steps.current_commit.outputs.commit }} - name: find run: find /home/runner/work/devblog -name '*.md' From 1aed258e10ab1d42cebd0e0a292674a36c401743 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:29:21 +0200 Subject: [PATCH 42/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 13f61e263..c808c73b0 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -13,26 +13,29 @@ jobs: steps: - name: Inject env uses: rlespinasse/github-slug-action@v3.x - - - name: print env - run: printenv | sort - + - uses: actions/checkout@v2 - name: find run: find /home/runner/work -name '*.md' - name: git log - run: cd /home/runner/work/devblog/devblog && echo "##[set-output name=commit;]$(echo git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/')" + run: | + echo 'CURRENT_COMMIT<> $GITHUB_ENV + cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV id: current_commit + + - name: print env + run: printenv | sort - name: Test - run: echo ${{ steps.current_commit.outputs.commit }} + run: echo ${{ env.CURRENT_COMMIT }} - uses: actions/checkout@v2 with: repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} - ref: ${{ steps.current_commit.outputs.commit }} + ref: ${{ env.CURRENT_COMMIT }} - name: find run: find /home/runner/work/devblog -name '*.md' From 1c9329d89ccd17fc5b63e2433b0f457c2c206f22 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:35:31 +0200 Subject: [PATCH 43/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index c808c73b0..70cf9e7e5 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -21,10 +21,9 @@ jobs: - name: git log run: | - echo 'CURRENT_COMMIT<> $GITHUB_ENV - cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' >> $GITHUB_ENV - echo 'EOF' >> $GITHUB_ENV - id: current_commit + export CURRENT_COMMIT=cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' >> $GITHUB_ENV + echo "::set-env name=CURRENT_COMMIT::$CURRENT_COMMIT" + echo $CURRENT_COMMIT - name: print env run: printenv | sort From 08ec38e46cba93aa132f5a348e90e1a66d39fa18 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:36:46 +0200 Subject: [PATCH 44/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 70cf9e7e5..0b05a2f1f 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -21,7 +21,7 @@ jobs: - name: git log run: | - export CURRENT_COMMIT=cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' >> $GITHUB_ENV + export CURRENT_COMMIT=cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' echo "::set-env name=CURRENT_COMMIT::$CURRENT_COMMIT" echo $CURRENT_COMMIT From 8ff4a31aa26d51172379be189be1d357144684ef Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:46:16 +0200 Subject: [PATCH 45/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 0b05a2f1f..182573555 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -21,7 +21,9 @@ jobs: - name: git log run: | - export CURRENT_COMMIT=cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/' + CURRENT_COMMIT=`cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/'` + echo $CURRENT_COMMIT + export $CURRENT_COMMIT echo "::set-env name=CURRENT_COMMIT::$CURRENT_COMMIT" echo $CURRENT_COMMIT From 986ce0f28643bc262c9d5e5cffbc9c0e67d0200a Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 30 Sep 2021 17:50:12 +0200 Subject: [PATCH 46/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 182573555..ef1fac431 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -21,7 +21,9 @@ jobs: - name: git log run: | - CURRENT_COMMIT=`cd /home/runner/work/devblog/devblog && git log | sed -e 's/\"Merge\s\(.*\)into\(.*\)/\1/'` + LOG_MESSAGE=`cd /home/runner/work/devblog/devblog && git log` + echo $LOG_MESSAGE + CURRENT_COMMIT=`$LOG_MESSAGE | sed -e 's/\(.*\)00\sMerge\s\(.*\)into\(.*\)/\1/'` echo $CURRENT_COMMIT export $CURRENT_COMMIT echo "::set-env name=CURRENT_COMMIT::$CURRENT_COMMIT" From a5468d728c9d763609d2fee19d486a7aeef0cb70 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:16:29 +0200 Subject: [PATCH 47/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index ef1fac431..462976d7b 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -23,7 +23,7 @@ jobs: run: | LOG_MESSAGE=`cd /home/runner/work/devblog/devblog && git log` echo $LOG_MESSAGE - CURRENT_COMMIT=`$LOG_MESSAGE | sed -e 's/\(.*\)00\sMerge\s\(.*\)into\(.*\)/\1/'` + CURRENT_COMMIT=`$LOG_MESSAGE | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` echo $CURRENT_COMMIT export $CURRENT_COMMIT echo "::set-env name=CURRENT_COMMIT::$CURRENT_COMMIT" From 02136c6b3a99f767410efa29d0655cc2af882f3d Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:18:06 +0200 Subject: [PATCH 48/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 462976d7b..f21bc3fd2 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -22,7 +22,6 @@ jobs: - name: git log run: | LOG_MESSAGE=`cd /home/runner/work/devblog/devblog && git log` - echo $LOG_MESSAGE CURRENT_COMMIT=`$LOG_MESSAGE | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` echo $CURRENT_COMMIT export $CURRENT_COMMIT From 76815847754e4d337c9df7784de0108f42f77d71 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:20:57 +0200 Subject: [PATCH 49/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index f21bc3fd2..fc6c236c3 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -15,24 +15,24 @@ jobs: uses: rlespinasse/github-slug-action@v3.x - uses: actions/checkout@v2 - - - name: find - run: find /home/runner/work -name '*.md' - + - name: git log run: | LOG_MESSAGE=`cd /home/runner/work/devblog/devblog && git log` + echo "Test 1" + echo "$LOG_MESSAGE" CURRENT_COMMIT=`$LOG_MESSAGE | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` - echo $CURRENT_COMMIT + echo "Test 2" + echo "$CURRENT_COMMIT" export $CURRENT_COMMIT + echo "Test 3" echo "::set-env name=CURRENT_COMMIT::$CURRENT_COMMIT" + echo "Test 4" echo $CURRENT_COMMIT + echo "Test 5" - - name: print env - run: printenv | sort - - name: Test - run: echo ${{ env.CURRENT_COMMIT }} + run: echo "${{ env.CURRENT_COMMIT }}" - uses: actions/checkout@v2 with: From 9e2e73c10ecc71d728b0ca7ef5a3080944ef766d Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:27:00 +0200 Subject: [PATCH 50/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index fc6c236c3..282f92a06 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -18,10 +18,7 @@ jobs: - name: git log run: | - LOG_MESSAGE=`cd /home/runner/work/devblog/devblog && git log` - echo "Test 1" - echo "$LOG_MESSAGE" - CURRENT_COMMIT=`$LOG_MESSAGE | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` + CURRENT_COMMIT=`cd /home/runner/work/devblog/devblog && git log | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` echo "Test 2" echo "$CURRENT_COMMIT" export $CURRENT_COMMIT From 3d7029c1b2d854a60eb5847e5f09232e0a077624 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:34:58 +0200 Subject: [PATCH 51/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 282f92a06..379a6a829 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -18,15 +18,16 @@ jobs: - name: git log run: | - CURRENT_COMMIT=`cd /home/runner/work/devblog/devblog && git log | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` + MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline + echo "Test 0" + echo "$MESSAGE" + COMMIT=`$MESSAGE | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` + echo "Test 1" + echo "$COMMIT" + export $COMMIT echo "Test 2" - echo "$CURRENT_COMMIT" - export $CURRENT_COMMIT + echo "::set-env name=CURRENT_COMMIT::$COMMIT" echo "Test 3" - echo "::set-env name=CURRENT_COMMIT::$CURRENT_COMMIT" - echo "Test 4" - echo $CURRENT_COMMIT - echo "Test 5" - name: Test run: echo "${{ env.CURRENT_COMMIT }}" From 0cd79d1f36256b6b73725dc1836c0f4ee94bfcb5 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:38:06 +0200 Subject: [PATCH 52/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 379a6a829..51b58e8a6 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -18,7 +18,7 @@ jobs: - name: git log run: | - MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline + MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` echo "Test 0" echo "$MESSAGE" COMMIT=`$MESSAGE | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` From cf73089103dc50a1872e9432f9c677e93ea2f45c Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:43:30 +0200 Subject: [PATCH 53/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 51b58e8a6..04d774472 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -21,10 +21,11 @@ jobs: MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` echo "Test 0" echo "$MESSAGE" - COMMIT=`$MESSAGE | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` + echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/' + COMMIT=`"$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` echo "Test 1" echo "$COMMIT" - export $COMMIT + export "$COMMIT" echo "Test 2" echo "::set-env name=CURRENT_COMMIT::$COMMIT" echo "Test 3" From 0bcd774ec5114e9270442b5f31aedd94ae3ba377 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:45:11 +0200 Subject: [PATCH 54/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 04d774472..01806739c 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -22,7 +22,7 @@ jobs: echo "Test 0" echo "$MESSAGE" echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/' - COMMIT=`"$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` + COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` echo "Test 1" echo "$COMMIT" export "$COMMIT" From 463ffcb6c94f8df87e7ef9bf28828b538ba52214 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:49:39 +0200 Subject: [PATCH 55/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 01806739c..37bcbbe96 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -18,11 +18,11 @@ jobs: - name: git log run: | - MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` + MESSAGE=cd /home/runner/work/devblog/devblog && git log --pretty=oneline echo "Test 0" echo "$MESSAGE" - echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/' - COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\)into\(.*\)/\2/'` + echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/' + COMMIT=echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/' echo "Test 1" echo "$COMMIT" export "$COMMIT" From c74eb73bd8b843f4d2910c8d10893152389217af Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:52:00 +0200 Subject: [PATCH 56/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 37bcbbe96..5717d7ea7 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -18,7 +18,7 @@ jobs: - name: git log run: | - MESSAGE=cd /home/runner/work/devblog/devblog && git log --pretty=oneline + MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` echo "Test 0" echo "$MESSAGE" echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/' From ea059eb837cfe94918e56e7bf5e0cd326aaba7c4 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 15:55:47 +0200 Subject: [PATCH 57/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 5717d7ea7..f7845edd9 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -22,7 +22,7 @@ jobs: echo "Test 0" echo "$MESSAGE" echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/' - COMMIT=echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/' + COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` echo "Test 1" echo "$COMMIT" export "$COMMIT" From 8df31b11bf5f9ea8decf12f4fce1614e50b2f151 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 16:03:09 +0200 Subject: [PATCH 58/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index f7845edd9..44640747a 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -19,13 +19,10 @@ jobs: - name: git log run: | MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` - echo "Test 0" - echo "$MESSAGE" - echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/' COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` echo "Test 1" echo "$COMMIT" - export "$COMMIT" + export CURRENT_COMMIT="$COMMIT" echo "Test 2" echo "::set-env name=CURRENT_COMMIT::$COMMIT" echo "Test 3" From c2197524eade8954ad7756110081336591411706 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 16:07:17 +0200 Subject: [PATCH 59/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 44640747a..61d70e875 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -20,12 +20,10 @@ jobs: run: | MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` - echo "Test 1" - echo "$COMMIT" export CURRENT_COMMIT="$COMMIT" - echo "Test 2" echo "::set-env name=CURRENT_COMMIT::$COMMIT" - echo "Test 3" + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' - name: Test run: echo "${{ env.CURRENT_COMMIT }}" From c1e7a2e51dece291803a17c8acd6e371d653fe8f Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 17:39:34 +0200 Subject: [PATCH 60/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 61d70e875..fd2c2db75 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -37,7 +37,7 @@ jobs: run: find /home/runner/work/devblog -name '*.md' - name: Pull Docker image - run: docker pull jekyll2cms/blogpost-checker:1.0.0 + run: docker pull jekyll2cms/blogpost-checker:1.0.1 - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' jekyll2cms/blogpost-checker:1.0.0 + run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='/home/runner/work/devblog/devblog' jekyll2cms/blogpost-checker:1.0.0 From fa88a77effe3e9cf62a85aff5176928789eeef61 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 17:40:30 +0200 Subject: [PATCH 61/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index fd2c2db75..0635f9e24 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -40,4 +40,4 @@ jobs: run: docker pull jekyll2cms/blogpost-checker:1.0.1 - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='/home/runner/work/devblog/devblog' jekyll2cms/blogpost-checker:1.0.0 + run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='/home/runner/work/devblog/devblog' --env SPRING_PROFILES_ACTIVE=remote jekyll2cms/blogpost-checker:1.0.0 From 249b80c9242f66e018e8f847a51b955baa71139a Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 17:56:25 +0200 Subject: [PATCH 62/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 0635f9e24..2ed99a8f1 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -40,4 +40,4 @@ jobs: run: docker pull jekyll2cms/blogpost-checker:1.0.1 - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='/home/runner/work/devblog/devblog' --env SPRING_PROFILES_ACTIVE=remote jekyll2cms/blogpost-checker:1.0.0 + run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='/home/runner/work/devblog/devblog' --env SPRING_PROFILES_ACTIVE=remote jekyll2cms/blogpost-checker:1.0.1 From ad0109452cfe735cea0aac9327e319cecf99baac Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 18:05:49 +0200 Subject: [PATCH 63/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 2ed99a8f1..f07cfff4a 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -40,4 +40,4 @@ jobs: run: docker pull jekyll2cms/blogpost-checker:1.0.1 - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='/home/runner/work/devblog/devblog' --env SPRING_PROFILES_ACTIVE=remote jekyll2cms/blogpost-checker:1.0.1 + run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='repo' --env SPRING_PROFILES_ACTIVE=remote --mount src=/home/runner/work/devblog/devblog,target=/repo jekyll2cms/blogpost-checker:1.0.1 From b6983b887ff737cfeb00fe1dd311968183477d2d Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 18:11:39 +0200 Subject: [PATCH 64/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index f07cfff4a..cfaa3630e 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -24,20 +24,11 @@ jobs: echo "::set-env name=CURRENT_COMMIT::$COMMIT" env: ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' - - - name: Test - run: echo "${{ env.CURRENT_COMMIT }}" - + - uses: actions/checkout@v2 with: repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} ref: ${{ env.CURRENT_COMMIT }} - - name: find - run: find /home/runner/work/devblog -name '*.md' - - - name: Pull Docker image - run: docker pull jekyll2cms/blogpost-checker:1.0.1 - - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH='repo' --env SPRING_PROFILES_ACTIVE=remote --mount src=/home/runner/work/devblog/devblog,target=/repo jekyll2cms/blogpost-checker:1.0.1 + run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH=repo --env SPRING_PROFILES_ACTIVE=remote -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.1 From c06e2c36f7758b232fe243e4f43d16147bbeb8d7 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 4 Oct 2021 19:47:14 +0200 Subject: [PATCH 65/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index cfaa3630e..ef82c4952 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -19,9 +19,12 @@ jobs: - name: git log run: | MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` - COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` - export CURRENT_COMMIT="$COMMIT" - echo "::set-env name=CURRENT_COMMIT::$COMMIT" + HEAD_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\3/'` + HEAD_BASE=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` + export HEAD_COMMIT="$HEAD_COMMIT" + export BASE_COMMIT="$BASE_COMMIT" + echo "::set-env name=HEAD_COMMIT::$HEAD_COMMIT" + echo "::set-env name=BASE_COMMIT::$BASE_COMMIT" env: ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' @@ -31,4 +34,4 @@ jobs: ref: ${{ env.CURRENT_COMMIT }} - name: Run Docker image - run: docker run --env REPOSITORY_REMOTE_URL='https://github.com/${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }}' --env REPOSITORY_BRANCH_NAME='${{ env.GITHUB_HEAD_REF_SLUG }}' --env LOCAL_REPO_PATH=repo --env SPRING_PROFILES_ACTIVE=remote -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.1 + run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.1 From ebd0b7222688adfbfb081a3c0a290310e7bc21d4 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 1 Nov 2021 18:09:18 +0100 Subject: [PATCH 66/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index ef82c4952..433d321d5 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -34,4 +34,4 @@ jobs: ref: ${{ env.CURRENT_COMMIT }} - name: Run Docker image - run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.1 + run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.2 From e64b8863ec10c6531cc1a570c115061bee661669 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 1 Nov 2021 18:13:08 +0100 Subject: [PATCH 67/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 433d321d5..d4825d849 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -19,6 +19,7 @@ jobs: - name: git log run: | MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` + echo "$MESSAGE" HEAD_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\3/'` HEAD_BASE=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` export HEAD_COMMIT="$HEAD_COMMIT" From c0d91b79e0d6e0e7bda1995fc7b60c18d0a22ba7 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 1 Nov 2021 18:16:03 +0100 Subject: [PATCH 68/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index d4825d849..b5b562008 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -21,7 +21,7 @@ jobs: MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` echo "$MESSAGE" HEAD_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\3/'` - HEAD_BASE=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` + BASE_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` export HEAD_COMMIT="$HEAD_COMMIT" export BASE_COMMIT="$BASE_COMMIT" echo "::set-env name=HEAD_COMMIT::$HEAD_COMMIT" From ead420a5ae7442b03dbfe1d181020f2d56b21e19 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Mon, 1 Nov 2021 18:19:04 +0100 Subject: [PATCH 69/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index b5b562008..cdafc7f92 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -20,8 +20,8 @@ jobs: run: | MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` echo "$MESSAGE" - HEAD_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\3/'` - BASE_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into\(.*\)/\2/'` + HEAD_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into \(.*\)/\3/'` + BASE_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into \(.*\)/\2/'` export HEAD_COMMIT="$HEAD_COMMIT" export BASE_COMMIT="$BASE_COMMIT" echo "::set-env name=HEAD_COMMIT::$HEAD_COMMIT" From 04033f5e859553737955b4581843cd588b3d9bc5 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 23 Dec 2021 13:08:08 +0100 Subject: [PATCH 70/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index cdafc7f92..b17aa03e2 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -35,4 +35,4 @@ jobs: ref: ${{ env.CURRENT_COMMIT }} - name: Run Docker image - run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.2 + run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.3 From 96460f21741b0a0b5d52676696fec89160853522 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 23 Dec 2021 13:30:59 +0100 Subject: [PATCH 71/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index b17aa03e2..91de073a1 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -35,4 +35,4 @@ jobs: ref: ${{ env.CURRENT_COMMIT }} - name: Run Docker image - run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.3 + run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.4 From 63d16a477e13baa965c8b2e9f3c002e2d03f9dfe Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 23 Dec 2021 13:36:12 +0100 Subject: [PATCH 72/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 91de073a1..814fa883e 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -32,7 +32,7 @@ jobs: - uses: actions/checkout@v2 with: repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} - ref: ${{ env.CURRENT_COMMIT }} + ref: ${{ env.HEAD_COMMIT }} - name: Run Docker image run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.4 From 4990f85cca8ecfc53dfd0b7c4aff4c160723b051 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 23 Dec 2021 13:41:58 +0100 Subject: [PATCH 73/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 814fa883e..c4f3cfecf 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -20,8 +20,8 @@ jobs: run: | MESSAGE=`cd /home/runner/work/devblog/devblog && git log --pretty=oneline` echo "$MESSAGE" - HEAD_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into \(.*\)/\3/'` - BASE_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into \(.*\)/\2/'` + HEAD_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into \(.*\)/\2/'` + BASE_COMMIT=`echo "$MESSAGE" | sed -e 's/\(.*\)Merge\s\(.*\) into \(.*\)/\3/'` export HEAD_COMMIT="$HEAD_COMMIT" export BASE_COMMIT="$BASE_COMMIT" echo "::set-env name=HEAD_COMMIT::$HEAD_COMMIT" From 5266fee27b4bf1329349368a29325adf40177e3f Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 23 Dec 2021 13:52:24 +0100 Subject: [PATCH 74/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index c4f3cfecf..f180327b1 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -33,6 +33,12 @@ jobs: with: repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} ref: ${{ env.HEAD_COMMIT }} + + - name: check repo 1 + run: find / -name 2021-08-19-functional-kotlin-eine-einführung.md + + - name: check repo 2 + run: find / -name 2021-08-23-functional-kotlin-eine-einführung.md - name: Run Docker image run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.4 From 8648891331b2364929b9d14835cc9eb631e074e5 Mon Sep 17 00:00:00 2001 From: johannesteklote Date: Thu, 23 Dec 2021 13:59:46 +0100 Subject: [PATCH 75/78] Update validate-blogpost.yml --- .github/workflows/validate-blogpost.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index f180327b1..e08670e9d 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -33,12 +33,9 @@ jobs: with: repository: ${{ env.GITHUB_REPOSITORY_OWNER_PART }}/${{ env.GITHUB_REPOSITORY_NAME_PART }} ref: ${{ env.HEAD_COMMIT }} - - - name: check repo 1 - run: find / -name 2021-08-19-functional-kotlin-eine-einführung.md - + - name: check repo 2 - run: find / -name 2021-08-23-functional-kotlin-eine-einführung.md + run: find /home/runner/work/ -name 2021-08-23-functional-kotlin-eine-einführung.md - name: Run Docker image run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.4 From 163cf332ffc7b04828ce4ff3acfb001151902993 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 17 Feb 2022 16:10:02 +0100 Subject: [PATCH 76/78] merge --- .github/workflows/validate-blogpost.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/validate-blogpost.yml b/.github/workflows/validate-blogpost.yml index 4457c401b..dae5f008b 100644 --- a/.github/workflows/validate-blogpost.yml +++ b/.github/workflows/validate-blogpost.yml @@ -8,10 +8,6 @@ on: jobs: pull-and-run-blogpost-checker-image: - permissions: - issues: write - pull-requests: write - runs-on: ubuntu-latest steps: @@ -44,21 +40,6 @@ jobs: echo github.event.pull_request.number = ${{ github.event.pull_request.number }} echo github.event.issue.number = ${{ github.event.issue.number }} - - name: Create comment using REST API - run: | - curl --request POST \ - --url https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.number }}/comments \ - --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \ - --header 'content-type: application/json' \ - --header 'accept: application/vnd.github.v3+json' - --data '{ - "body": "This is a test to create an issue comment via API." - }' \ - --fail - - - name: check repo 2 - run: find /home/runner/work/ -name 2021-08-23-functional-kotlin-eine-einführung.md - - name: Run Docker image run: docker run --env BASE_COMMIT='${{ env.BASE_COMMIT }}' --env HEAD_COMMIT='${{ env.HEAD_COMMIT }}' --env LOCAL_REPO_PATH=repo --env PR_NUMBER='${{ github.event.number }}' --env TOKEN=${{ secrets.GITHUB_TOKEN }} -v /home/runner/work/devblog/devblog:/repo jekyll2cms/blogpost-checker:1.0.12 From aef0e3ec25aa042471d2633f5a2609bbd5cb9ad0 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Thu, 17 Feb 2022 17:52:49 +0100 Subject: [PATCH 77/78] squash --- _posts/2021-06-24-example.md | 165 -------- ...nctional-kotlin-eine-einf\303\274hrung.md" | 371 ++++++++++++++++++ _posts/2021-09-20-test-post.md | 75 ---- 3 files changed, 371 insertions(+), 240 deletions(-) delete mode 100644 _posts/2021-06-24-example.md create mode 100644 "_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" delete mode 100644 _posts/2021-09-20-test-post.md diff --git a/_posts/2021-06-24-example.md b/_posts/2021-06-24-example.md deleted file mode 100644 index 901179e4e..000000000 --- a/_posts/2021-06-24-example.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -layout: [post, post-xml] -title: "Testartikel" -date: 2021-06-24 16:00 -modified_date: 2021-06-24 16:00 -author: DanielKraft -author_ids: [DanielKraft, jo2] -categories: [Softwareentwicklung] -tags: [Kong, SOAP, REST, Lua] ---- - -Welche Möglichkeiten haben wir, wenn neben einer REST-API auch eine SOAP-Schnittstelle zur Verfügung stehen soll? -In diesem Artikel wird eine Methode vorgestellt, wie man diese Anforderung mit Hilfe von Kong umsetzen kann. - -# Motivation -Wie bereist beschrieben, kann es manchmal gewollt sein, dass eine Schnittstelle über REST und SOAP erreichbar ist. -Hier stellt sich nun die Frage wie man diese Anforderung realisiert. - -Eine intuitive Herangehensweise wäre es, für den Service die zwei Schnittstellen getrennt zu implementieren. -Diese Lösung hat allerdings den Nachteil, dass die Schnittstellen sich durch die getrennte Implementierung unterschiedlich verhalten könnten. -Außerdem müssen bei einer Änderung des Service beide Schnittstellen verändert werden, womit zusätzlicher Arbeitsaufwand verbunden wäre. - -Um diese Probleme zu vermeiden, könnten wir für den Service nur eine Schnittstelle implementieren, zum Beispiel eine REST-API, da diese heutzutage häufig verwendet wird. -Die SOAP-Schnittstelle hingegen könnten wir anschließend aus der REST-API generieren. - -# Vorstellung der Architektur -Für die Realisierung beider Schnittstellen wird ein [Kong API Gateway](https://konghq.com/kong/) mit dem Kong Plugin [soap2rest](https://github.com/adessoAG/kong-plugin-soap2rest) sowie ein REST-Service benötigt. - -![Architektur Skizze](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Architektur.png) - -Die Abbildung zeigt, wie die einzelnen Komponenten miteinander verknüpft sind. -Das Kong API Gateway verwaltet den Zugriff auf den REST-Service. -Für den Fall, dass wir eine Anfrage über die REST-Schnittstelle stellen, wird diese Anfrage an den Service weitergeleitet und bearbeitet. - -Für die Verarbeitung von SOAP-Anfragen wird das Kong Plugin soap2rest verwendet. -Das Plugin benötigt zur Konfiguration zwei Dateien. -Damit das Plugin die SOAP-Anfragen richtig verarbeiten kann, benötigt es die WSDL der SOAP-Schnittstelle. -Und um die Konvertierung von SOAP zu REST Anfragen korrekt durchzuführen, wird zusätzlich die OpenAPI-Spezifikation der REST-API benötigt. - -# Funktionsablauf des Plugins -![Funktionsablauf des Plugins](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Ablauf.png) - -Diese Abbildung zeigt den Fall, dass eine Anfrage über die SOAP-Schnittstelle gestellt wird. -Sobald Kong eine Anfrage über die Route der SOAP-Schnittstelle registriert, wird das Plugin soap2rest ausgeführt. -Das Plugin konvertiert die Anfrage in eine gültige REST-Anfrage und sendet diese an den REST-Service. -Nachdem der REST-Service geantwortet hat, wird die Antwort in eine gültige SOAP-Antwort übersetzt und zurückgegeben. - -Anhand des folgenden Beispiels lässt sich der Ablauf näher verdeutlichen. -Angenommen, folgende Anfrage wird an die SOAP-Schnittstelle gestellt. - -```xml - - - - - 1 - - - -``` - -Aus dieser Anfrage lassen sich verschiedene Informationen ableiten. -Zum einen wird mit dieser Anfrage die SOAP-Action `GetPetByPetid` ausgeführt. -Zusätzlich beinhaltet die Anfrage den Parameter `petId` mit dem Wert `1`. -Anhand dieser Informationen kann die Anfrage der passenden REST Anfrage zugeordnet werden. -In diesem Fall entspricht die Anfrage dem Pfad `/pet/1`. - -Nachdem das Plugin die generierte Anfrage an die REST-API gestellt hat, bekommt es folgende Antwort: - -```json -{ - "id": 1, - "name": "doggie", - "photoUrls": [], - "tags": [], - "status": "available" -} -``` - -Anschließend wird diese Antwort vom Plugin in gültiges XML umgewandelt und in eine SOAP-Antwort eingesetzt, welche anschließend zurückgegeben wird. - -```xml - - - - - - 1 - doggie - - - available - - - - -``` - -# Besonderheiten des Kong Plugins soap2rest -## Analyse der Schnittstellen-Spezifikationen -Die Analyse der WSDL und der OpenAPI ist ein wichtiger Bestandteil des Plugins. -Sie wird nur einmal vor der ersten Anfrage an die SOAP-Schnittstelle ausgeführt, um die Schnittstelle zu konfigurieren. -Dadurch verzögert sich die Antwort der ersten Anfrage im Durchschnitt um 200 Millisekunden. -Anschließend wird diese Konfiguration für die Verarbeitung aller folgenden Anfragen verwendet. - -Bei der Analyse der WSDL werden wichtige Merkmale der SOAP-Schnittstelle ausgelesen. -Dazu gehören zum Beispiel das Auslesen der verschiedenen Operationen und ihrer zugehörigen Rückgabetypen und Faults. -Es wird besonders die Struktur der Rückgabetypen betrachtet, damit das Plugin später gültige SOAP-Antworten generieren kann. - -Nachdem die WSDL analysiert wurde, wird die Konfiguration des Plugins mit der OpenAPI-Spezifikation der REST-API vervollständigt. -Dabei werden den SOAP-Operationen die passenden Pfade der REST-API automatisiert zugeordnet. -Außerdem werden jeder Operation die passenden Content-Types zugeordnet, damit die HTTP-Header bei der Weiterleitung der Anfragen an die REST-API korrekt gesetzt werden können. - -## Request und Response Konvertierung -Bei der Konvertierung von eingehenden SOAP-Anfragen, werden diese in den meisten Fällen direkt von XML in JSON überführt. -Manchmal müssen davor aber noch andere Verarbeitungsschritte durchgeführt werden. -Zum Beispiel werden sämtliche SOAP-Header in HTTP-Header überführt. -Außerdem werden Dateiuploads in Multipart Bodys überführt und den Dateien wird mit Hilfe einer Mime Type Analyse der richtige Content-Type zugeordnet. - -Auch bei der Konvertierung der REST-Antworten werden verschiedene Zwischenschritte benötigt. -Wenn die REST-API nicht den Statuscode 200 zurückgibt, wird die Antwort in ein gültiges SOAP-Fault umgewandelt. - -Bei der Umwandlung der Antwort in XML wird besonders darauf geachtet, dass die Reihenfolge der Attribute des Rückgabetyps mit der Reihenfolge in der WSDL übereinstimmen. -Dafür wird die automatisch generierte Konfiguration des Plugins verwendet. - -# Auswirkungen auf die Verfügbarkeit -Damit der Einsatz des Plugins sich lohnt, sollte die Verfügbarkeit der Schnittstelle nicht unter dem Einsatz des Plugins leiden. -Um die Auswirkungen des Plugins auf die Verfügbarkeit der Schnittstelle zu testen, wurde ein Performance- und ein Lasttest vorgenommen. - -## Durchführung eines Performancetests -Der Performancetest besteht aus vier verschiedenen Anfragen, welche jeweils 10-mal wiederholt wurden. -Zwei der vier Anfragen liefern nur einen HTTP Status Code von 200 und 300 zurück. -Die dritte Anfrage sendet mit einem HTTP POST ein kleines JSON Objekt an die Schnittstelle. -Und die vierte Anfrage versucht die Grenzen der Schnittstelle auszuloten, indem eine Datei an die Schnittstelle gesendet wird. - -Die nachfolgende Grafik zeigt links die Ergebnisse des Performancetests auf die REST-API und rechts die Ergebnisse der SOAP-Schnittstelle. - -![Vergleich der Anfragezeiten](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Performancetest.png) - -Im direkten Vergleich fällt auf, dass die Performance nur beim Senden von Dateien leidet. -Die Performance aller andern Anfragen verändert sich nur geringfügig. - -Der Anstieg der Antwortzeit ist darauf zurückzuführen, dass bei SOAP-Anfragen deutlich mehr Daten an die Schnittstelle gesendet werden müssen. - -## Durchführung eines Lasttests -Im Gegensatz zum Performancetest wurden die vier Anfragen 250-mal parallel ausgeführt. -Um ein aussagekräftiges Ergebnis zu erhalten wurde dieser 10-mal wiederholt. - -Die folgende Grafik zeigt die Ergebnisse des Lasttests. - -![Lasttest](/assets/images/posts/Konvertierung-einer-REST-API-zu-einer-SOAP-Schnittstelle-mithilfe-von-Kong/Lasttest.png) - -Auf den ersten Blick fällt auf, dass die SOAP-Schnittstelle bei vielen parallelen Anfragen längere Antwortzeiten aufweist, als die REST-API. -Vor allem das Senden von Dateien führt zu einem deutlichen Anstieg der Antwortzeit. -Der Kommunikationsaufwand in Verbindung mit den vielen gleichzeitigen Anfragen auf die Schnittstelle ist für die langsamere Antwortzeit verantwortlich. - -# Fazit -Zusammenfassend lässt sich sagen, dass die Nutzung dieses Kong Plugins den Vorteil hat, dass nicht beide Schnittstellen implementiert werden müssen. -Ein Nachteil ist die zusätzliche Wartezeit auf die Antwort der Schnittstelle, da sich hinter jeder SOAP-Anfrage eine Anfrage auf die REST-API verbirgt. -Diese Verzögerung kann allerdings vernachlässigt werden, da erst bei vielen parallelen Anfragen ein deutlich längere Wartezeit entsteht. -Im Großen und Ganzen überwiegen die Vorteile des Plugins die Nachteile. diff --git "a/_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" "b/_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" new file mode 100644 index 000000000..246451c8d --- /dev/null +++ "b/_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" @@ -0,0 +1,371 @@ +--- +layout: [post-xml] # Pflichtfeld. Nicht ändern! +title: 'Functional Kotlin - Eine Einführung' # Pflichtfeld. Bitte einen Titel für den Blog Post angeben. +date: 2021-08-23 13:00 # Pflichtfeld. Format "YYYY-MM-DD HH:MM". Muss für Veröffentlichung in der Vergangenheit liegen. (Für Preview egal) +modified_date: 2021-08-23 13:00 # Optional. Muss angegeben werden, wenn eine bestehende Datei geändert wird. +author_ids: [fabianvolkert, jo2] # Pflichtfeld. Es muss in der "authors.yml" einen Eintrag mit diesem Namen geben. +categories: [Softwareentwicklung] # Pflichtfeld. Maximal eine der angegebenen Kategorien verwenden. +tags: [Kotlin, Funktionale Programmierung] # Bitte auf Großschreibung achten. +--- +In diesem Blogeintrag widmen wir uns der Programmiersprache Kotlin. +Wir werfen einen kurzen Blick auf die Ursprünge der Sprache, wie sie aufgebaut ist und mit welchen Designprinzipien im Hinterkopf sie entworfen wurde. +An Beispielen betrachten wir die Best Practices und stellen uns dabei die Frage: Was hat das mit funktionaler Programmierung zu tun? + +# Kotlin + +Vor zehn Jahren (2011) stellte JetBrains erstmals die Open-Source Programmiersprache Kotlin auf dem [JVM Language Summit](https://blog.jetbrains.com/kotlin/2011/07/hello-world-2/) vor -- "Eine Sprache einfach genug für den gewöhnlichen Entwickler und produktiv genug für moderne Anforderungen an Projekte". +Die Sprache setzt auf der Java Virtual Machine (JVM) auf und erschien 2016 in der ersten Release-Version. +Seit 2017 wird sie von Google offiziell zur Entwicklung von Android-Apps unterstützt und ist seit 2019 Googles bevorzugte Sprache für diese Plattform. + +Im [TIOBE-Index](https://www.tiobe.com/tiobe-index/)[^1] rangiert Kotlin aktuell (Juli 2021) auf Platz 38 der beliebtesten Programmiersprachen. +Betrachtet man ausschließlich die JVM-spezifischen Sprachen steht Kotlin dort auf Platz 4 (übertrumpft von #36 Scala, #15 Groovy und #2 Java). + +Im [PYPL-Index](https://pypl.github.io/PYPL.html)[^2] belegt Kotlin den 11. Platz. + +[^1]:TIOBE zählt die gefundenen Ergebnisse zu Programmiersprachen aus verschiedenen Suchmaschinen. +[^2]:PYPL nutzt Google Trends für Tutorial-Suchanfragen. + +Kotlin, eine statisch typisierte Programmiersprache, ist voll interoperabel zu Java-Programmen und -Bibliotheken und kann ohne aufwändige Integration in bereits bestehende Projekte eingepflegt werden. + +## Grundlagen +Jeder Einstieg in eine Programmiersprache fängt gleich an. +Man muss sich an die Syntax gewöhnen. +Folgendes Beispiel zeigt ein kleines, in Kotlin geschriebenes Programm, welches zuerst das Ergebnis einer Instanzmethode und dann das einer statischen Methode ausgibt: +```kotlin +fun main(){ + val mainClassInstance = MainClass("instanceString") + println(mainClassInstance.instanceMethod()) + println(MainClass.staticMethod(3)) +} + +class MainClass(private var member: String){ + companion object{ + fun staticMethod(parameter:Int):Int{ + return parameter*2 + } + } + + public fun instanceMethod():String{ + return "A" + } +} +``` + +Das [`companion object`](https://kotlinlang.org/docs/object-declarations.html#companion-objects) ist, wie der Name es andeutet, ein Begleiterobjekt zu dieser Klasse und verhält sich ähnlich der statischen Initialisierung in Java (auch wenn das Begleiterobjekt noch einiges mehr kann, auf das ich hier nicht eingehen werde). +Anders als in Java werden die Rückgabewerte von Methoden am Ende des Methodenkopfs plaziert und auch für Wertdefinitionen und Parameter wird der jeweilige Typ durch einen ":" getrennt auf die rechte Seite gestellt. +Kotlin unterstützt [Typinferenz](https://kotlinlang.org/spec/type-inference.html), weswegen die Typdefinitionen in den meisten Fällen auch weggelassen werden können. +Was -- anders als bei Java -- hier auch auffällt, ist, dass ich die *Properties* der `MainClass` direkt hinter den Klassennamen in "( )" definieren kann und sie nicht im Codeblock schreiben muss (, aber auch das könnte ich). +Kotlin generiert für die Variablen Getter- und Setter-Methoden und für die Values nur Getter-Methoden. +Auf den Unterschied komme ich im Abschnitt [Immutabilität](#immutabilität) zu sprechen. +Wie das Beispiel oben auch zeigt, habe ich einen primären Konstruktor für die `MainClass`geschrieben, der sich direkt im Header befindet. +Die in den Klammern des Konstruktors angegebenen Properties (hier *member*) entsprechen direkt einer Deklaration dieser als Teil der Klasse. +Auch die Semikolons können wir in den meisten Fällen weglassen. + +## Nullsicherheit +Eine Ärgerlichkeit, mit der wir uns im Entwicklungsalltag häufig auseinandersetzen müssen, ist das Behandeln von Nullpointer-Exceptions, also dem Fehlen von Daten an Stellen, an denen das Programm welche erwartet hat. +Tony Hoare, der Erfinder der Null-Referenz, hielt 2009 einen Vortrag und nannte als Grund für dessen Einführung die Einfachheit, mit der sie zu implementieren gewesen sei. +Er bezeichnet seine Entscheidung inzwischen als "Milliarde-Dollar-Fehler": +([My billion-dollar mistake](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/)) +Kotlin behandelt dieses Problem aus meiner Sicht pragmatisch ([Null-Safety](https://kotlinlang.org/docs/null-safety.html)), indem, wenn nicht anders angegeben, Werte einfach nicht null sein dürfen. +Betrachten wir folgendes kleines Beispiel eines Produkts, für das ein Preis mit Steuer berechnet werden soll. +```kotlin +fun main() { + val product = Product(4.99) + val vat: Double = null + product.getConsumerPrice(vat) +} + +class Product(private val price: Double) { + fun getConsumerPrice(vat: Double): Double { + val tempValue = helperFunction(vat) + return tempValue * this.price + } + ... +} +``` +Was tendenziell in Java und vielen anderen Sprachen funktioniert wird hier vom Compiler mit einer Fehlermeldung quittiert, da der Wert `val vat: Double` als Double mit Wert definiert und null dort nicht erlaubt ist. +So werden wir bei der Entwicklung immer informiert, wenn Daten potentiell undefinierte Zustände annehmen könnten: +`"Kotlin: Null can not be a value of a non-null type Double"` +Manchmal lässt es sich allerdings auch nicht vermeiden oder ist erwünscht, dass ein null Wert übernommen wird; +Das kann zum Beispiel an Schnittstellen der Fall sein, an denen ein Standardwert keinen Sinn ergibt (auch wenn sich hier wieder darüber streiten lässt, ob ein Standardwert wirklich nicht die bessere Entscheidung ist). +Wir können die Werte mit einem `?` markieren, um kenntlich zu machen, dass sie null (*nullable*) sein dürfen: +`val vat: Double? = null` +Hier kommt die Arbeit zum Vorschein, die uns der Compiler durch diese kleine Änderung abnimmt: `product.getConsumerPrice(vat)` wird mit dem `Double?`aufgerufen, aber `getConsumerPrice(vat: Double)` erwartet einen Wert, der nicht null ist. +Auch das erkennt der Compiler und gibt `Type mismatch: inferred type is Double? but Double was expected`zurück. +So sind wir gezwungen, uns um diesen Fall zu kümmern und entweder vorher sicherzustellen, dass `vat` nicht null sein kann, oder einen Nullwert als Eingabeparameter zu erlauben, wodurch sich die Fehlermeldung auf nachfolgende Aufrufe von `vat` verbreitet. + +Ein anderes Beispiel zeigt, wie wir uns beim Programmieren mit Nullwerten in Kotlin viel Boilerplate-Code sparen können. +Dafür schauen wir uns zunächst ein Problem in Java und anschließend eine Lösung in Kotlin an: +```java +class Head { + public Node next; +} +class Node { + public Node next; + String value = null; +} +... +head.next.next.value; +``` +Die Suche von `value` in dem Beispiel kann, wenn einer der Zwischenaufrufe null ist, zu einer `NullpointerException` führen. +Um dieses Problem zu umgehen, müssen wir zwischen den Aufrufen null-Checks einführen. +Um Platz zu sparen schreibe ich die Prüfungen direkt als ternäre Operationen: +```java +Head head = new Head(); +Node nodeA = head.next != null? head.next :null; +Node nodeB = nodeA.next != null? nodeA.next :null; +String value = nodeB != null? nodeB.value: null; +``` +In Kotlin kann bei potentiellen Nullwerten `?` eingesetzt werden, um diese zu erlauben: +```java +class Head(val next: Node?) +class Node(val next: Node?, val value: String) +... +val head = Head(null) // Bei der Initialisierung muss ich den Wert für 'next' direkt angeben und kann ihn nicht unbestimmt lassen +val string = head.next?.next?.value +``` +Dieser Aufruf führt zu keiner `NullpointerException`, sondern weist `string` null zu, da bereits der Aufruf von `head.next?` null zurückgibt. +Der Wert ist dabei implizit vom Typ `String?`, wodurch auch alle folgenden Aufrufe vom Compiler wieder geprüft werden. + +Alternativ kann der Elvis-Opeator `?:` genutzt werden, um in solchen Fällen direkt einen Standardwert zuzuweisen, sodass statt `String?` der Typ `String` inferiert wird. +```Kotlin +val string = head.next?.next?.value?:"default" +``` + +So kann sichergestellt werden, dass Nullwerte innerhalb der Anwendung angemessen behandelt werden können. + +## Immutabilität +In den beiden Beispielen der vorherigenen Sektionen habe ich das `val`- und das `var`-Schlüsselwort zur Definition von Werten genutzt. +`val` wird genutzt um einen zur Laufzeit unveränderlichen Wert zu definieren (anders noch als `const`, welches für unveränderliche, zur Kompilierzeit bekannte, Werte steht). +Es ist vergleichbar mit `final` aus Java. +Auf der anderen Seite steht das `var`-Schlüsselwort mit dem herkömmliche Variablen beschrieben werden können. +Immutabilität hilft während der Entwicklung Nebeneffekte im Code auf ein Minimum zu reduzieren und schafft so Sicherheit vor allem für Parallelität. +Betrachten wir folgendes Beispiel in Java: +```Java +class SideEffect { + public int member = 0; + + public int someCalculation(int input) { + int aux = member + 2; + int result = member + aux + input; + member++; + return result; + } +} +``` +`someCalculation` nutzt die Variable `member` für einige Berechnungen. +In einer synchronen Umgebung ist dies problemlos möglich. +Soll die Methode allerdings parallel ausgeführt werden, kann es zu inkonsistentem Verhalten kommen, da `member` zu verschiedenen Zeitpunkten innerhalb der Ausführung der Methode unterschiedliche Werte annehmen kann. +Besser ist hier eine Lösung, die `someCalculation` weitestgehend unabhängig vom aktuellen Wert von `member`macht. +Denkbar ist: +```Java +public int someCalculation(int input, int memberVal) { + int aux = memberVal + 2; + int result = memberVal + aux + input; + member++; + return result; +} +``` +Durch das Verlagern des für die Berechnung genutzten Wertes ist sichergestellt, dass die Methode, selbst wenn sich `member` zur Laufzeit ändert, innerhalb ihres Ausführungskontextes einen konsistenten Zustand einhält. +An dieser Stelle bediene ich mich zusätzlich an einigen Punkten, auf die man zum Thema Immutabilität im Internet immer wieder trifft: +- Threadsicherheit (Durch Zugriff auf Werte, die sich nicht ändern) +- Keine versteckten Nebeneffekte (Es gibt kein Risiko, dass Methoden unbemerkt Werte an anderen Stellen ändern) +- Sicherheit vor Nullwerten (Wenn ein Wert einmal überprüft wurde, behält er seine Gültigkeit) +- Leichteres Caching (Wenn ein Wert einmal geladen wurde und sich Rahmenbedingungen ändern, ist sichergestellt, dass dieser Wert nach wie vor gültig ist und nicht neu geladen werden muss) +- Bessere Kapselung von Methoden und Klassen (Es ist sichergestellt, dass Methoden und Klassen, die untereinander kommunizieren, sich nicht gegenseitig verändern) +- Einfacher zu Testen (Durch feste Werte und fehlende Nebeneffekte sind die Punkte, die es bei Fehlern zu überprüfen gilt, weniger und einfacher) +- Leichtere Lesbarkeit und Wartbarkeit (Geht einher mit der leichteren Testbarkeit) +- Vorhersagbarkeit (Wenn Werte konkret sind, können zuverlässige Annahmen getroffen werden) + +Diese Auflistung zeigt, dass der Aufwand für Immutabilität im Verältnis zu den Vorteilen in den meisten Fällen gering ausfällt. + +# Funktionale Programmierung +An dieser Stelle macht es Sinn, die funktionalen Programmierung ins Spiel zu bringen. +Was ist funktionale Programmierung und wie kann sie uns bei unserer Arbeit helfen? +Die funktionale Programmierung ist ein Ansatz der Programmierung, die Verarbeitung von Daten nicht anweisungsgetrieben (imperativ, wie z.B. in Java) zu konzipieren, sondern aus einer mathematischen Perspektive heraus -- funktional -- zu betrachten. +Also statt dass wir ein Problem aus der Perspektive betrachten, jeden Schritt einzeln durchzugehen, arbeiten wir mit einer Menge von Daten, auf die Operationen angewandt werden und die mitunter eine neue Menge von Daten erzeugt. +Die funktionale Programmierung ist etwas, was in vielen großen Programmiersprachen immer mehr Einzug hält, auch weil die Rechenleistung heutiger Computer so hoch ist, dass die schlechtere Performance, die durch diesen Ansatz erreicht wird, nicht mehr ins Gewicht fällt. +Theoretische Grundlage der funktionalen Programmierung ist das Lambda-Kalkül, welches in den 30er Jahren von Church und Kleene zur Beschreibung von Funktionen eingeführt wurde. +Ein einfacher Lambda-Ausdruck sieht dabei wie folgt aus und beschreibt hier f(x)=x+2: +``` +λx.x+2 +``` +Lambda-Ausdrücke kennen wir aus der Entwicklung im Java-Kontext hauptsächlich in Form von Lambda-Ausdrücken (ab Java 8 in 2014). +Collections müssen dazu erst in einen *stream* konvertiert, transformiert und dann dann wieder zurück konvertiert werden: +```Java +strings + .stream() + .filter(s -> s.length() == 5) + .collect(Collectors.toList()); +``` +Lambda-Ausdrücke gibt es auch in Kotlin und werden dort viel häufiger verwendet. +Gibt es nur einen Wert im Lambda-Ausdruck der gebunden werden muss, kann der implizite Name *it* benutzt werden, statt dem Laufwert einen konkreten Namen geben zu müssen. +```Kotlin +strings.filter { it.length == 5 } +``` +Auch wenn beide Beispiele hier nur einfache sind, empfinde ich persönlich die Kotlin-seitigen Lösungen häufig intuitiver und kürzer als das bei Java der Fall ist. +Allein der Wegfall der Konvertierungen reduziert den Boilerplate-Code und erleichtert damit die Wartung der Software. + +## map, reduce, filter, ... +Die `filter`-Methode haben wir gerade eben kennengelernt. +Wie der Name beschreibt, kann sie genutzt werden, um Elemente aus einer Menge an Daten herauszufiltern. +Die zwei wichtigen anderen Methoden, die häufig eingesetzt werden, sind die `map`- und die `reduce`-Methode. +`map` iteriert über jedes Element einer Menge von Daten und wendet eine Funktion auf dieses an. +Heraus kommt dabei eine neue Menge von Daten, die möglicherweise geändert wurden. +(Ich sage möglicherweise, weil die identische Abbildung f(x)=x existiert) +```Kotlin +productList.map { product -> product.getConsumerPrice(0.19) } +``` +Obiges Beispiel zeigt, wie eine Liste von Produkten in eine Liste von Preisen konvertiert wird, indem von jedem Produkt-Element der Konsumentenpreis geholt wird. +Die `reduce`-Methode verhält sich ähnlich zur `map`-Methode, mit dem Unterschied, dass das Ergebnis ein einzelnes Element ist. +Auch hier wird auf jedes Element der Menge eine Funktion angewandt. +Das folgende Beispiel zeigt, wie aus unserer Preisliste eine Summe über alle Preise gebildet wird. +`sum` definiert dabei das Akkumulator-Element im ersten Parameter. +`price` ist die Laufvariable (eher Laufwert) für die einzelnen Preise, über die iteriert wird. +```Kotlin +priceList.reduce { sum, price -> sum+price } +``` +Statt uns mit der Iteration beschäftigen zu müssen, erlaubt diese Heransgehensweise uns das eigentliche Problem behandeln zu können. +`map`, `filter` und `reduce` sind Beispiele für sogenannte [Funktionen höherer Ordnung](https://kotlinlang.org/docs/lambdas.html), denn sie nehmen nicht nur einfache Werte als Parameter entgegen, sondern erwarten Funktionen, die sie während ihrer Ausführung aufrufen können. +Ihre Flexibilität im Kern, während sie einen klaren Rahmen für die Verarbeitung von Daten in einer bestimmten Art und Weise schaffen, machen sie zu mächtigen Werkzeugen. + +## Extension Functions + +```Kotlin +inline fun Iterable.reduce( + operation: (acc: S, T) -> S +): S +``` +*Definition der reduce Extensionfunktion mit Generics* + +Zwei Dinge, die an dem obigen Beispiel auffallen, sind der Einsatz von Generics zur Verallgemeinerung der Anwendbarkeit der Funktion; +Und dass es sich hierbei um eine sogenannte [*Extension-Function*](https://kotlinlang.org/docs/extensions.html) handelt, die -- in diesem Fall -- Iterable um eine Methode erweitert. +Extension-Functions können genutzt werden um Klassen zu erweitern, ohne neue Klassen oder Interfaces definieren zu müssen, die von der Grundklasse erben. +Hier gibt es mehr Informationen zu [inline-Funktionen](https://kotlinlang.org/docs/inline-functions.html). + +Hier ist ein Beispiel aus einem Projekt in dem ich gearbeitet habe. +Dort haben wir Extension-Functions häufig genutzt, um vor allem die Lesbarkeit unseres Codes zu erhöhen. +```Kotlin +data class Partner( + val name: String, + ... +) + +fun Partner.toDto(): PartnerDto = PartnerDto( + name, + ... +) +... +partner01.toDto() +``` +Natürlich lässt sich die Konvertierung in ein DTO auch klassisch lösen: +```Kotlin +fun createPartnerDto(partner:Partner):PartnerDto { + return PartnerDto( + partner.name, + ... + ) +} + +createPartnerDto(partner01) +``` +Allerdings erhöht die erste Variante die Lesbarkeit des Codes, wenn es um [Methodenverkettung](https://en.wikipedia.org/wiki/Method_chaining) geht (wie oben zu sehen, gibt es dieses Konzept auch in Java). + +Klassische Funktionen: +```Java +prepareSend(enrichWithData(createFromPartnerDto(partner01), data), destination) +``` +Extension-Functions: +```Kotlin +partner01.toDTO().enrichWithData(data).prepareSend(destination) +``` +Ein anderes Beispiel zeigt, dass wir auch Klassen erweitern können, die wir nicht selber geschrieben haben. +(Das Schlüsselwort `suspend` kann ignoriert werden. +Bei Interesse empfehle ich die Einführung in [Coroutines](https://kotlinlang.org/docs/coroutines-basics.html).) +Hier haben wir String um eine domänenspezifische Funktion erweitert, um zu diesem eine zugehörige Klasse zu finden: +```Kotlin +private suspend fun String.getCategoryByCategoryId(): Category? +... +val category = item.category?.getCategoryByCategoryId() +``` + + +# Funktionales Testen mit Property Based Testing + +![Available automated test technics](/assets/images/posts/functional-kotlin-eine-einführung/available-automated-test-technics.png) + +[Bildquelle](https://medium.com/criteo-engineering/introduction-to-property-based-testing-f5236229d237) + +Nehmen wir das, was wir bis jetzt betrachtet haben, ergeben sich daraus auch neue Möglichkeiten Softwarequalität sicherzustellen. +Die Standardvorgehensweise für das Schreiben von Tests auf unterster Ebene sind die Unit-Tests. +Kleine Blöcke, die die Funktionalität einzelner, isolierter Code-Ausschnitte überprüfen sollen, indem wir feste Vorgabewerte definieren und an die jeweilige Funktion übergeben. +An dieser Stelle tritt das Property based testing aus der funktionalen Programmierung auf den Plan. +Dahinter verbirgt sich die Idee, statt einige feste Werte auf bestimmte Ergebnisse zu überprüfen (und damit Fehlerräume an den Stellen zu lassen, die man nicht testet), gemeinsame Eigenschaften in Gruppen von Eigabeparametern zu finden, die anschließend randomisiert überprüft werden können. +Schauen wir uns für ein besseres Verständnis ein einfaches Beispiel an. +Die folgende Funktion konkateniert zwei Strings miteinander (Man beachte, dass die geschweiften Klammern weggelassen werden können, wenn es sich bei der Funktion um eine einzelne Operation handelt): +```kotlin +public fun concatenate(string1: String, string2: String): String = string1 + string2 +``` +In klassischer Herangehensweise würden wir beim Testen neben den Grenzfällen (leerer String, Nullstring), einen "normalen" Methodenaufruf testen. +Eine andere Art und Weise an den Test heranszugehen ist, sich zu überlegen, welche Eigenschaft die Ergebnisse des Methodenaufrufs gemein haben. +Eigenschaften lassen sich dabei nach folgender Form beschreiben: + +*Für Werte ... gilt, wenn ... zutrifft, dass ... wahr/falsch ist* + +In diesem Fall können wir also sagen: + +*Für alle Strings string1 und string2 gilt, dass die Konkatenation von string1 und string2 mit string1 anfängt und mit string2 endet* + +In [Kotest](https://kotest.io/) könnte der Test dann so aussehen: +```kotlin +class StringConcatTest: StringSpec({ + "Alle konkatenierten Strings starten mit string1 und enden mit string2" { + forAll { string1, string2 -> { + val concat = concatenate(string1, string2) + return concat.startsWith(string1) && concat.endsWith(string2) + } + } + } +}) +``` +Kotest würde mit seinem Standardgenerator diesen Test für 1000 Werte durchspielen und die Ergebnisse prüfen. +Selbstverständlich können auch eigene Generatoren geschrieben werden, die an die eigenen Bedürfnisse angepasst sind. +In diesem Beispiel mag der Test trivial sein, da auch die Fachlichkeit sehr simpel ist. +Je komplexer allerdings die Methode, desto schwieriger kann es sein herauszufinden, welche Menge von Daten eigentlich welche Eigenschaften erfüllen soll. +Ein netter Nebeneffekt: +Tests so zu schreiben zwingt uns damit nochmal auf eine andere Art und Weise über die Korrektheit einer Methode nachzudenken. + +# Abschluss +Für mich persönlich, mit Java-Erfahrung seit 2012, war mein erster praktischer Kontakt mit Kotlin in 2019 wie eine kleine Offenbarung. +Möglicherweise ist es der Gewöhnungseffekt, dass Kotlin für mich in vielen Punkten durchdachter als Java scheint. +Sicherlich wird dabei auch das noch recht junge Alter der Sprache und die Erfahrungen, die in sie hineingeflossen sind, eine Rolle spielen. +Das funktionale Paradigma und Kotlin in seiner Ausprägung, ich habe es schon vorher geschrieben, kommen mir häufig leichtgängiger vor und es bereitet mir viel Freude, so zu programmieren. +Wir sollten uns dabei aber auch immer bewusst sein, dass dies zu einem gewissen Preis geschieht. +Der Preis, den wir hier zahlen, sind Effizienzeinbußen (die in vielen Projekten allerdings vernachlässigbar sein werden) gegenüber zum Beispiel einer optimierten Programmierlösung in C, sowie der Aufwand, den es für uns mit sich bringt, sich an diese *neue* Art zu denken zu gewöhnen. +Es hat einen Grund, dass sich viele Sprachen heutzutage an funktionaler Programmierung orientieren und diese sehr populär ist. +Ich hoffe, dass ich euch einen kleinen Einblick in Kotlin und die funktionale Welt geben konnte. + +Wenn ihr an dieser Stelle neugierig geworden seid und euch weiter mit der Sprache beschäftigen möchtet, dann empfehle ich ausdrücklich die [Kotlin Koans](https://kotlinlang.org/docs/koans.html). +Kotlin Koans sind sehr gute offizielle Tutorial-Reihe, die sich unter anderem mit den Inhalten beschäftigt, die wir hier nur oberflächlich betrachten konnten, und auch noch viel weiter in die Details der Sprache eintaucht. + +Im Allgemeinen empfehle ich auch den [Kotlin Playground](https://play.kotlinlang.org/) zum schnellen und unkomplizierten herumprobieren und programmieren im Webbrowser eurer Wahl, wenn ihr Kotlin nicht lokal ausführen wollt. + +Ein anderer spannender Blogeintrag zum Thema Kotlin bei adesso zum direkt Weiterlesen: +[Kotlin Multiplattform Mobile](https://www.adesso.de/de/news/blog/vorteile-von-kotlin-fuer-die-businesslogik-von-android-und-ios-apps.jsp) +oder direkt an der Quelle: +[The Kotlin Blog](https://blog.jetbrains.com/kotlin/) + + +Quellen: +- [Kotlin-Wikipedia](https://de.wikipedia.org/wiki/Kotlin_(Programmiersprache)) +- [Funktionale Programmierung-Wikipedia](https://de.wikipedia.org/wiki/Funktionale_Programmierung) +- [Lambda Kalkül-Wikipedia](https://de.wikipedia.org/wiki/Lambda-Kalk%C3%BCl) +- [Kotlin Dokumentation](https://kotlinlang.org/docs/properties.html) +- [Learning Journal](https://www.learningjournal.guru/article/scala/functional-programming/immutability-in-functional-programming/) +- [Baeldung](https://www.baeldung.com/kotlin/const-var-and-val-keywords) +- [Philipp Hauer's Blog](https://phauer.com/2017/idiomatic-kotlin-best-practices/#functional-programming) +- [Medium](https://medium.com/criteo-engineering/introduction-to-property-based-testing-f5236229d237) +- [Kotest](https://kotest.io/docs/proptest/property-test-functions.html) +- [Leading Agile](https://www.leadingagile.com/2018/03/immutability-in-java/) +- [Hackernoon](https://hackernoon.com/5-benefits-of-immutable-objects-worth-considering-for-your-next-project-f98e7e85b6ac) +- [Stackoverflow](https://stackoverflow.com/questions/34385243/why-is-immutability-so-important-or-needed-in-javascript) diff --git a/_posts/2021-09-20-test-post.md b/_posts/2021-09-20-test-post.md deleted file mode 100644 index f52ea579f..000000000 --- a/_posts/2021-09-20-test-post.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -layout: [post, post-xml] # Pflichtfeld. Nicht ändern! -title: 'Ein Testpost' # Pflichtfeld. Bitte einen Titel für den Blog Post angeben. -date: 2021-09-20 13:00 # Pflichtfeld. Format "YYYY-MM-DD HH:MM". Muss für Veröffentlichung in der Vergangenheit liegen. (Für Preview egal) -modified_date: 2021-09-20 13:00 # Optional. Muss angegeben werden, wenn eine bestehende Datei geändert wird. -author_ids: [jo2] # Pflichtfeld. Es muss in der "authors.yml" einen Eintrag mit diesem Namen geben. -categories: [Softwareentwicklung] # Pflichtfeld. Maximal eine der angegebenen Kategorien verwenden. -tags: [Test] # Bitte auf Großschreibung achten. ---- -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. - -# Lorem Ipsum -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. - -Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. -Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. - -Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. -Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. - -Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. -Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. -Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. - -Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. - -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. -sanctus sea sed takimata ut vero voluptua. -est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. - -Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus. - -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. -At vero eos et accusam et justo duo dolores et ea rebum. -Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. - -Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. -Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. - -Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. -Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. - -Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. -Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. -Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo From 61ec055dda46c1af9758f655ef5a6575d2796382 Mon Sep 17 00:00:00 2001 From: Johannes Teklote Date: Mon, 21 Feb 2022 14:29:53 +0100 Subject: [PATCH 78/78] fix blogpost --- .../2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" "b/_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" index 246451c8d..c8a45ef27 100644 --- "a/_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" +++ "b/_posts/2021-08-23-functional-kotlin-eine-einf\303\274hrung.md" @@ -1,6 +1,6 @@ --- -layout: [post-xml] # Pflichtfeld. Nicht ändern! -title: 'Functional Kotlin - Eine Einführung' # Pflichtfeld. Bitte einen Titel für den Blog Post angeben. +layout: [post, post-xml] # Pflichtfeld. Nicht ändern! +title: "Functional Kotlin - Eine Einführung" # Pflichtfeld. Bitte einen Titel für den Blog Post angeben. date: 2021-08-23 13:00 # Pflichtfeld. Format "YYYY-MM-DD HH:MM". Muss für Veröffentlichung in der Vergangenheit liegen. (Für Preview egal) modified_date: 2021-08-23 13:00 # Optional. Muss angegeben werden, wenn eine bestehende Datei geändert wird. author_ids: [fabianvolkert, jo2] # Pflichtfeld. Es muss in der "authors.yml" einen Eintrag mit diesem Namen geben.