Overview
Jenkins Pipeline (specifically Declarative Pipeline) provides a powerful way to define continuous integration and delivery pipelines as code. For Java applications, this includes building, testing, packaging, and deploying.
Basic Pipeline Structure
1. Simple Java Pipeline
pipeline { agent any tools { maven 'M3' // Maven installation configured in Jenkins jdk 'JDK11' // JDK installation configured in Jenkins } stages { stage('Checkout') { steps { checkout scm } } stage('Build') { steps { sh 'mvn clean compile' } } stage('Test') { steps { sh 'mvn test' } post { always { junit 'target/surefire-reports/*.xml' } } } stage('Package') { steps { sh 'mvn package -DskipTests' } } } post { always { emailext ( subject: "Pipeline ${currentBuild.currentResult}: Job ${env.JOB_NAME}", body: "Run ${env.BUILD_URL}", to: "[email protected]" ) } success { archiveArtifacts 'target/*.jar' } } } 2. Advanced Multi-Module Pipeline
pipeline { agent any tools { maven 'M3' jdk 'JDK11' } parameters { choice( name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: 'Target deployment environment' ) booleanParam( name: 'RUN_INTEGRATION_TESTS', defaultValue: false, description: 'Run integration tests' ) } environment { NEXUS_URL = 'https://nexus.company.com' SONAR_URL = 'https://sonar.company.com' DOCKER_REGISTRY = 'registry.company.com' } stages { stage('Checkout and Validate') { steps { checkout scm script { // Validate POM and dependencies sh 'mvn validate dependency:analyze' } } } stage('Build and Unit Tests') { parallel { stage('Compile') { steps { sh 'mvn compile -q' } } stage('Unit Tests') { steps { sh 'mvn test -Dtest=*UnitTest' } post { always { junit 'target/surefire-reports/*.xml' } } } } } stage('Code Quality') { parallel { stage('Static Analysis') { steps { sh 'mvn sonar:sonar -Dsonar.host.url=${SONAR_URL}' } } stage('Dependency Check') { steps { sh 'mvn org.owasp:dependency-check-maven:check' } } } } stage('Integration Tests') { when { expression { params.RUN_INTEGRATION_TESTS } } steps { sh 'mvn verify -Dtest=*IntegrationTest' junit 'target/failsafe-reports/*.xml' } } stage('Build Docker Image') { steps { script { def version = sh(script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim() def artifactId = sh(script: 'mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout', returnStdout: true).trim() docker.build("${DOCKER_REGISTRY}/${artifactId}:${version}") } } } stage('Deploy to Environment') { steps { script { deployToEnvironment(params.DEPLOY_ENV) } } } } post { always { cleanWs() publishHTML([ allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true, reportDir: 'target/site', reportFiles: 'index.html', reportName: 'Maven Site Report' ]) } success { script { slackSend( channel: '#builds', message: "Build Successful: ${env.JOB_NAME} #${env.BUILD_NUMBER}" ) } } failure { script { slackSend( channel: '#builds', message: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}", color: 'danger' ) } } } } // Shared library function def deployToEnvironment(env) { switch(env) { case 'dev': sh "mvn tomcat7:deploy -Dtomcat.url=http://dev-tomcat.company.com" break case 'staging': sh "mvn tomcat7:deploy -Dtomcat.url=http://staging-tomcat.company.com" break case 'prod': input message: 'Deploy to production?', ok: 'Deploy' sh "mvn tomcat7:deploy -Dtomcat.url=http://prod-tomcat.company.com" break } } Spring Boot Specific Pipeline
3. Spring Boot with Docker and Kubernetes
pipeline { agent any tools { maven 'M3' jdk 'JDK17' } environment { APP_NAME = 'my-spring-boot-app' DOCKER_IMAGE = "company/${APP_NAME}" KUBE_NAMESPACE = 'default' HELM_CHART_PATH = 'charts/my-app' } stages { stage('Checkout') { steps { checkout scm } } stage('Build and Test') { steps { sh ''' mvn clean compile mvn test mvn jacoco:report ''' } post { always { junit 'target/surefire-reports/*.xml' jacoco( execPattern: 'target/jacoco.exec', classPattern: 'target/classes', sourcePattern: 'src/main/java' ) } } } stage('Build JAR') { steps { sh 'mvn package -DskipTests' archiveArtifacts 'target/*.jar' } } stage('Build Docker Image') { steps { script { def version = sh(script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim() def commitHash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() docker.build("${DOCKER_IMAGE}:${version}-${commitHash}") docker.build("${DOCKER_IMAGE}:latest") } } } stage('Security Scan') { steps { script { sh 'mvn org.owasp:dependency-check-maven:check' dependencyCheckPublisher( pattern: '**/dependency-check-report.xml' ) // Trivy vulnerability scan sh ''' docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ aquasec/trivy image ${DOCKER_IMAGE}:latest ''' } } } stage('Push to Registry') { steps { script { def version = sh(script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim() def commitHash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() withCredentials([usernamePassword( credentialsId: 'docker-registry', usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS' )]) { sh """ docker login -u $REGISTRY_USER -p $REGISTRY_PASS ${env.DOCKER_REGISTRY} docker push ${DOCKER_IMAGE}:${version}-${commitHash} docker push ${DOCKER_IMAGE}:latest """ } } } } stage('Deploy to Kubernetes') { when { branch 'main' } steps { script { def version = sh(script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim() def commitHash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() withCredentials([file( credentialsId: 'kubeconfig', variable: 'KUBECONFIG' )]) { sh """ helm upgrade --install ${APP_NAME} ${HELM_CHART_PATH} \ --namespace ${KUBE_NAMESPACE} \ --set image.tag=${version}-${commitHash} \ --set image.repository=${DOCKER_IMAGE} \ --wait """ } } } } stage('Integration Tests') { steps { script { // Wait for application to be ready sh """ kubectl wait --for=condition=ready pod -l app=${APP_NAME} \ --namespace ${KUBE_NAMESPACE} \ --timeout=300s """ // Run integration tests against deployed application sh 'mvn verify -Dtest=*IntegrationTest' } } post { always { junit 'target/failsafe-reports/*.xml' } } } stage('Performance Tests') { steps { script { dir('performance-tests') { sh 'mvn gatling:test' } } } post { always { gatling() } } } } post { always { // Cleanup test namespace sh "kubectl delete namespace test-${env.BUILD_NUMBER} --ignore-not-found=true" // Build cleanup sh 'docker system prune -f' } success { script { def version = sh(script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim() office365ConnectorSend( message: "Spring Boot App ${version} deployed successfully", status: "Success", webhookUrl: "${env.TEAMS_WEBHOOK_URL}" ) } } failure { script { office365ConnectorSend( message: "Pipeline failed for ${env.JOB_NAME}", status: "Failure", webhookUrl: "${env.TEAMS_WEBHOOK_URL}" ) } } } } Microservices Pipeline
4. Multi-Service Pipeline with Shared Library
Shared Library Structure:
vars/ buildJavaApp.groovy deployToK8s.groovy runIntegrationTests.groovy
buildJavaApp.groovy:
def call(Map config) { def defaultConfig = [ javaVersion: '11', buildTool: 'maven', skipTests: false, buildArgs: '' ] config = defaultConfig + config pipeline { agent any tools { jdk "JDK${config.javaVersion}" if (config.buildTool == 'maven') { maven 'M3' } } stages { stage('Build') { steps { script { if (config.buildTool == 'maven') { sh "mvn clean compile ${config.buildArgs}" } else if (config.buildTool == 'gradle') { sh "./gradlew compileJava ${config.buildArgs}" } } } } stage('Test') { when { expression { !config.skipTests } } steps { script { if (config.buildTool == 'maven') { sh 'mvn test' junit 'target/surefire-reports/*.xml' } else if (config.buildTool == 'gradle') { sh './gradlew test' junit 'build/test-results/test/*.xml' } } } } stage('Package') { steps { script { if (config.buildTool == 'maven') { sh "mvn package -DskipTests ${config.buildArgs}" } else if (config.buildTool == 'gradle') { sh "./gradlew build -x test ${config.buildArgs}" } } } } } } } Main Pipeline using Shared Library:
@Library('java-shared-library')_ def serviceConfigs = [ 'user-service': [javaVersion: '17', buildArgs: '-Pdocker'], 'order-service': [javaVersion: '11', skipTests: false], 'payment-service': [javaVersion: '11', buildTool: 'gradle'] ] pipeline { agent any stages { stage('Build All Services') { steps { script { parallel serviceConfigs.collect { serviceName, config -> "${serviceName}": { buildJavaApp(config) } } } } } stage('Integration Tests') { steps { runIntegrationTests() } } stage('Deploy to Staging') { steps { script { serviceConfigs.each { serviceName, config -> deployToK8s( service: serviceName, environment: 'staging', namespace: 'microservices-staging' ) } } } } } } Advanced Pipeline with Quality Gates
5. Pipeline with Quality Gates and Approval
pipeline { agent any tools { maven 'M3' jdk 'JDK11' } environment { QUALITY_GATE_SONAR = '80' QUALITY_GATE_COVERAGE = '70' QUALITY_GATE_TESTS = '100' } stages { stage('Checkout') { steps { checkout scm } } stage('Build') { steps { sh 'mvn clean compile' } } stage('Unit Tests') { steps { sh 'mvn test' } post { always { junit 'target/surefire-reports/*.xml' step([ $class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1, thresholds: [ [$class: 'FailedThreshold', failureThreshold: '0'], [$class: 'SkippedThreshold', skippedThreshold: '0'] ], tools: [[$class: 'JUnitType', pattern: 'target/surefire-reports/*.xml']] ]) } } } stage('Code Quality') { steps { script { sh "mvn sonar:sonar -Dsonar.qualitygate.wait=true" // Wait for quality gate timeout(time: 10, unit: 'MINUTES') { def qg = waitForQualityGate() if (qg.status != 'OK') { error "Quality gate failed: ${qg.status}" } } } } } stage('Code Coverage Check') { steps { script { def coverage = sh( script: 'mvn help:evaluate -Dexpression=project.coverage.percentage -q -DforceStdout', returnStdout: true ).trim().toInteger() if (coverage < env.QUALITY_GATE_COVERAGE.toInteger()) { error "Code coverage ${coverage}% is below required ${env.QUALITY_GATE_COVERAGE}%" } echo "Code coverage: ${coverage}% - PASSED" } } } stage('Security Scan') { steps { script { sh 'mvn org.owasp:dependency-check-maven:check -DfailBuildOnCVSS=7' dependencyCheckPublisher( pattern: '**/dependency-check-report.xml', failTotalHigh: '10', failTotalMedium: '50' ) } } } stage('Build Artifact') { steps { sh 'mvn package -DskipTests' archiveArtifacts 'target/*.jar' } } stage('Docker Build and Scan') { steps { script { def version = sh(script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim() docker.build("myapp:${version}") // Security scan sh """ trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:${version} """ } } } stage('Deploy to Staging') { steps { script { withKubeConfig([credentialsId: 'k8s-cluster', serverUrl: '']) { sh 'kubectl apply -f k8s/staging/' } } } } stage('Integration Tests on Staging') { steps { script { timeout(time: 15, unit: 'MINUTES') { waitUntil { try { sh 'mvn verify -Dtest=*IntegrationTest -Dservice.url=http://staging.myapp.com' return true } catch (Exception e) { sleep 30 return false } } } } } } stage('Approval for Production') { steps { script { def deployToProd = input( id: 'DeployToProd', message: 'Deploy to production?', parameters: [ choice( name: 'ENVIRONMENT', choices: ['prod-eu', 'prod-us'], description: 'Target production environment' ), booleanParam( name: 'CONFIRM', defaultValue: false, description: 'I confirm deployment to production' ) ] ) if (deployToProd['CONFIRM']) { env.DEPLOY_ENV = deployToProd['ENVIRONMENT'] } else { error 'Deployment to production cancelled' } } } } stage('Deploy to Production') { steps { script { withKubeConfig([credentialsId: 'k8s-prod', serverUrl: '']) { sh """ kubectl apply -f k8s/production/${env.DEPLOY_ENV}/ kubectl rollout status deployment/myapp -n production """ } } } } stage('Smoke Tests') { steps { script { sh 'mvn test -Dtest=SmokeTest -Dservice.url=http://prod.myapp.com' } } } } post { always { // Cleanup sh 'docker system prune -f' // Publish reports publishHTML([ allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: 'target/site', reportFiles: 'jacoco/index.html', reportName: 'Coverage Report' ]) } success { script { // Notify success slackSend( channel: '#deployments', message: "✅ Successfully deployed ${env.JOB_NAME} to production", color: 'good' ) } } failure { script { // Notify failure slackSend( channel: '#deployments', message: "❌ Deployment failed for ${env.JOB_NAME}", color: 'danger' ) // Rollback on failure if (env.DEPLOY_ENV) { withKubeConfig([credentialsId: 'k8s-prod', serverUrl: '']) { sh "kubectl rollout undo deployment/myapp -n production" } } } } unstable { // Handle unstable build (test failures, quality gate warnings) emailext ( subject: "Build ${env.JOB_NAME} is unstable", body: "Check test results and quality gates", to: "[email protected]" ) } } } Pipeline with Database Migrations
6. Pipeline with Flyway/Liquibase
pipeline { agent any tools { maven 'M3' jdk 'JDK11' } environment { DB_URL = credentials('database-url') DB_USERNAME = credentials('database-username') DB_PASSWORD = credentials('database-password') } stages { stage('Checkout') { steps { checkout scm } } stage('Build') { steps { sh 'mvn clean compile' } } stage('Run Database Migrations - Test') { steps { script { sh """ mvn flyway:migrate \ -Dflyway.url=${DB_URL}_test \ -Dflyway.user=${DB_USERNAME} \ -Dflyway.password=${DB_PASSWORD} """ } } } stage('Run Tests') { steps { sh 'mvn test' } post { always { junit 'target/surefire-reports/*.xml' } } } stage('Package') { steps { sh 'mvn package -DskipTests' } } stage('Deploy to Staging') { steps { script { // Deploy application sh 'mvn tomcat7:deploy -Dtomcat.url=http://staging-tomcat' // Run migrations on staging sh """ mvn flyway:migrate \ -Dflyway.url=${DB_URL}_staging \ -Dflyway.user=${DB_USERNAME} \ -Dflyway.password=${DB_PASSWORD} """ } } } stage('Production Database Migration') { when { branch 'main' } steps { script { // Dry run first sh """ mvn flyway:info \ -Dflyway.url=${DB_URL}_production \ -Dflyway.user=${DB_USERNAME} \ -Dflyway.password=${DB_PASSWORD} """ // Get approval for migration input message: 'Run database migration on production?', ok: 'Run Migration' // Execute migration sh """ mvn flyway:migrate \ -Dflyway.url=${DB_URL}_production \ -Dflyway.user=${DB_USERNAME} \ -Dflyway.password=${DB_PASSWORD} """ } } } stage('Deploy to Production') { when { branch 'main' } steps { script { input message: 'Deploy to production?', ok: 'Deploy' sh 'mvn tomcat7:deploy -Dtomcat.url=http://prod-tomcat' } } } } post { always { // Cleanup test database sh """ mvn flyway:clean \ -Dflyway.url=${DB_URL}_test \ -Dflyway.user=${DB_USERNAME} \ -Dflyway.password=${DB_PASSWORD} """ } } } Best Practices and Tips
7. Pipeline Configuration with Jenkinsfile
#!/usr/bin/env groovy // Configuration as code def config = [ application: [ name: 'my-java-app', version: readMavenVersion(), port: 8080 ], quality: [ coverageThreshold: 80, testPassRate: 100, maxCriticalVulnerabilities: 0 ], deployment: [ staging: [ url: 'http://staging.company.com', namespace: 'staging' ], production: [ url: 'http://prod.company.com', namespace: 'production' ] ] ] def readMavenVersion() { return sh( script: 'mvn help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true ).trim() } pipeline { agent any tools { maven 'M3' jdk 'JDK11' } options { timeout(time: 1, unit: 'HOURS') buildDiscarder(logRotator(numToKeepStr: '10')) disableConcurrentBuilds() timestamps() } triggers { pollSCM('H/5 * * * *') // Poll SCM every 5 minutes // or for GitHub githubPush() } parameters { choice( name: 'BUILD_TYPE', choices: ['fast', 'full'], description: 'Build type: fast (skip tests) or full' ) string( name: 'FEATURE_FLAGS', defaultValue: '', description: 'Feature flags to enable' ) } stages { stage('Initialize') { steps { script { echo "Building ${config.application.name} v${config.application.version}" echo "Build type: ${params.BUILD_TYPE}" // Validate environment sh 'java -version' sh 'mvn -version' } } } stage('Build') { steps { script { def buildCommand = 'mvn clean compile' if (params.BUILD_TYPE == 'fast') { buildCommand += ' -DskipTests' } sh buildCommand } } } stage('Test') { when { expression { params.BUILD_TYPE == 'full' } } steps { script { sh 'mvn test' sh 'mvn jacoco:report' } } post { always { junit 'target/surefire-reports/*.xml' jacoco( execPattern: 'target/jacoco.exec', classPattern: 'target/classes', sourcePattern: 'src/main/java' ) } } } stage('Quality Gate') { when { expression { params.BUILD_TYPE == 'full' } } steps { script { // Check test results def testResults = readJSON file: 'target/surefire-reports/TEST-*.json' def passRate = (testResults.passed / testResults.total) * 100 if (passRate < config.quality.testPassRate) { error "Test pass rate ${passRate}% is below required ${config.quality.testPassRate}%" } // Check coverage def coverage = sh( script: 'mvn help:evaluate -Dexpression=project.coverage.percentage -q -DforceStdout', returnStdout: true ).trim().toInteger() if (coverage < config.quality.coverageThreshold) { error "Coverage ${coverage}% is below required ${config.quality.coverageThreshold}%" } } } } } post { always { // Archive everything useful archiveArtifacts artifacts: 'target/*.jar', fingerprint: true archiveArtifacts artifacts: 'target/site/**/*', fingerprint: true // Clean workspace cleanWs() } changed { // Notify on status change script { if (currentBuild.currentResult != currentBuild.previousBuild?.result) { slackSend( channel: '#build-status', message: "Build ${currentBuild.currentResult}: ${env.JOB_NAME} #${env.BUILD_NUMBER}" ) } } } } } These Jenkins pipeline examples provide comprehensive coverage for Java applications, including Spring Boot, microservices, quality gates, security scanning, and deployment strategies. They demonstrate best practices for continuous integration and delivery in Java environments.