How can I integrate SonarQube Quality Gate into my Jenkins pipeline? - jenkins

I am executing in a pipeline a command to pass the sound of a project, what I need is that, just like in a normal job the sonar link remains once the job is executed, the same happens in the pipeline, now that when I run it in the pipeline, the SonarQube link is not saved, so I have the steps in groovy:
stage ('QA'){
steps {
echo 'executing sonar'
bat 'mvn sonar:sonar -Dsonar.host.url='+env.SONAR_URL+' -
Dsonar.projectName=QA:%JOB_BASE_NAME% -
Dsonar.projectKey=QA:%JOB_BASE_NAME%'
}
}
stage("Quality Gate"){
timeout(time: 1, unit: 'HOURS') { // Just in case something goes wrong, pipeline will be killed after a timeout
def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}

Try replacing with:
stage ('QA'){
steps {
echo 'Running SonarQube..'
withSonarQubeEnv('XXXXXXXX') {
bat 'mvn sonar:sonar -Dsonar.host.url='+env.SONAR_URL+' -
Dsonar.projectName=QA:%JOB_BASE_NAME% -
Dsonar.projectKey=QA:%JOB_BASE_NAME%'
timeout(time: 1, unit: 'HOURS') {
script {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to a quality gate failure: ${qg.status}"
}
}
}
}
}
}
Note that the XXXXXXXX should be replaced with the name of a Sonar config you've entered in Jenkins under Manage Jenkins>Configure System>SonarQube servers

Related

Error "Unknown stage section" while integrating sonarqube with jenkins using scripted pipeline

I have been trying to integrate sonarqube with Jenkins. It was working fine until I used scripted pipeline to return the quality gate status.
The code I am writing is:
pipeline {
agent any
stages {
stage("Git checkout") {
steps {
git 'https://github.com/AmolMandloi/junit-java-example.git'
}
}
stage("Maven") {
steps {
bat "mvn clean package test"
}
}
stage("Sonar") {
steps {
withSonarQubeEnv('sonar'){
bat 'mvn sonar:sonar'
}
}
}
stage("Quality Gate"){
timeout(time: 1, unit: 'HOURS') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
stage("Postsonar") {
steps{
bat 'echo "All done"'
}
}
}}
The error is in the Quality Gate stage because without it all is working fine.enter image description here
This is the error:
Started by user Amol Mandloi
Running in Durability level: MAX_SURVIVABILITY
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 21: Unknown stage section "timeout". Starting with version 0.5, steps in a stage must be in a ‘steps’ block. # line 21, column 9.
stage("Quality Gate"){
^
WorkflowScript: 21: Expected one of "steps", "stages", or "parallel" for stage "Quality Gate" # line 21, column 9.
stage("Quality Gate"){
^
2 errors
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1085)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:142)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:127)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:561)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:522)
at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:337)
at hudson.model.ResourceController.execute(ResourceController.java:97)
at hudson.model.Executor.run(Executor.java:428)
Finished: FAILURE
stage("Quality Gate"){
timeout(time: 1, unit: 'HOURS') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
In declarative pipeline, timeout is not valid directly under stage. You can either use it as an option or as a step.
In any case you need a script step for a scripted section within a declarative pipeline.
Timeout option
stage("Quality Gate"){
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
script {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
This syntax is more readable when the timeout applies to everything within the stage.
Timeout step
stage("Quality Gate"){
steps {
script {
timeout(time: 1, unit: 'HOURS') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
}
This syntax is necessary when the timeout applies only to parts of the stage. In your case I would go with the timeout option for a more declarative, readable approach.

Sonar Qube Quality Gates plugin in Jenkins pipline

i've installed and configure a SonanarQube Qualuity Gates plugin and successfully configured it in a non-pipline job. But when u try to configure it in pipline i face an different errors, when i try to make pipline like this:
stage ("SonarQube analysis") {
dir('source') {
def scannerHome = tool 'sonscanner';
withSonarQubeEnv('sonar'){
timeout(time: 1, unit: 'HOURS');
withSonarQubeEnv('sonar'){
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
}
}
i see this:
java.lang.IllegalStateException: There is no body to invoke
at org.jenkinsci.plugins.workflow.cps.CpsStepContext.newBodyInvoker(CpsStepContext.java:283)
at org.jenkinsci.plugins.workflow.cps.CpsStepContext.newBodyInvoker(CpsStepContext.java:95)
at org.jenkinsci.plugins.workflow.steps.TimeoutStepExecution.start(TimeoutStepExecution.java:46)
When as separate step after SonarQube analytics :
stage("Quality Gate"){
timeout(time: 1, unit: 'HOURS') { // Just in case something goes wrong, pipeline will be killed after a timeout
def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
if (qg.status != 'OK') {error "Pipeline aborted due to quality gate failure: ${qg.status}"
} else {
echo 'Quality Gate PASSED'
}
}
}
Than
java.lang.IllegalStateException: Unable to get SonarQube task id and/or server name. Please use the 'withSonarQubeEnv' wrapper to run your analysis.
at org.sonarsource.scanner.jenkins.pipeline.WaitForQualityGateStep$Execution.processStepParameters(WaitForQualityGateStep.java:125)
at org.sonarsource.scanner.jenkins.pipeline.WaitForQualityGateStep$Execution.start(WaitForQualityGateStep.java:107)
at org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:224)
at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:150)
at org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:108)
And when pipline :
stage ("SonarQube analysis") {
dir('source') {
def scannerHome = tool 'sonscanner';
withSonarQubeEnv('sonar'){
sh "${scannerHome}/bin/sonar-scanner -Dsonar.projectKey=android -Dsonar.sources='${WORKSPACE}'/source -Dsonar.language=java -Dsonar.projectBaseDir='${WORKSPACE}'/source -Dsonar.java.binaries='${WORKSPACE}'/source/app/build/intermediates/classes/debug -Dsonar.junit.reportsPath='${WORKSPACE}'/sourceapp/build/test-results/testDebugUnitTest"
}
}
}
stage("Quality Gate"){
timeout(time: 1, unit: 'HOURS') { // Just in case something goes wrong, pipeline will be killed after a timeout
def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
if (qg.status != 'OK') {error "Pipeline aborted due to quality gate failure: ${qg.status}"
} else {
echo 'Quality Gate PASSED'
}
}
}
This:
Caused: java.lang.IllegalStateException: Unable to parse response from https://sonar//api/ce/task?id=AWCYPE3v1VuUrqmUzLyR:
Unable to parse response from https://sonar//api/ce/task?id=AWCYPE3v1VuUrqmUzLyR:
Note the double // in the url. You can fix this easily, by removing the trailing slash in the configuration of the plugin on Jenkins.
In Jenkins:
Manage Jenkins
Configure System
Scrol to the section called SonarQube servers
Remove the trailing \ from the Server URL ;)
It should look something like this:
https://sonarcloud.io
NOT
https://sonarcloud.io/

No such DSL method 'waitForQualityGate' found among steps

I have problem with method waitForQualityGate(). I got an error "No such DSL method 'waitForQualityGate' found among steps". Another strange thing is that I must use parameter -DX for sonarscanner. I don't know what is wrong. Thanks for help.
pipeline {
agent { label 'builders' }
tools {
maven 'maven 3.3.9'
}
stages {
stage ('Checkout'){
steps {
git branch: 'develop', credentialsId: 'credential', url: 'ssh://repository'
}
}
stage ('Build'){
steps {
withMaven (
maven: 'maven 3.3.9',
mavenSettingsConfig: 'cc86690e-095d-4714-92b2-b61861241c7a'){
sh 'mvn -U clean package -DskipTests'
}
}
}
stage ('SonarQube Scan'){
steps {
withSonarQubeEnv('SonarQube') {
withMaven (
maven: 'maven 3.3.9',
mavenSettingsConfig: 'cc86690e-095d-4714-92b2-b61861241c7a'){
sh 'mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar ' +
'-DX' +
'-Dsonar.login=login' +
'-Dsonar.password=password' +
'-Dsonar.issuesReport.json.enable=true' +
'-Dsonar.report.export.path=sonar-report.json'
}
} // SonarQube taskId is automatically attached to the pipeline context
}
}
stage ('Quality Gate') {
steps {
timeout(time: 1, unit: 'HOURS') { // Just in case something goes wrong, pipeline will be killed after a timeout
script {
def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
}
}
}
}
This will not be an immediate answer, but the reason for the error is, you are calling a custom method without even loading it initially. Load the groovy file that have the method, which jenkins is complaining that dsl doesn't exist... only when you load the groovy file/the class, then you can instantiate it.
Cannot do this, without loading it ... def qg = waitForQualityGate()
If its a method, u have to call it and it should return something...

waitForQualityGate() with Sonar scanner for MSbuild

Is there any way to break Jenkins build when Sonar quality gate fails with waitForQualityGate() method along with Sonar Scanner for MSbuild? I could not find any documentation for the same. All I could find is the usage of waitForQualityGate() along with Sonar scanner, but the general sonar scanner is not recommended for MSbuild projects.
The below mentioned link does not talk about usage waitForQualityGate with MSBuild.
https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+Jenkins#AnalyzingwithSonarQubeScannerforJenkins-AnalyzinginaJenkinspipeline
That documentation talks about Sonar Scanner, but I am referring to Sonar scanner for MSbuild which is a different scanner altogether. The way I use this scanner is as shown below.
void beginSonarMSBuild(String VERSION){
stage('Begin Sonar Analysis') {
def MSBuildScannerHome = tool 'sonar-scanner-msbuild-3.0.0.629';
withSonarQubeEnv('civil sonar') {
bat "${MSBuildScannerHome}\\SonarQube.Scanner.MSBuild.exe begin /k:mcdc
/n:mc-design-converter /v:${VERSION}.$BUILD_NUMBER /d:sonar.sourceEncoding=UTF-8
}
}
}
void build(){
stage ('Build'){
bat "Nuget restore SOMEHTING.sln"
bat "MSBuild.exe SOMETHING.csproj "
}
}
void endSonarMSBuild(){
stage ('Complete Sonar Analysis'){
def MSBuildScannerHome = tool 'sonar-scanner-msbuild-3.0.0.629';
bat "${MSBuildScannerHome}\\SonarQube.Scanner.MSBuild.exe end"
}
}
Now when I use waitforqualitygate() with beginSonarMSBuild(String VERSION)as shown below:
void beginSonarMSBuild(String VERSION){
stage('Begin Sonar Analysis') {
def MSBuildScannerHome = tool 'sonar-scanner-msbuild-3.0.0.629';
withSonarQubeEnv('civil sonar') {
bat "${MSBuildScannerHome}\\SonarQube.Scanner.MSBuild.exe begin /k:mcdc
/n:mc-design-converter /v:${VERSION}.$BUILD_NUMBER /d:sonar.sourceEncoding=UTF-8
}
}
stage("Quality Gate"){
timeout(time: 1, unit: 'MINUTES') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
void build(){
scripts here...
}
void endSonarMSBuild(){
scripts here...
}
I get this error msg java.lang.IllegalStateException: Unable to get SonarQube task id and/or server name. Please use the 'withSonarQubeEnv' wrapper to run your analysis.
Also I get the same error when I use waitForQualityGate() with endSonarMSBuild() step as shown below.
void beginSonarMSBuild(String VERSION){
stage('Begin Sonar Analysis') {
scripts here...
}
void build(){
scripts here...
}
void endSonarMSBuild(){
stage ('Complete Sonar Analysis'){
def MSBuildScannerHome = tool 'sonar-scanner-msbuild-3.0.0.629';
bat "${MSBuildScannerHome}\\SonarQube.Scanner.MSBuild.exe end"
}
stage("Quality Gate"){
timeout(time: 1, unit: 'MINUTES') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
}
So the question I have is, does Sonar scanner for MSBuild even support waitForQualityGate(), if yes, then how to use the same?
On the documentation, the example is made with the scanner for Maven but it should work fine with any scanner as long as you wrap it in a withSonarQubeEnv step.
For the scanner for MSBuild, it is important to wrap the end step (but wrapping the begin step is also a good idea to automatically pass credentials.
void beginSonarMSBuild(String VERSION) {
stage('Begin SonarQube Analysis') {
def MSBuildScannerHome = tool 'sonar-scanner-msbuild-3.0.0.629';
withSonarQubeEnv('civil sonar') {
bat "${MSBuildScannerHome}\\SonarQube.Scanner.MSBuild.exe begin /k:mcdc
/n:mc-design-converter /v:${VERSION}.$BUILD_NUMBER /d:sonar.sourceEncoding=UTF-8
}
}
}
void build() {
stage ('Build') {
bat "Nuget restore SOMEHTING.sln"
bat "MSBuild.exe SOMETHING.csproj"
}
}
void endSonarMSBuild() {
stage ('Complete SonarQube Analysis') {
withSonarQubeEnv('civil sonar') {
def MSBuildScannerHome = tool 'sonar-scanner-msbuild-3.0.0.629';
bat "${MSBuildScannerHome}\\SonarQube.Scanner.MSBuild.exe end"
} // Will collect task id
}
stage("Quality Gate"){
timeout(time: 1, unit: 'MINUTES') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
}

How to react on SonarQube Quality Gate within Jenkins Pipeline

Within my Jenkins Pipeline I need to react on the SonarQube Quality Gate.
Is there an easier way to achieve this but looking in the Sonar-Scanner log for the result page (e.g. https://mysonarserver/sonar/api/ce/task?id=xxxx) and parse the JSON Result from there?
I use Jenkins 2.30 and SonarQube 5.3
Thanks in advance
Based on Vincent's answer, and using Pipeline utility steps, here's my updated version that worked for me (using sonarscanner report file) :
withSonarQubeEnv('SONAR 6.4') {
sh "${scannerHome}/bin/sonar-scanner"
sh "cat .scannerwork/report-task.txt"
def props = readProperties file: '.scannerwork/report-task.txt'
echo "properties=${props}"
def sonarServerUrl=props['serverUrl']
def ceTaskUrl= props['ceTaskUrl']
def ceTask
timeout(time: 1, unit: 'MINUTES') {
waitUntil {
def response = httpRequest ceTaskUrl
ceTask = readJSON text: response.content
echo ceTask.toString()
return "SUCCESS".equals(ceTask["task"]["status"])
}
}
def response2 = httpRequest url : sonarServerUrl + "/api/qualitygates/project_status?analysisId=" + ceTask["task"]["analysisId"], authentication: 'jenkins_scanner'
def qualitygate = readJSON text: response2.content
echo qualitygate.toString()
if ("ERROR".equals(qualitygate["projectStatus"]["status"])) {
error "Quality Gate failure"
}
}
Please note the use of a Jenkins Credentials (authentication: 'jenkins_scanner') to retrieve the quality gate in Sonar being auhtenticated.
Using SonarQube Scanner for Jenkins 2.8.1 the solution is available out of the Box:
stage('SonarQube analysis') {
withSonarQubeEnv('My SonarQube Server') {
sh 'mvn clean package sonar:sonar'
} // SonarQube taskId is automatically attached to the pipeline context
}
}
stage("Quality Gate"){
timeout(time: 1, unit: 'HOURS') { // Just in case something goes wrong, pipeline will be killed after a timeout
def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv
if (qg.status != 'OK') {
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
Scan first:
node("sonar") {
deleteDir()
unstash 'sources'
def scannerHome = tool 'sonar-scanner';
withSonarQubeEnv('sonarqube-rec') {
withEnv(["JAVA_HOME=${ tool 'JDK_8.0' }", "PATH+MAVEN=${tool 'M325'}/bin:${env.JAVA_HOME}/bin"]) {
// requires SonarQube Scanner for Maven 3.2+
sh '''
mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.2:sonar
echo "SONAR_AUTH_TOKEN=$SONAR_AUTH_TOKEN" >> target/sonar/report-task.txt
'''
stash includes: "target/sonar/report-task.txt", name: 'sonar-report-task'
}
}
}
then check the quality gate:
stage("Quality Gate"){
node("sonar") {
deleteDir()
unstash 'sonar-report-task'
def props = utils.getProperties("target/sonar/report-task.txt")
echo "properties=${props}"
def sonarServerUrl=props.getProperty('serverUrl')
def ceTaskUrl= props.getProperty('ceTaskUrl')
def ceTask
def URL url = new URL(ceTaskUrl)
timeout(time: 1, unit: 'MINUTES') {
waitUntil {
ceTask = utils.jsonParse(url)
echo ceTask.toString()
return "SUCCESS".equals(ceTask["task"]["status"])
}
}
url = new URL(sonarServerUrl + "/api/qualitygates/project_status?analysisId=" + ceTask["task"]["analysisId"] )
def qualitygate = utils.jsonParse(url)
echo qualitygate.toString()
if ("ERROR".equals(qualitygate["projectStatus"]["status"])) {
error "Quality Gate failure"
}
}
}
I used ".sonar/report-task.txt" to retrieve the ceTaskUrl - Then I used Pipeline Shared Libraries and wrote my own Pipeline Function to retrieve the quality gate.
http://mySonarQube.com:9001/api/ce/task?id="ceTaskUrl"
Parse "task.analysisId"
Parse quality-gates from http://mySonarQube.com:9001/api/qualitygates/project_status?analysisId="task.analysisId"

Resources