194 lines
7.3 KiB
Groovy
194 lines
7.3 KiB
Groovy
// Jenkins-Pipeline für den PDF KI Renamer
|
|
// Läuft auf einem Linux-Container (Synology NAS).
|
|
// Der MSI-Build ist Windows-only (jpackage + WiX Toolset 3.x). Jenkins läuft im
|
|
// Linux-Container auf Synology NAS und kann kein MSI erzeugen. Der MSI-Build
|
|
// wird bewusst manuell auf der Windows-Entwicklungsmaschine ausgeführt:
|
|
// .\mvnw.cmd clean package -P release -pl pdf-umbenenner-packaging --also-make -DskipTests
|
|
|
|
pipeline {
|
|
agent any
|
|
|
|
options {
|
|
disableConcurrentBuilds()
|
|
}
|
|
|
|
tools {
|
|
maven 'maven-3'
|
|
}
|
|
|
|
// MAJOR und MINOR werden manuell als Jenkins-Parameter gepflegt.
|
|
// BUILD_NUMBER wird automatisch durch Jenkins vergeben.
|
|
// Die resultierende Versionsnummer lautet: MAJOR.MINOR.BUILD_NUMBER
|
|
parameters {
|
|
string(name: 'MAJOR', defaultValue: '3', description: 'SemVer MAJOR (manuell)')
|
|
string(name: 'MINOR', defaultValue: '0', description: 'SemVer MINOR (manuell)')
|
|
}
|
|
|
|
stages {
|
|
|
|
stage('Version bestimmen') {
|
|
steps {
|
|
script {
|
|
def isManual = !currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause').isEmpty()
|
|
def jenkinsHome = env.JENKINS_HOME ?: '/var/jenkins_home'
|
|
def safeJobName = env.JOB_NAME.replaceAll(/[^A-Za-z0-9._-]/, '_')
|
|
def stateDir = "${jenkinsHome}/version-state"
|
|
def stateFile = "${stateDir}/${safeJobName}.properties"
|
|
|
|
if (isManual) {
|
|
env.EFFECTIVE_MAJOR = params.MAJOR
|
|
env.EFFECTIVE_MINOR = params.MINOR
|
|
|
|
sh """
|
|
mkdir -p '${stateDir}'
|
|
cat > '${stateFile}' <<'EOF'
|
|
MAJOR=${params.MAJOR}
|
|
MINOR=${params.MINOR}
|
|
EOF
|
|
"""
|
|
|
|
echo "Manueller Build erkannt. Version gespeichert: ${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}"
|
|
} else {
|
|
def stateExists = (sh(script: "[ -f '${stateFile}' ]", returnStatus: true) == 0)
|
|
|
|
if (stateExists) {
|
|
env.EFFECTIVE_MAJOR = sh(
|
|
script: "grep '^MAJOR=' '${stateFile}' | cut -d= -f2-",
|
|
returnStdout: true
|
|
).trim()
|
|
|
|
env.EFFECTIVE_MINOR = sh(
|
|
script: "grep '^MINOR=' '${stateFile}' | cut -d= -f2-",
|
|
returnStdout: true
|
|
).trim()
|
|
|
|
echo "Automatischer Build erkannt. Gespeicherte Version verwendet: ${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}"
|
|
} else {
|
|
env.EFFECTIVE_MAJOR = params.MAJOR
|
|
env.EFFECTIVE_MINOR = params.MINOR
|
|
|
|
echo "Automatischer Build ohne gespeicherten Stand. Fallback auf Parameter: ${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}"
|
|
}
|
|
}
|
|
|
|
currentBuild.displayName = "#${env.BUILD_NUMBER} ${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}"
|
|
}
|
|
}
|
|
} // stage: Version bestimmen
|
|
|
|
stage('Maven Build') {
|
|
steps {
|
|
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
|
|
// -Drevision übergibt die vollständige Versionsnummer an Maven.
|
|
// Das flatten-maven-plugin im Parent-POM löst ${revision} in
|
|
// allen installierten POMs auf.
|
|
sh "mvn clean verify -Drevision=${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}.${env.BUILD_NUMBER}"
|
|
}
|
|
}
|
|
} // stage: Maven Build
|
|
|
|
stage('SonarQube Analyse') {
|
|
steps {
|
|
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
|
|
withSonarQubeEnv('SonarQube') {
|
|
sh "mvn sonar:sonar -Drevision=${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}.${env.BUILD_NUMBER} -Dsonar.projectKey=pdf-umbenenner -Dsonar.projectName='PDF KI Renamer'"
|
|
}
|
|
}
|
|
}
|
|
} // stage: SonarQube Analyse
|
|
|
|
stage('Publish PIT Coverage') {
|
|
steps {
|
|
recordCoverage(
|
|
tools: [[
|
|
parser: 'PIT',
|
|
pattern: '**/target/pit-reports/mutations.xml'
|
|
]],
|
|
id: 'pit',
|
|
name: 'PIT Mutation Coverage',
|
|
failOnError: true
|
|
)
|
|
}
|
|
} // stage: Publish PIT Coverage
|
|
|
|
stage('Archive JAR') {
|
|
steps {
|
|
// Bash wird explizit erzwungen, weil Jenkins-Agenten standardmäßig
|
|
// sh (dash) verwenden, das kein mapfile kennt. mapfile zählt exakt
|
|
// die gefundenen Shade-JARs und bricht ab, wenn nicht genau eines vorhanden ist.
|
|
sh '''#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
mapfile -t JARS < <(find pdf-umbenenner-bootstrap/target \
|
|
-maxdepth 1 -name "pdf-umbenenner-bootstrap-*.jar" \
|
|
! -name "*-sources.jar" ! -name "*-javadoc.jar")
|
|
|
|
test "${#JARS[@]}" -eq 1 \
|
|
|| { echo "FEHLER: Erwartet genau 1 Shade-JAR, gefunden: ${#JARS[@]}"; exit 1; }
|
|
|
|
JAR_NAME="pdf-ki-renamer-${EFFECTIVE_MAJOR}.${EFFECTIVE_MINOR}.${BUILD_NUMBER}.jar"
|
|
cp "${JARS[0]}" "$JAR_NAME"
|
|
echo "Shade-JAR archiviert als: $JAR_NAME"
|
|
'''
|
|
archiveArtifacts artifacts: 'pdf-ki-renamer-*.jar', fingerprint: true
|
|
}
|
|
} // stage: Archive JAR
|
|
|
|
stage('Artefakt ablegen') {
|
|
steps {
|
|
sh '''#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
BUILD_DIR="/builds/${EFFECTIVE_MAJOR}.${EFFECTIVE_MINOR}.${BUILD_NUMBER}"
|
|
mkdir -p "$BUILD_DIR"
|
|
cp pdf-ki-renamer-*.jar "$BUILD_DIR/"
|
|
echo "Artefakt abgelegt unter: $BUILD_DIR"
|
|
'''
|
|
}
|
|
} // stage: Artefakt ablegen
|
|
|
|
stage('Berichte veröffentlichen') {
|
|
steps {
|
|
junit testResults: '**/target/surefire-reports/*.xml', allowEmptyResults: true
|
|
|
|
recordCoverage(
|
|
tools: [[parser: 'JACOCO', pattern: 'pdf-umbenenner-coverage/target/site/jacoco-aggregate/jacoco.xml']],
|
|
enabledForFailure: true
|
|
)
|
|
|
|
publishHTML(target: [
|
|
reportName: 'JaCoCo HTML Report',
|
|
reportDir: 'pdf-umbenenner-coverage/target/site/jacoco-aggregate',
|
|
reportFiles: 'index.html',
|
|
keepAll: true,
|
|
alwaysLinkToLastBuild: true,
|
|
allowMissing: true
|
|
])
|
|
}
|
|
} // stage: Berichte veröffentlichen
|
|
|
|
stage('Aufräumen') {
|
|
steps {
|
|
sh '''#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
rm -f pdf-ki-renamer-*.jar
|
|
echo "Aufräumen abgeschlossen."
|
|
'''
|
|
}
|
|
} // stage: Aufräumen
|
|
|
|
} // stages
|
|
|
|
post {
|
|
success {
|
|
echo "Build ${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}.${env.BUILD_NUMBER} erfolgreich abgeschlossen."
|
|
}
|
|
failure {
|
|
echo "Build ${env.EFFECTIVE_MAJOR}.${env.EFFECTIVE_MINOR}.${env.BUILD_NUMBER} fehlgeschlagen."
|
|
}
|
|
always {
|
|
deleteDir()
|
|
}
|
|
}
|
|
|
|
} // pipeline |