From 9e32a5e4da17cb5144ed002ecd9d85517fca44bf Mon Sep 17 00:00:00 2001 From: Patrick Stoeckle Date: Thu, 25 Sep 2025 23:04:52 +0200 Subject: [PATCH 1/5] feat(ci): add initial ci lab --- content/2025/labs/99_shared/ci/_index.md | 173 ++++++++++++++++++ .../2025/labs/99_shared/ci/java-example.zip | Bin 0 -> 3154 bytes 2 files changed, 173 insertions(+) create mode 100644 content/2025/labs/99_shared/ci/_index.md create mode 100644 content/2025/labs/99_shared/ci/java-example.zip diff --git a/content/2025/labs/99_shared/ci/_index.md b/content/2025/labs/99_shared/ci/_index.md new file mode 100644 index 000000000..c0cc44515 --- /dev/null +++ b/content/2025/labs/99_shared/ci/_index.md @@ -0,0 +1,173 @@ +--- +title: "Continuous Integration (CI) - Automatisiere deine Builds und Tests" +linkTitle: "SimpleExample" +type: docs +weight: 1 +description: > + In diesem Abschnitt lernst du, wie du Continuous Integration (CI) einrichtest, um Builds und Tests zu automatisieren. +--- + + + +## Voraussetzung + +- Du kennst die Grundlagen von Git und verstehst, wie Versionskontrollsysteme funktionieren. +- Du kennst die Grundlagen von Java und Maven und kannst einfache Java-Projekte erstellen und verwalten. +- Du kennst die Grundlagen des Software-Testings. +- Du verstehst YAML Dateien. + +## Was ist Continuous Integration (CI)? + +Continuous Integration (CI) ist eine Praxis in der Softwareentwicklung, bei der Entwickler ihre Codeänderungen _kontinuierlich_ (continuous) in ein gemeinsames Repository _integrieren_. +Jede Integration wird automatisch durch einen Build-Prozess +und automatisierte Tests überprüft, um sicherzustellen, dass der neue Code keine Fehler oder Konflikte einführt. +Es gibt verschiedene CI Systeme, z.B. + +- GitHub Actions +- GitLab CI/CD +- Tekton + +## Motivation für CI + +Warum ist CI wichtig? +Stell dir vor, du arbeitest in einem Team von Entwicklern an einem grossen Projekt. +Deine Chefin sagt dir, dass du eine neue Funktion implementieren sollst. +Also checkst den `main` Branch aus, implementierst die Funktion, willst sie testen +und stellst fest, dass irgendwas nicht mehr funktioniert. +Nach einigem Suchen findest du heraus, dass Problem schon vor deiner Änderung existierte. +Ein Kollege hat eine Änderung gemacht, die das Problem verursacht hat, und diese +einfach auf den `main` Branch gepusht, ohne sie zu testen. +Das ist frustrierend, oder? +Mit einer funktionierenden CI-Pipeline, die automatisch Builds und Tests durchführt, +hätte dieses Problem vermieden werden können. +Eine gute CI-Pipeline stellt sicher, dass z.B. der `main` Branch immer in einem funktionsfähigen Zustand ist. + +## Übung + +In dieser Übung lernst du, wie du eine einfache CI-Pipeline mit GitHub Actions[^1] einrichtest. +Die Pipeline wird automatisch ausgeführt, wenn du Code in den `main` Branch pusht. + +### Aufgabe 1: Erstelle ein GitHub Repository + +1. Gehe zu [GitHub](https://github.com/new) und erstelle ein neues Repository. +2. Nenne das Repository `ci-example` und setze es auf "Public". +3. Initialisiere das Repository mit einer `README.md` Datei. +4. Klicke auf `Create`. +5. Clone das Repository auf deinen Rechner. +6. Öffne das Repository in IntelliJ. +7. Kopiere den Inhalt der Beispielanwendung (aus dem ZIP-File) in das Repository. + Anschliessend solltest du + + - `./src/main/java/ch/itninja/Main.java` + - `./src/test/java/ch/itninja/MainTest.java` + - `./pom.xml` + - `./.gitignore` + + in deinem Repository haben. +8. Teste, ob Maven funktioniert. + + ```shell + mvn test + ``` + + Das Ergebnis sollte ungefähr so aussehen + + ```log + [INFO] Results: + [INFO] + [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 + [INFO] + [INFO] ------------------------------------------------------------------------ + [INFO] BUILD SUCCESS + ``` + +9. Verwende `git add .` und `git commit` um einen Commit zu erstellen. +10. Pushe deinen neuen Commit. + Öffne dein GitHub Repository und überprüfe, ob dein Push funktioniert hat. + +### Aufgabe 2: Erstelle einen GitHub Action, um die Tests auszuführen + +GitHub Actions sind das CI System von GitHub. +In GitHub Actions definieren wir `workflows`. +Die Workflows speichern wir im Ordner `.github/workflows`. +Ein Workflow besteht aus einem oder mehreren Jobs. +Ein Job kann einen oder mehrere Schritte (`steps`) haben. + +1. Erstelle im Root-Verzeichnis deines Projekts den Ordner `.github/workflows`. +2. Erstelle im Ordner `.github/workflows` die Datei `java-test.yml`. +3. Füge folgenden Inhalt in die Datei `java-test.yml` ein: + + ```yaml + name: java test with maven + + on: + push: + branches: + - main + + jobs: + java-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "temurin" + - name: Run JUnit tests using Maven + run: mvn test + ``` + +
+ Was bedeuten die einzelnen Schlüsselworte? + + - `name`: Der Name des Workflows. + - `on`: Definiert, wann der Workflow ausgelöst wird. In diesem Fall bei einem Push auf den `main` Branch. + - `jobs`: Definiert die Jobs, die ausgeführt werden sollen. + - `java-test`: Der Name des Jobs. + - `runs-on`: Definiert die Umgebung, in der der Job ausgeführt wird. + - `steps`: Definiert die einzelnen Schritte des Jobs. + - `uses`: Verwendet eine vordefinierte Action mit einer bestimmten Version. + - [actions/checkout](https://www.github.com/actions/checkout/tree/v5/) + - [actions/setup-java](https://www.github.com/actions/setup-java/tree/v4/) + - `name`: Der Name eines Schritts. + - `run`: Führt einen Shell-Befehl aus. + +
+ + Unser Job `java-test` verwendet `ubuntu-latest` als Basis, um seine Schritte + auszuführen. + Unser Job hat 3 Schritte: + + - Schritt 1: Checke den aktuellen Stand des Repositories aus. + - Schritt 2: Setze Java. Hier können wir die Java Version angeben, die wir benutzen. + - Schritt 3: Führe `mvn test` aus. + +4. Committe und pushe die Änderungen. +5. Gehe zu deinem GitHub Repository und klicke auf den Reiter `Actions`. + Du solltest sehen, dass dein Workflow ausgeführt wird. +6. Klicke auf den laufenden Workflow, um die Details zu sehen. +7. Klicke auf den Job `java-test` und dann auf den Step `Run JUnit tests using Maven`. + Du solltest die Ausgabe von Maven sehen. +8. Am Ende sollte der Workflow erfolgreich sein und mit einem ✅ markiert sein. + +Herzlichen Glückwunsch! +Du hast deine erste CI erstellt! + +### Aufgabe 2a: Teste Deine CI! (Optional) + +1. Füge dem Java Code einen Fehler hinzu, der verhindert, dass das Java Programm +kompiliert werden kann oder die Tests fehlschlagen lässt. +2. Committe und pushe die Änderungen. +3. Gehe zu deinem GitHub Repository und klicke auf den Reiter `Actions`. + Warte, bis dein Workflow abgeschlossen ist. + Der Workflow sollte fehlschlagen und mit einem ❌ markiert sein. +4. Klicke auf den Workflow, um die Details zu sehen. +5. Klicke auf den Job `java-test` und dann auf den Step `Run JUnit tests using Maven`. + Du solltest die Ausgabe von Maven sehen und dort auf den Fehler + hingewiesen werden, den du gerade eingeführt hast. +6. Fixe den Fehler wieder. +7. Committe und pushe die Änderungen. +8. Der Workflow sollte wieder erfolgreich sein und mit einem ✅ markiert sein. + +[^1]: Diese Aufgabe basiert auf diff --git a/content/2025/labs/99_shared/ci/java-example.zip b/content/2025/labs/99_shared/ci/java-example.zip new file mode 100644 index 0000000000000000000000000000000000000000..36ee342e151e384c6e986399f25b99dd7b83b835 GIT binary patch literal 3154 zcmWIWW@h1HU|`^2xUj)8`p^H*kM1xsFic}+VBlilWY9~`EXhpI%P&d|4Pj+qJh9+v z#?oNl{M!aRdw+*>d|0ZT#r>l2fWd;ya*k<*YI3>lTmM%>_3W;@ZLu7$ zX4Wi{n;*T=lcObyN8M2H=%2__rLomq6AygTvRGN@D6Odn*?+zX4sNg$jAsmKCMtY=EUn(@_%7aOk>r|!1!|82SFltH*~IJUzsYt}!Sp`6Wt*&xbXFegh+7=KTyNn#(O2&- zUE);1Izt~8x)O{g;Zw8l#<*Z!ODcQQ)-Eh(Ikh67W$KS7)E=vwhvtFchYx!4}su<3?*Qu$^tQNcf{!Th@ByWw@^j`@- zKc*cp&R?+iV!FV(9c61b&EKZ}{1>yLY&~0R<@uwW8_alre*D|F=eVlg_Ss2QOiv58 z8eP_#&b{vr%b|5T+Mg=Qe_wuop-^RNX$Aw1f{pUHhXa88e z_OTL|&YRb|pJQ&ll)4q4u*SZxRZg{gtKbz0+b{9iYJL$`s#j+Q8?EiF&6{IW^sr{; zuN6=I#W*`3oZ7vQ)hlhr#7}d!t$#Ezc&B7_9gA&+MTFRsizdQ7;nyk2`c zs@elSzIF5rf5Y8!De2hXw9HL6YwX=>XS=<8RqHSf4u6* z?wcGz_qp^NEjRQ{`XO6CQRjbQSo+pPw##pBE&P~x{`Rq1Pw(h`S$f1RS@`qRGfOYb zc$LYaG3gr1d6oMQRz)q*Q*H@!zsaK(V{f)Q=86ON9j4WG0Y~y%joebXXeLHVX^T+!=o0}UKn|ug+TvqYlN{gE{I5pWSNbD19>TG*hf`B9@U>br0 z7GQ!XE=tyirv}_gLFo>pG&eCbj~MlQ$m+8a%MyvvB#5CYIfEE|lGyZRmgHsTWnr-w zk}=Xe8E0()hJ-mVb131{?+f&?9>@pqP|EEyJI9)cI}J5mHRK!e&gUOue8K>T3+ilF}`ar)jU5Jo$7mY z{@(<4P0eo6>z60%Pro0vlr=?W5|^2`vevT0*KI=%oYrq=Z`ttcs6>Ixj|(5~S~@lx zH>^)~|HeW%W=m3wONa?XelNz%KO{B#viar7{E6$#9e<3ht-vF^1G-k2t2gPg% z(ATK3TiUyk>yQIa+xP0Op0!g#LSlBUc<|yGcgyR-Wv^m$g9MknfA{sm#d;3TpP!bh zSF6515I4cJ;Kd5Vw)eF%B99(ylxEIeWxHB>Le;U&!nt)F8k)E5pTr&EJ!QzDH|gp< z4;H^8iD3tBJ9x!1EA0~RF8Yv={Q6SPr#$oGoz-r62dix-Y|uUR{;kX@`@a5(c|kd= z*Bo~dTkXsGIyKTva&FJeGwcE0j7*?b0j{2k_WA{+6Jh`_&?3y* z2B9B&9fQ#C3Dl2X;~;cnFOVSa764LFEDY$y6U^tBT0sRALTf8jD|&H-TR$jSBlK@Y z){maZaT@|Ezz~MK!Y~9i(c?A;RG=ZuQ3BT8@Uj=|7@#>=G6Bpy>;)XiJV>l2;WH1j zxWgA=sG%Ou25~4jx50}`eELyCy&qXWxuJdp!w~X9{SP*C2!=X(;e!Zu8+N3?L61f3 zMNxn^E6@=P417TN3fL3S;$UFVU`R_&wJ=FZG%zwxG*2;1H8V*xFiA_bG*7iOH8C(v ONlG?Iu}CsAw*UZ2kr~|p literal 0 HcmV?d00001 From 5255761baddec8072eab8bed26225f127be450a3 Mon Sep 17 00:00:00 2001 From: Patrick Stoeckle Date: Fri, 26 Sep 2025 09:22:35 +0200 Subject: [PATCH 2/5] chore: update content for CI lab --- content/2025/labs/99_shared/ci/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/2025/labs/99_shared/ci/_index.md b/content/2025/labs/99_shared/ci/_index.md index c0cc44515..3df635897 100644 --- a/content/2025/labs/99_shared/ci/_index.md +++ b/content/2025/labs/99_shared/ci/_index.md @@ -1,8 +1,8 @@ --- title: "Continuous Integration (CI) - Automatisiere deine Builds und Tests" -linkTitle: "SimpleExample" +linkTitle: "Continuous Integration (CI)" type: docs -weight: 1 +weight: 5 description: > In diesem Abschnitt lernst du, wie du Continuous Integration (CI) einrichtest, um Builds und Tests zu automatisieren. --- From 215e470f4d481ef6dc59aa28f4aa173fb6f793be Mon Sep 17 00:00:00 2001 From: Patrick Stoeckle Date: Fri, 26 Sep 2025 09:28:50 +0200 Subject: [PATCH 3/5] chore: prettier --- content/2025/labs/99_shared/ci/_index.md | 31 ++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/content/2025/labs/99_shared/ci/_index.md b/content/2025/labs/99_shared/ci/_index.md index 3df635897..e367c0801 100644 --- a/content/2025/labs/99_shared/ci/_index.md +++ b/content/2025/labs/99_shared/ci/_index.md @@ -4,7 +4,7 @@ linkTitle: "Continuous Integration (CI)" type: docs weight: 5 description: > - In diesem Abschnitt lernst du, wie du Continuous Integration (CI) einrichtest, um Builds und Tests zu automatisieren. + In diesem Abschnitt lernst du, wie du Continuous Integration (CI) einrichtest, um Builds und Tests zu automatisieren. --- @@ -64,6 +64,7 @@ Die Pipeline wird automatisch ausgeführt, wenn du Code in den `main` Branch pus - `./.gitignore` in deinem Repository haben. + 8. Teste, ob Maven funktioniert. ```shell @@ -101,21 +102,21 @@ Ein Job kann einen oder mehrere Schritte (`steps`) haben. name: java test with maven on: - push: - branches: - - main + push: + branches: + - main jobs: - java-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-java@v4 - with: - java-version: "21" - distribution: "temurin" - - name: Run JUnit tests using Maven - run: mvn test + java-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "temurin" + - name: Run JUnit tests using Maven + run: mvn test ```
@@ -157,7 +158,7 @@ Du hast deine erste CI erstellt! ### Aufgabe 2a: Teste Deine CI! (Optional) 1. Füge dem Java Code einen Fehler hinzu, der verhindert, dass das Java Programm -kompiliert werden kann oder die Tests fehlschlagen lässt. + kompiliert werden kann oder die Tests fehlschlagen lässt. 2. Committe und pushe die Änderungen. 3. Gehe zu deinem GitHub Repository und klicke auf den Reiter `Actions`. Warte, bis dein Workflow abgeschlossen ist. From 6e6a454e9b78e2bc1af1081901fe47e287e8ed1b Mon Sep 17 00:00:00 2001 From: Patrick Stoeckle Date: Thu, 2 Oct 2025 15:33:38 +0200 Subject: [PATCH 4/5] chore(review): repo does not have to be public --- content/2025/labs/99_shared/ci/_index.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/content/2025/labs/99_shared/ci/_index.md b/content/2025/labs/99_shared/ci/_index.md index e367c0801..16e2c92c6 100644 --- a/content/2025/labs/99_shared/ci/_index.md +++ b/content/2025/labs/99_shared/ci/_index.md @@ -50,12 +50,11 @@ Die Pipeline wird automatisch ausgeführt, wenn du Code in den `main` Branch pus ### Aufgabe 1: Erstelle ein GitHub Repository 1. Gehe zu [GitHub](https://github.com/new) und erstelle ein neues Repository. -2. Nenne das Repository `ci-example` und setze es auf "Public". -3. Initialisiere das Repository mit einer `README.md` Datei. -4. Klicke auf `Create`. -5. Clone das Repository auf deinen Rechner. -6. Öffne das Repository in IntelliJ. -7. Kopiere den Inhalt der Beispielanwendung (aus dem ZIP-File) in das Repository. +2. Initialisiere das Repository mit einer `README.md` Datei. +3. Klicke auf `Create`. +4. Clone das Repository auf deinen Rechner. +5. Öffne das Repository in IntelliJ. +6. Kopiere den Inhalt der Beispielanwendung (aus dem ZIP-File) in das Repository. Anschliessend solltest du - `./src/main/java/ch/itninja/Main.java` @@ -65,7 +64,7 @@ Die Pipeline wird automatisch ausgeführt, wenn du Code in den `main` Branch pus in deinem Repository haben. -8. Teste, ob Maven funktioniert. +7. Teste, ob Maven funktioniert. ```shell mvn test @@ -82,9 +81,9 @@ Die Pipeline wird automatisch ausgeführt, wenn du Code in den `main` Branch pus [INFO] BUILD SUCCESS ``` -9. Verwende `git add .` und `git commit` um einen Commit zu erstellen. -10. Pushe deinen neuen Commit. - Öffne dein GitHub Repository und überprüfe, ob dein Push funktioniert hat. +8. Verwende `git add .` und `git commit` um einen Commit zu erstellen. +9. Pushe deinen neuen Commit. + Öffne dein GitHub Repository und überprüfe, ob dein Push funktioniert hat. ### Aufgabe 2: Erstelle einen GitHub Action, um die Tests auszuführen From 6e93f4e91cab6bbf8a4439975bccb630afe9b20c Mon Sep 17 00:00:00 2001 From: Patrick Stoeckle Date: Thu, 2 Oct 2025 16:43:18 +0200 Subject: [PATCH 5/5] chore(review): more details on CI/CD and workflows --- content/2025/labs/99_shared/ci/_index.md | 58 ++++++++++++++++++++---- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/content/2025/labs/99_shared/ci/_index.md b/content/2025/labs/99_shared/ci/_index.md index 16e2c92c6..c21158ad9 100644 --- a/content/2025/labs/99_shared/ci/_index.md +++ b/content/2025/labs/99_shared/ci/_index.md @@ -135,13 +135,56 @@ Ein Job kann einen oder mehrere Schritte (`steps`) haben.
- Unser Job `java-test` verwendet `ubuntu-latest` als Basis, um seine Schritte - auszuführen. - Unser Job hat 3 Schritte: + **Wie funktioniert dieser Workflow genau?** - - Schritt 1: Checke den aktuellen Stand des Repositories aus. - - Schritt 2: Setze Java. Hier können wir die Java Version angeben, die wir benutzen. - - Schritt 3: Führe `mvn test` aus. + Unser Workflow mit dem Namen `java test with maven` hat verschiedene Teile: + + - Trigger (`on:`): Bestimmt, bei welchen Ereignissen der Workflow ausgelöst wird. + Im Beispiel ist das `push` auf `main`. + + Häufig ergänzt man `pull_request`, damit auch PRs geprüft werden, bevor sie gemerged werden. + Man kann auch `schedule` nutzen, um den Workflow z.B. täglich auszuführen. + Oder man führt den Workflow nur aus, wenn ein Release erstellt wird. + Manche Workflows haben gar kein Ereignis als Trigger, sondern werden von anderen Workflows gestartet, d.h. `on: workflow_run`. + Dies ist nützlich für komplexe CI/CD-Pipelines, da wir so wiederverwendbare Workflows erstellen können. + + - Jobs (`jobs:`): Ein Workflow kann mehrere Jobs haben, die parallel oder nacheinander ausgeführt werden. + In unserem Beispiel gibt es nur einen Job namens `java-test`. + + Jeder Job läuft in einer frischen Umgebung (Runner) und hat seine eigenen Schritte. + Jobs können auch durch `needs` voneinander abhängen, d.h. ein Job startet erst, wenn ein anderer erfolgreich abgeschlossen ist. + Da wir aber nur einen Job haben, ist das hier nicht relevant. + + Unser `java-test` Job hat folgende Bestandteile: + + - `runs-on`: Legt die Ausführungsumgebung (Runner) fest — in der Regel ein Linux-, Windows- oder macOS-Runner. + In unserem Beispiel nutzen wir `ubuntu-latest`, d.h. die neueste verfügbare Ubuntu Version. + - `steps`: Die Schritte, die der Job ausführt. + Jeder Schritt kann eine fertige GitHub Action (`uses:`) oder einen Shell-Befehl (`run:`) ausführen. + GitHub Actions sind wiederverwendbare Komponenten, die bestimmte Aufgaben erledigen. + GitHub Actions haben den Vorteil, dass wir uns **nicht** um die Details kümmern müssen. + In unserem Beispiel müssen wir z.B. nicht selbst Java installieren, sondern nutzen die `actions/setup-java` Action. + Wir können im jeweiligen Online Repository auch die Dokumentation der Actions lesen, um zu verstehen, was sie tun und welche Eingaben sie erwarten. + + Unser Job hat drei Schritte: + + - `uses: actions/checkout@v5`: Der erste Schritt nutzt `git` bzw. die `actions/checkout` GitHub Action, um den Code aus dem Repository in die Runner-Umgebung zu klonen. + + Bei GitHub Actions können wir git Commit Hashes, Branch-Namen, Tags oder Versionsnummern angeben, um eine spezifische Version der Action zu nutzen. + Im Beispiel verwenden wir hier die Version `v5`, d.h. wir verwenden den aktuellsten Tag, der mit `v5` beginnt (aktuell ist das `v5.0.0`, könnte aber in Zukunft `v5.3.2` oder höher sein). + Wenn wir immer die neueste Version einer Action nutzen wollen, könnten wir auch `@main` angeben, was aber nicht empfohlen wird, da es zu unerwarteten Änderungen führen kann. + Wenn wir eine spezifischere Version wie `v5.3.2` angeben wollen, könnten wir das auch tun. + Wenn wir immer diesselbe Version einer Action nutzen wollen, auch wenn der Maintainer Tags löscht und neu erstellt, könnten wir auch den Commit Hash angeben, z.B. `@a1b2c3d4e`. + + - `uses: actions/setup-java@v4`: Installiert die gewünschte JDK-Version, damit `mvn` mit der richtigen Java-Version läuft. + + Hier nutzen wir, dass GitHub Actions `inputs` unterstützen, die wir mit `with:` angeben können. + In unserem Beispiel geben wir die Java-Version `21` und die Distribution `temurin` an. + Die Action installiert dann automatisch das passende JDK. + + - `run: mvn test`: Führt Maven aus und startet Build und Tests. + Hier führen wir einen Shell-Befehl aus, der Maven startet und die Tests ausführt. + Für die Darstellung in der GitHub Actions Oberfläche ist es hilfreich, wenn wir dem Schritt einen Namen geben, z.B. `Run JUnit tests using Maven`. 4. Committe und pushe die Änderungen. 5. Gehe zu deinem GitHub Repository und klicke auf den Reiter `Actions`. @@ -151,9 +194,6 @@ Ein Job kann einen oder mehrere Schritte (`steps`) haben. Du solltest die Ausgabe von Maven sehen. 8. Am Ende sollte der Workflow erfolgreich sein und mit einem ✅ markiert sein. -Herzlichen Glückwunsch! -Du hast deine erste CI erstellt! - ### Aufgabe 2a: Teste Deine CI! (Optional) 1. Füge dem Java Code einen Fehler hinzu, der verhindert, dass das Java Programm