A real Java pipeline, end to end
Build, test, gate on quality, publish an image and deploy - assembled one directive at a time.
Open this lesson in the learning hubKey points
- Run Maven with
-B -ntpso the console is build output instead of thousands of download lines. - Gradle on an agent should pass
--no-daemon, because a leftover daemon holds heap between builds. - Cache
~/.m2or~/.gradleby mounting a volume into the container, not by copying it around. withSonarQubeEnvinjects the server URL and token, andwaitForQualityGateneeds a webhook back from SonarQube.- Tag the image with
BUILD_NUMBERand the short commit so a running container maps to one build. - Deploy is just another stage, but give it its own agent label and its own credential scope.
Example
pipeline {
agent none
options { timeout(time: 45, unit: 'MINUTES') }
environment {
IMAGE = "registry.example.com/orders-api:${BUILD_NUMBER}"
}
stages {
stage('Build and test') {
agent { docker { image 'maven:3.9-eclipse-temurin-17'
args '-v $HOME/.m2:/var/maven/.m2 -e MAVEN_CONFIG=/var/maven/.m2' } }
steps {
sh 'mvn -B -ntp -Duser.home=/var/maven -Dmaven.test.failure.ignore=true verify'
// Analysis runs HERE, in the workspace that holds target/classes. On a fresh
// agent sonar:sonar fails with "Please provide compiled classes of your project".
withSonarQubeEnv('sonar') { sh 'mvn -B -ntp -Duser.home=/var/maven sonar:sonar' }
}
post {
always {
junit '**/target/surefire-reports/*.xml'
stash name: 'jar', includes: 'target/*.jar'
}
}
}
stage('Quality gate') {
// No agent needed: this only waits for SonarQube to call the webhook back,
// so it holds a flyweight executor rather than a whole build agent.
agent none
steps {
timeout(time: 10, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
stage('Publish image') {
agent { label 'docker-build' }
steps {
unstash 'jar'
sh 'docker build -t $IMAGE .'
withCredentials([usernamePassword(credentialsId: 'registry-creds',
usernameVariable: 'U',
passwordVariable: 'P')]) {
sh 'set +x; echo "$P" | docker login registry.example.com -u "$U" --password-stdin'
}
sh 'docker push $IMAGE'
}
}
stage('Deploy to production') {
when { beforeInput true; branch 'main' }
input { message 'Ship to production?'; ok 'Deploy' }
agent { label 'deploy' }
steps { sh './deploy.sh "$IMAGE"' }
}
}
}
Pin the toolchain, stash between agents, gate on quality and keep deploy on its own agent behind a when guard.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Jenkins CI/CD Course course, and every lesson in it is listed on the Jenkins CI/CD Course contents page.