Wichtiger Hinweis vorab: Fuer dieses Lernprojekt stand kein echter Jenkins-Server zur
Verfuegung - das Jenkinsfile selbst konnte deshalb nicht gegen einen echten Jenkins
ausgefuehrt werden. Was dagegen sehr wohl echt getestet wurde: jedes einzelne Shell-Kommando,
das die Pipeline aufruft (mvn ..., ci/scripts/deploy.sh ...) - siehe
ci/scripts/deploy.sh selbst, das manuell mit allen drei Zielstufen durchlaufen wurde.
Dieselbe Grenze wie beim automatisierten Liberty-EAR-Deployment in Phase 5
(docs/50-websphere-config/03-liberty-serverstart-verifiziert.md) - ehrlich benannt statt
verschwiegen.
mvn ist auf dem Agenten bereits verfuegbarDas Jenkinsfile hat bewusst keinen tools { maven '...'; jdk '...' }-Block - so ein
Block muesste auf konkrete Namen verweisen, die unter "Global Tool Configuration" auf dem
Ziel-Jenkins eingerichtet sind. Da fuer dieses Projekt kein echter Jenkins-Server zur
Verfuegung stand, waeren solche Namen frei erfunden und wuerden eine Pruefbarkeit
vortaeuschen, die nicht besteht. Stattdessen die ehrliche Annahme: der Jenkins-Agent, der
diese Pipeline ausfuehrt, hat Maven und ein passendes JDK bereits auf dem PATH (z.B. ueber
ein vorbereitetes Docker-Agent-Image). Wer dieses Jenkinsfile gegen einen echten Jenkins
einsetzt, sollte diesen Block ergaenzen und an die dort konfigurierten Tool-Namen anpassen.
Das Jenkinsfile nutzt Jenkins' Declarative Pipeline-Syntax (pipeline { ... }) statt der
aelteren, freieren Scripted-Pipeline-Syntax (node { ... }) - Declarative erzwingt eine
feste Struktur (Stages, Steps, klar getrennte post-Aktionen), die leichter zu lesen und zu
validieren ist. Fuer eine Multibranch-Pipeline (mehrere Branches, jeder mit eigenem
Pipeline-Lauf) ist das der Standardweg.
parameters: Wie weit soll dieser Lauf gehen?parameters {
choice(name: 'DEPLOY_STAGE', choices: ['none', 'test', 'qs', 'prod'], ...)
}
Ein Build-Parameter, den ein Nutzer beim manuellen Ausloesen waehlt (oder der bei
automatischen Trigger-Laeufen auf seinem Default none bleibt). Jede when-Bedingung
weiter unten prueft params.DEPLOY_STAGE, um zu entscheiden, ob ihre Stage ueberhaupt
ausgefuehrt wird.
stage('Unit- und Modultests'): Coverage im Standardlaufsh 'mvn -B -Pcoverage verify'
novaris-integration-tests (Phase 5) hat sein eigenes Surefire deaktiviert. Ohne das Profil
integration bleiben diese Docker-Tests beim normalen Verify-Lauf uebersprungen. Das Profil
coverage aktiviert JaCoCo fuer die Unit-Tests und erzeugt Reports unter target/site/jacoco/.
Die echten Oracle-/IBM-MQ-Tests werden erst ueber den Pipeline-Parameter
RUN_INTEGRATION_TESTS mit mvn -Pintegration verify ausgefuehrt.
-B (Batch-Modus) unterdrueckt interaktive Maven-Ausgaben/-Prompts - in einer CI-Umgebung
ohne Terminal essenziell, sonst kann ein Build unerwartet haengen bleiben.
Die Pipeline wird zentral vom Jenkins aus ../../shared/enterprise-infrastructure verwaltet. Das projektspezifische
Jenkinsfile bleibt die fachliche Build-/Deploy-Definition; Jenkins Configuration as Code
verweist auf dieses Repository.
post { always { junit ... } }: Testergebnisse sichtbar machenjunit testResults: 'novaris-legacy-parent/*/target/surefire-reports/*.xml', allowEmptyResults: true
Das JUnit-Plugin von Jenkins liest die von Surefire erzeugten XML-Testberichte und macht sie
als grafische Testuebersicht (bestanden/fehlgeschlagen/Trend ueber die Zeit) im Jenkins-UI
sichtbar - unabhaengig davon, ob der Build insgesamt erfolgreich war oder nicht (always,
nicht success), damit man auch bei einem fehlgeschlagenen Build sofort sieht, WELCHER Test
fehlgeschlagen ist, ohne das Konsolenlog durchsuchen zu muessen. allowEmptyResults: true
verhindert, dass ein Modul ohne Tests (z.B. novaris-policy-ear) den Schritt selbst zum
Scheitern bringt.
input: die manuellen Freigabe-Gatesinput message: "QS-Deployment von Build #${env.BUILD_NUMBER} freigeben?",
submitter: 'novaris-qs-approvers'
input haelt die Pipeline an einer bestimmten Stelle an und wartet auf eine manuelle
Bestaetigung im Jenkins-UI. submitter schraenkt ein, WER bestaetigen darf (eine in Jenkins
konfigurierte Berechtigungsgruppe) - ohne dieses Attribut duerfte jeder mit allgemeinem
Jenkins-Zugriff die Freigabe erteilen, was fuer ein PROD-Gate offensichtlich zu schwach waere.
withCredentials: Passwoerter nur zur Laufzeit, nie im LogwithCredentials([
string(credentialsId: 'novaris-test-oracle-password', variable: 'NOVARIS_ORACLE_PASSWORD'),
...
]) {
sh 'ci/scripts/deploy.sh test'
}
credentialsId verweist auf einen Eintrag im Jenkins-Credentials-Store (dort einmalig von
einem Administrator hinterlegt, niemals im Repository). Innerhalb des withCredentials-
Blocks steht der tatsaechliche Wert als Umgebungsvariable (NOVARIS_ORACLE_PASSWORD) zur
Verfuegung - Jenkins maskiert diesen Wert automatisch in der Konsolenausgabe (jedes
Vorkommen wird durch **** ersetzt), selbst wenn ein aufgerufenes Skript ihn versehentlich
ausgeben wuerde. Das ist der Grund, warum ci/env/*.properties bewusst keine Passwoerter
enthaelt (siehe 01-vier-stages-ueberblick.md) - die Trennung "unkritische Konfiguration in
Dateien, Geheimnisse im Credentials-Store" ist hier durchgezogen, nicht nur behauptet:
ci/scripts/deploy.sh prueft explizit, dass NOVARIS_ORACLE_PASSWORD/NOVARIS_DB2_PASSWORD
beim Aufruf tatsaechlich gesetzt sind (Praesenz-Check, ohne die Werte selbst zu verwenden
oder auszugeben) - so bleibt die withCredentials-Verkabelung keine reine Behauptung im
Jenkinsfile, sondern etwas, das das Skript beim Fehlen sichtbar ablehnt.
when { allOf { ... } }: mehrere Bedingungen fuer PRODwhen {
allOf {
expression { params.DEPLOY_STAGE == 'prod' }
expression { env.BRANCH_NAME == 'main' || (env.BRANCH_NAME ?: '').startsWith('release/') }
}
}
Beide Bedingungen muessen zutreffen - der gewaehlte Parameter UND der richtige Branch.
(env.BRANCH_NAME ?: '') faengt den Fall ab, dass BRANCH_NAME in einer Nicht-
Multibranch-Pipeline-Konfiguration gar nicht gesetzt ist (dann waere es null, und
null.startsWith(...) wuerde eine NullPointerException werfen statt einfach false zu
ergeben).