Publish test results and coverage to Jenkins, integrate SonarQube for static code analysis, and automatically stop the pipeline when a Quality Gate fails with waitForQualityGate.

In episode 13 we turned Jenkins configuration into code with JCasC. Now let's question something that is often taken for granted: what is actually inside your pipeline?
Many pipelines stop at the build stage — compilation succeeds, the image is built, then straight to deploy. Yet a successful build does not at all guarantee the code is correct, secure, or release-ready. Imagine passing a written exam without anyone checking the answers: the grade comes out, but fundamental mistakes still slip through. In the real world, serious CI must run automated tests, measure code coverage, and assess code quality statically before anything may head to production.
In this episode we will publish test results to Jenkins with the junit step, integrate coverage with JaCoCo, and then connect Jenkins to SonarQube for static code analysis complete with a Quality Gate that can stop the pipeline automatically.
junit StepModern test frameworks produce XML reports at standard locations, for example Maven writes to target/surefire-reports/. Jenkins can read those reports and display trends, flaky tests, and per-build history with the junit step:
steps {
sh 'mvn test'
junit 'target/surefire-reports/*.xml'
archiveArtifacts artifacts: 'target/surefire-reports/*.xml'
}The pattern in the junit argument is a glob and is relative to the workspace. After this step runs, the build page shows a summary of passed, failed, and skipped test counts, complete with a trend graph across builds.
Tip
If many tests fail randomly (flaky), monitor the test trend page in Jenkins. A pattern of always-green tests sometimes turns red without any code change — that is a sign the tests depend on order or global state.
Running tests alone is not enough; we need to know how much code is actually tested. For Java, JaCoCo is the coverage standard. Configure it in pom.xml, then after mvn test Jenkins records the results with the jacoco step:
steps {
sh 'mvn test'
jacoco execPattern: 'target/jacoco.exec',
classPattern: 'target/classes',
sourcePattern: 'src/main/java'
}Jenkins then displays the line, branch, and method coverage percentages on the build page. For XML-coverage-based projects like Cobertura, use the cobertura step with the coverage.xml report file. Present coverage as a pass requirement — for example below 70 percent means it needs improvement.
To assess code quality comprehensively — bugs, code smells, duplication, and security holes — use SonarQube. The architecture: a SonarQube server as the analyzer, and the SonarQube Scanner for Jenkins plugin as the bridge. Configure the server in Manage Jenkins > Configure System, add a credential token, then each project can include a sonar-project.properties file:
sonar.projectKey=my-app
sonar.projectName=My App
sonar.sources=src
sonar.tests=src/test
sonar.java.binaries=target/classes
sonar.jacoco.reportPaths=target/jacoco.execFor Maven projects, the analysis can be run directly through the Maven sonar plugin inside a withSonarQubeEnv block, which points the scanner at the configured server.
SonarQube assesses quality based on a Quality Gate — a set of thresholds such as minimum coverage or the number of blocker bugs. After the analysis completes, the waitForQualityGate step waits for the assessment result and stops the pipeline if the gate fails. A complete pipeline example for a Java project:
pipeline {
agent { label 'linux-runner' }
stages {
stage('Build & Test') {
steps {
sh 'mvn clean verify'
}
}
stage('Publish Test & Coverage') {
steps {
junit 'target/surefire-reports/*.xml'
jacoco execPattern: 'target/jacoco.exec'
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.11.0.3922:sonar'
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
}
}With abortPipeline: true, the pipeline stops automatically as soon as SonarQube reports a failed gate — the code will never reach the deploy stage.
Warning
waitForQualityGate waits for a callback from the SonarQube server. If
the webhook to Jenkins is not configured in SonarQube, or the Quality Gate
is not set to pass automatically when there is no new analysis, this step
can hang forever. Always wrap it in a timeout as in the
example above.
Important
Important: make sure the default Quality Gate in SonarQube is applied to
the project, and add the webhook http://jenkins.example.com/sonarqube-webhook/
in the SonarQube administration. Without both, the gate result will never
get back to Jenkins.
As soon as a threshold is violated, SonarQube sends an ERROR status and Jenkins stops the build right at the Quality Gate stage. The development team sees directly on the build page where the analysis reports problems, opens the details in the SonarQube dashboard, and fixes them in the source code before triggering the next build. This gate turns quality from mere hope into an automatically enforced requirement.
Tip
Start with a realistic gate — for example minimum coverage and zero blockers — then tighten it as the team gets used to it. A gate that is too strict from the start usually drives teams to disable it.
In episode 14 you published test results with the junit step, recorded code coverage with JaCoCo, connected Jenkins to SonarQube for static code analysis, and enforced quality with waitForQualityGate, which stops the pipeline automatically when a Quality Gate fails. You also know the common trap of a gate hanging when the webhook is not configured.
Now your pipeline is complete on the build side: secure, configured as code, tested, and high quality. Only one most-anticipated stage remains: sending the code to a production server.
In episode 15 we will discuss Continuous Deployment (CD) to a Linux Server via SSH / Ansible — securely injecting an SSH key and automating deployment with Ansible. See you there!