Jenkins Pipeline for Java Applications

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.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper