Can I Continue the Build From Preivous Point in Jenkins
Last Updated on May 4, 2022
SonarQube is an excellent tool for measuring code quality, using static analysis to find code smells, bugs, vulnerabilities, and poor test coverage. Rather than manually analysing the reports, why not automate the process by integrating SonarQube with your Jenkins continuous integration pipeline? This way, you can configure a quality gate based on your own requirements, ensuring bad code always fails the build.
You'll learn exactly how to do that in this article, through a full worked example where we add SonarQube analysis and SonarQube quality gate stages to a Jenkins pipeline.
UPDATED in December 2021 to use more recent Jenkins and plugin versions.
SonarQube refresher
SonarQube works by running a local process to scan your project, called the SonarQube scanner. This sends reports to a central server, known as the SonarQube server.
The SonarQube server also has a UI where you can browse these reports. They look like this:
Quality gates
In SonarQube a quality gate is a set of conditions that must be met in order for a project to be marked as passed. In the above example the project met all the conditions.
Here's an example where things didn't go so well.
Clicking on the project name gives full details of the failure.
Here you can see here that a condition failed because the maintainability rating was a D rather than A.
SonarQube and Jenkins
Running a SonarQube scan from a build on your local workstation is fine, but a robust solution needs to include SonarQube as part of the continuous integration process. If you add SonarQube analysis into a Jenkins pipeline, you can ensure that if the quality gate fails then the pipeline won't continue to further stages such as publish or release. After all, nobody wants to release crappy code into production. 👌
To do this, we can use the SonarQube Scanner plugin for Jenkins. It includes two features that we're going to make use of today:
- SonarQube server configuration – the plugin lets you set your SonarQube server location and credentials. This information is then used in a SonarQube analysis pipeline stage to send code analysis reports to that SonarQube server.
- SonarQube Quality Gate webhook – when a code analysis report is submitted to SonarQube, unfortunately it doesn't respond synchronously with the result of whether the report passed the quality gate or not. To do this, a webhook call must be configured in SonarQube to call back into Jenkins to allow our pipeline to continue (or fail). The SonarQube Scanner Jenkins plugin makes this webhook available.
Here's a full breakdown of the interaction between Jenkins and SonarQube:
- a Jenkins pipeline is started
- the SonarQube scanner is run against a code project, and the analysis report is sent to SonarQube server
- SonarQube finishes analysis and checking the project meets the configured Quality Gate
- SonarQube sends a pass or failure result back to the Jenkins webhook exposed by the plugin
- the Jenkins pipeline will continue if the analysis result is a pass or optionally otherwise fail
Full worked example
Let's get our hands dirty with a worked example. We'll run through all the steps in the UI manually as this is the best way to understand the setup.
In this example we'll:
- get Jenkins and SonarQube up and running
- install the SonarQube Scanner Jenkins plugin and configure it to point to our SonarQube instance
- configure SonarQube to call the Jenkins webhook when project analysis is finished
- create two Jenkins pipelines
- one that runs against a codebase with zero issues (I wish all my code was like this 😉)
- one that runs against a codebase with bad code issues
- run the pipelines and see it all working
You'll need to make sure you have Docker installed before carrying on.
Fast track: to get up and running quickly check out this GitHub repository. Everything is setup through configuration-as-code, except the steps under Configure SonarQube below.
Running Jenkins and SonarQube
What better way to start these two services than with Docker Compose? Create the following file docker-compose.yml:
version: "3" services: sonarqube: image: sonarqube:lts ports: - 9000:9000 networks: - mynetwork environment: - SONAR_FORCEAUTHENTICATION=false jenkins: image: jenkins/jenkins:2.319.1-jdk11 ports: - 8080:8080 networks: - mynetwork networks: mynetwork:
- we're configuring two containers in Docker Compose: Jenkins and SonarQube
- the Docker images used come from the official repositories in Docker Hub
- we're adding both containers to the same network so they can talk to each other
- for demo purposes SonarQube authentication is disabled so Jenkins won't need to pass a token
Running docker-compose up
in the directory containing the file will start Jenkins on http://localhost:8080 and SonarQube on http://localhost:9000. Awesomeness!
Configuring the SonarQube Scanner Jenkins plugin
Grab the Jenkins administrator password from the Jenkins logs in the console output of the Docker Compose command you just ran.
jenkins_1 | Please use the following password to proceed to installation: jenkins_1 | jenkins_1 | 7efed7f025ee430c8938beaa975f5dde
Head over to your Jenkins instance and paste in the password.
On the next page choose Select plugins to install and install only the pipeline and git plugins. The SonarQube Scanner plugin we'll have to install afterwards since this Getting Started page doesn't give us the full choice of plugins.
In the final steps you'll have to create a user and confirm the Jenkins URL of http://localhost:8080
.
Once complete head over to Manage Jenkins > Manage Plugins > Available and search for sonar. Select the SonarQube Scanner plugin and click Install without restart.
Once the plugin is installed, let's configure it!
Go to Manage Jenkins > Configure System and scroll down to the SonarQube servers section. This is where we'll add details of our SonarQube server so Jenkins can pass its details to our project's build when we run it.
Click the Add SonarQube button. Now add a Name for the server, such as SonarQube. The Server URL will be http://sonarqube:9000. Remember to click Save.
Networking in Docker Compose: the SonarQube URL is http://sonarqube:9000
because by default Docker Compose allows any service to call any other service in the same network. You do this by using the service name as the hostname in the request URL, as defined in docker-compose.yml. This is why we use a host of sonarqube
.
Configuring SonarQube
Let's jump over to SonarQube. Click Log in at the top-right of the page, and log in with the default credentials of admin/admin
. You'll then have to set a new password.
Now go to Administration > Configuration > Webhooks. This is where we can add webhooks that get called when project analysis is completed. In our case we need to configure SonarQube to call Jenkins to let it know the results of the analysis.
Click Create, and in the popup that appears give the webhook a name of Jenkins, set the URL to http://jenkins:8080/sonarqube-webhook and click Create.
In this case, the URL has the path sonarqube-webhook
which is exposed by the SonarQube Scanner plugin we installed earlier.
Adding a quality gate
SonarQube comes with its own Sonar way quality gate enabled by default. If you click on Quality Gates you can see the details of this.
It's all about making sure that new code is of a high quality. In this example we want to check the quality of existing code, so we need to create a new quality gate.
Click Create, then give the quality gate a name. I've called mine Tom Way 😉
Click Save then on the next screen click Add Condition. Select On Overall Code. Search for the metric Maintainability Rating and choose worse than A. This means that if existing code is not maintainable then the quality gate will fail. Click Add Condition to save the condition.
Finally click Set as Default at the top of the page to make sure that this quality gate will apply to any new code analysis.
Creating Jenkins pipelines
Last thing to do is setup two Jenkins pipelines:
- A pipeline which runs against a code project over at the sonarqube-jacoco-code-coverage GitHub repository. The code here is decent enough that the pipeline should pass.
- A pipeline which runs against the same project, but uses the bad-code branch. The code here is so bad that the pipeline should fail.
Good code pipeline
Back in Jenkins click New Item and give it a name of sonarqube-good-code, select the Pipeline job type, then click OK.
Scroll down to the Pipeline section of the configuration page and enter the following declarative pipeline script in the Script textbox:
pipeline { agent any stages { stage('Clone sources') { steps { git url: 'https://github.com/tkgregory/sonarqube-jacoco-code-coverage.git' } } stage('SonarQube analysis') { steps { withSonarQubeEnv('SonarQube') { sh "./gradlew sonarqube" } } } stage("Quality gate") { steps { waitForQualityGate abortPipeline: true } } } }
The script has three stages:
- in the Clone sources stage code is cloned from the GitHub repository mentioned earlier
- in the SonarQube analysis stage we use the
withSonarQubeEnv('Sonarqube')
method exposed by the plugin to wrap the Gradle build of the code repository. This provides all the configuration required for the build to know where to find SonarQube. Note that the project build itself must have a way of running SonarQube analysis, which in this case is done by running./gradlew sonarqube
. For more information about running SonarQube analysis in a Gradle build see this article - in the Quality gate stage we use the
waitForQualityGate
method exposed by the plugin to wait until the SonarQube server has called the Jenkins webhook. TheabortPipeline
flag means if the SonarQube analysis result is a failure, we abort the pipeline.
Click Save to save the pipeline.
SonarQube magic: all the withSonarQubeEnv
method does is export some environment variables that the project's build understands. By adding a pipeline step which runs the command printenv
wrapped in withSonarQubeEnv
, you'll be able to see environment variables such as SONAR_HOST_URL
being set. These get picked up by the Gradle build of the code project to tell it which SonarQube server to connect to.
Bad code pipeline
Create another pipeline in the same way, but name it sonarqube-bad-code. The pipeline script is almost exactly the same, except this time we need to check out the bad-code branch of the same repository.
pipeline { agent any stages { stage('Clone sources') { steps { git branch: 'bad-code', url: 'https://github.com/tkgregory/sonarqube-jacoco-code-coverage.git' } } stage('SonarQube analysis') { steps { withSonarQubeEnv('SonarQube') { sh "./gradlew sonarqube" } } } stage("Quality gate") { steps { waitForQualityGate abortPipeline: true } } } }
- in the Clone sources stage we're now also specifying the
branch
attribute to point to the bad-code branch
Again, click Save.
You should now have two Jenkins jobs waiting to be run.
Any guesses as to what we're going to do next?
SonarQube analysis and quality gate stages in action
Yes, that's right, now it's time to run our pipelines! ✅
Let's run the sonarqube-good-code pipeline first.
You should get a build with all three stages passing.
If we head over to SonarQube we can see that indeed our project has passed the quality gate.
Now let's run the sonarqube-bad-code pipeline. Remember this is running against some really bad code!
You'll be able to see that the Quality gate stage of the pipeline has failed. Exactly what we wanted, blocking any future progress of this pipeline.
In the build's Console Output you'll see the message ERROR: Pipeline aborted due to quality gate failure: ERROR
which shows that the pipeline failed for the right reason.
Over in SonarQube you'll see that this time it's reporting a Quality Gate failure.
Looks like we got some code smells on our hands!
Click on the project name for more details.
We can see that the maintainability rating has dropped to B because of the two code smells. This doesn't meet our quality gate, which requires a minimum A rating.
Final thoughts
You've seen that integrating SonarQube quality gates into Jenkins is straightforward using the SonarQube Scanner Jenkins plugin. To apply this to a production setup, I suggest also to:
- remove the
SONAR_FORCEAUTHENTICATION
environment variable from SonarQube & configure the webhook in Jenkins to require an authentication token (see the SonarQube Scanner plugin configuration) - consider running SonarQube analysis on feature branches, so developers get early feedback on whether their code changes are good before merging into master. However, multi-branch analysis does require a paid subscription to SonarQube.
For full details about setting up SonarQube analysis in a Gradle code project, see How To Measure Code Coverage Using SonarQube and Jacoco. If you're using Maven, check out this documentation from SonarQube.
Video
Check out the accompanying video on the Tom Gregory Tech YouTube channel.
Resources
- the sonarqube-jenkins-example repository includes the example outlined in this article. Most of the manual steps from this article have been automated through configuration-as-code. All you need to do is configure SonarQube as described in the Configure SonarQube section.
- the SonarQube Scanner Jenkins plugin documentation has some useful details
hoffmancourbeacced.blogspot.com
Source: https://tomgregory.com/sonarqube-quality-gates-in-jenkins-build-pipeline/
0 Response to "Can I Continue the Build From Preivous Point in Jenkins"
Post a Comment