Execute SonarQube Scanner within Jenkins 2 Pipeline - jenkins

I want to execute a "SonarQube Scanner" Step within my Jenkins 2.x Pipeline.
When I try to create a sample groovy within the pipeline-syntax I only get a groovy script of the following format:
step <object of type hudson.plugins.sonar.SonarRunnerBuilder>
Does anyone know what is the correct Step Syntax? E.g. Publish JUnit Report looks like
step([$class: 'JUnitResultArchiver', testResults: ''])
I use the following Versions:
Jenkins 2.11
SonarQube Scanner 2.6.1
SonarQube Plugin 2.4.1

I think I got it.
First you have to retrieve your SonarQube Scanner Tool
def sonarqubeScannerHome = tool name: 'SonarQubeScanner', type: 'hudson.plugins.sonar.SonarRunnerInstallation'
Then you can call sonar-scanner via Shell:
sh "${sonarqubeScannerHome}/bin/sonar-scanner -e -Dsonar.host.url=..."

env.sonarHome= tool name: 'scanner-2.4', type: 'hudson.plugins.sonar.SonarRunnerInstallation'
withSonarQubeEnv('sonar.installation') { // from SonarQube servers > name
sh "${sonarHome}/bin/sonar-runner -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_AUTH_TOKEN} -Dsonar.projectName=xxx -Dsonar.projectVersion=xxx -Dsonar.projectKey=xxx -Dsonar.sources=."
}

You can, instead, just provide the full path to ur sonar-runner. As shown in the below snippet.
def runSonarScan(sonar_url){
withEnv(['SONAR_HOST=' + sonar_url]) {
sh '''
$/opt/sonarqube/sonar-runner-2.4/bin/sonar-runner -e -Dsonar.host.url=${SONAR_HOST}
'''
}
}
If you have specific sonar properties add them as a sonar-project.properties file as shown here Sonar Project Properties

Related

'.' is not recognized as an internal or external command for Gradle command in Jenkins when gradlew script is executed

I try to run SonarQube analysis for a Gradle project in a Jenkins Pipeline using the following code:
stage('SonarQube') {
withGradle {
withSonarQubeEnv('SonarQube Env') {
bat "./gradlew sonarqube"
}
}
}
The Gradle plugin is installed in Jenkins but I am getting the following error:
05:15:05 D:\*\*\*\*\*\*>./gradlew sonarqube
05:15:05 '.' is not recognized as an internal or external command,
Two things are incorrect in your code. On Windows machines you have to:
use backslashes instead of slashes in paths (./command → .\command)
execute script written for Windows (gradlew is a Unix script, gradlew.bat is a Windows script)
This code should work:
stage('SonarQube') {
withGradle {
withSonarQubeEnv('SonarQube Env') {
bat '.\\gradlew.bat sonarqube'
}
}
}
Gradle Wtapper by default is provided with two script gardlew and gradlew.bat. If your project doesn't have the gradlew.bat file, execute on your Unix machine ./gradlew wrapper. The missing file will be generated.
Btw. You don't need the Jenkins Gradle plugin, when you use Gradlew Wrapper. The plugin is required when you want to provide Gradle installations for jobs, example:
stage('SonarQube') {
withGradle {
withSonarQubeEnv('SonarQube Env') {
bat "${tool(name: 'toolId', type: 'gradle')}\\bin\\gradle.bat sonarqube"
}
}
}
toolId must much the identifiers used in the Jenkins Global Tool Configuration, examples: gradle-6.X, gradle-6.8.3 etc.

Running SonarQube scanner - Java/TypeScript

Checkout of front end & back end code in multiple folders within jenkin's ${WORKSPACE}
, as shown below
Frontend code is written in Angular(TypeScript) and built using npm
Backend code is written in Java and built using gradlew
Referring documentation for SonarQube scanner with Jenkins, here. I got the below piece of code to run SonarQube scanner for multi-language(angular & java) static code analysis
node {
stage('SCM') {
git 'https://github.com/foo/bar.git'
}
stage('SonarQube analysis') {
// requires SonarQube Scanner 2.8+
def scannerHome = tool 'SonarQube Scanner 2.8';
withSonarQubeEnv('My SonarQube Server') {
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
As per below screenshot, below is the sonar scanner installation in jenkins:
1) Does def scannerHome = tool 'abc_install'; grab the SonarQube scanner configured in Jenkins?
2) Does sh "${scannerHome}/bin/sonar-scanner" perform static code analysis for both TypeScript & Java? in front-end-code & backend-code folder
Please see answers:
1) Of course. In Jenkins you can configure many SonarQube scanners with different versions, and with construction def scannerHome = tool '<scanner name, configured in Jenkins>' you may grab any scanner your code need
2) Yes, it will. But, I'd recommend to split backend and frontend and specify language for each part. Also, I'd remove folders with with '#tmp' from static code scan. Please see list of parameters that can be added to scanner here: https://docs.sonarqube.org/latest/analysis/analysis-parameters/
Small example for backend:
${scannerHome}/bin/sonar-scanner \
-Dsonar.projectKey=project-${ENVIRONMENT} \
-Dsonar.sources=portal,common \
-Dsonar.java.binaries=portal,common \
-Dsonar.java.libraries=/**/*.jar \
-Dsonar.exclusions=portal/src/test/**,portal/src/intest/** \
-Dsonar.coverage.jacoco.xmlReportPaths=portal/build/reports/jacoco/test/jacocoTestReport.xml

SonarQube Scanner fails in a Jenkins pipeline due to command not found

I'd like to run SonarQube Scanner from a Jenkins pipeline and I followed the documentation.
Regarding the error, it seems that the scanner is present but some commands are not found. My jenkins instance runs in a docker.
Jenkins version : 2.46.1
SonarQube Scanner : 2.6.1
+ /var/lib/jenkins/tools/hudson.plugins.sonar.SonarRunnerInstallation/SonarQube_Scanner/bin/sonar-scanner
/var/lib/jenkins/tools/hudson.plugins.sonar.SonarRunnerInstallation/SonarQube_Scanner/bin/sonar-scanner: line 56: which: command not found
/var/lib/jenkins/tools/hudson.plugins.sonar.SonarRunnerInstallation/SonarQube_Scanner/bin/sonar-scanner: line 66: exec: : not found
In the sonar-scanner script, there is this block
if [ -n "$JAVA_HOME" ]
then
java_cmd="$JAVA_HOME/bin/java"
else
java_cmd="$(which java)"
fi
And given that my JAVA_HOME was unset, the script called which and the command is not installed inside my container.
As a workaround, I set the env variable JAVA_HOME.
Make sure the PATH is complete, or check if resetting it is enough
def sonarqubeScannerHome = tool name: 'SonarQubeScanner', type: 'hudson.plugins.sonar.SonarRunnerInstallation'
withEnv(["PATH=/usr/bin: ..."]) {
// Your call to Sonar
sh "${sonarqubeScannerHome}/bin/sonar-scanner -e -Dsonar.host.url=..."
}
I used the setup from "Execute SonarQube Scanner within Jenkins 2 Pipeline", but with Sonar 2.5, there is an official support of Jenkins pipeline:
def scannerHome = tool 'SonarQube Scanner 2.8';
withEnv(["PATH=/usr/bin: ..."]) {
withSonarQubeEnv('My SonarQube Server') {
sh "${scannerHome}/bin/sonar-scanner"
}
}

How to invoke Ant in a Jenkins Groovy Pipeline

I have created a Jenkins Pipeline job. In this job I want to do the build using Ant. I have configured the Ant variable in Manage **Jenkins > Global Tool Configuration** as Ant1.9.1= D:\path_to_hybris\hybris\bin\platform\apache-ant-1.9.1.
In a freestyle jenkins Job, I know that the build.xml location can be specified as in the below screenshot:
but I am unable to understand how to specify the ant groovy script beyond this point, especially where can we mention the path to build.xml file:
def antHome = tool 'Ant1.9.1'
????
????
you can use ant wrapper in Jenkins`s pipeline groovy script.
withAnt(installation: 'LocalAnt') {
// some block
sh "ant build"
//for windows
bat "ant build"
}
Remember to configure the ant tool in the Jenkins "Global Tool Configuration" with the same name "LocalAnt".
You can try this:
def antVersion = 'Ant1.9.1'
withEnv( ["ANT_HOME=${tool antVersion}"] ) {
sh '$ANT_HOME/bin/ant target1 target2'
}
Under Windows this would look like this (I didn't test it though):
def antVersion = 'Ant1.9.1'
withEnv( ["ANT_HOME=${tool antVersion}"] ) {
bat '%ANT_HOME%/bin/ant.bat target1 target2'
}
This assumes that you have Ant configured in Jenkins with name 'Ant1.9.1'.
I needed this multiple times within the same Jenkinsfile that needs to be executed on both linux and windows agents so I created a method for it.
You can call ant like this
callAnt("-v -p")
if you add this method definition to your jenkinsfile
def callAnt(String Parameters) {
if (isUnix()) {
env.PATH = "${tool 'ant'}/bin;${env.PATH}"
sh "ant ${Parameters}"
}
else {
env.PATH = "${tool 'ant'}\\bin;${env.PATH}"
bat "ant ${Parameters}"
}
}

Get gradle variables in jenkins pipeline script

I'm trying to migrate my build pipelines to the "Pipeline plugin" using the groovy build scripts.
My pipelines are usually:
Test (gradle)
IntegrationTest (gradle)
Build (gradle)
Publish (artifactory)
I would like to use the gradle variables like version/group etc. in my jenkins build script to publish to the correct folders in artifactory. Something the artifactory plugin would take care of for me in the past. How can this be achieved?
For a single gradle project I use something like this:
node('master')
{
def version = 1.0
def gitUrl = 'some.git'
def projectRoot = ""
def group = "dashboard/frontend/"
def artifactName = "dashboard_ui"
def artifactRepo = "ext-release-local"
stage "git"
git branch: 'develop', poll: true, url: "${gitUrl}"
dir(projectRoot)
{
sh 'chmod +x gradlew'
stage "test"
sh './gradlew clean test'
stage "build"
sh './gradlew build createPom'
stage "artifact"
def server = Artifactory.server('artifactory_dev01')
def uploadSpec = """{
"files": [
{
"pattern": "build/**.jar",
"target": "${artifactRepo}/$group/${artifactName}/${version}/${artifactName}-${version}.jar"
},
{
"pattern": "pom.xml",
"target": "${artifactRepo}/$group/${artifactName}/${version}/${artifactName}.pom"
}
]
}"""
def buildInfo1 = server.upload spec: uploadSpec
server.publishBuildInfo buildInfo1
}
}
For future reference here an example with the more modern declarative pipeline:
pipeline {
agent any
stages {
stage('somestage') {
steps {
script {
def version = sh (
script: "./gradlew properties -q | grep \"version:\" | awk '{print \$2}'",
returnStdout: true
).trim()
sh "echo Building project in version: $version"
}
}
}
}
}
see also:
Gradle plugin project version number
How to do I get the output of a shell command executed using into a variable from Jenkinsfile (groovy)?
I think you actually have two different approaches to tackle this problem :
1. Get version/group from sh script
Find a way to get Gradle version from gradle build tool (e.g. gradle getVersion(), but I'm not familiar with Gradle) and then use shell script to get this version. If Gradle command to get the version is gradle getVersion(), you would do in your pipeline :
def projectVersion = sh script: "gradle getVersion()", returnStdout: true
def projectGroup= sh script: "gradle getGroup()", returnStdout: true
and then just inject your $projectVersion and $projectGroup variables in your current pipeline.
2. Configure your Gradle build script to publish to Artifactory
This is the reverse approach, which I personnaly prefer : instead of giving Artifactory all your Gradle project information, juste give Gradle your Artifactory settings and use Gradle goal to easily publish to Artifactory.
JFrog has a good documentation for this solution in their Working with Gradle section. Basically, you will follow the following steps :
Generate a compliant Gradle build script from Artifactory using Gradle Build Script Generator and include it to your project build script
Use Gradle goal gradle artifactoryPublish to simply publish your current artifact to Artifactory
For others who Google'd their way here, if you have the Pipeline Utility Steps plugin and store what you need in your gradle.properties file, you can do something like this in the environment block:
MY_PROPS = readProperties file:"${WORKSPACE}/gradle.properties"
MY_VERSION = MY_PROPS['version']

Resources