Set the build unstable if sonar Quality Gate is failed - jenkins

I have a very simple pipeline. Everything is defined in my pom.xml files and .m2/settings.xml. I want to set my build as instable on Jenkins when SonarQube's Quality Gate is failed. Here is what I did but I have several errors like "expected }". Does anyone know how it works ?
Note that the environment part is optional.
Thank you.
pipeline {
agent {
label "master"
}
tools {
// Note: this should match with the tool name configured in your jenkins instance (JENKINS_URL/configureTools/)
maven "Maven 3.6.0"
jdk 'Java 1.8'
}
environment {
// This can be nexus3 or nexus2
NEXUS_VERSION = "nexus3"
// This can be http or https
NEXUS_PROTOCOL = "http"
// Where your Nexus is running
NEXUS_URL = "192.168.1.8:8081"
// Repository where we will upload the artifact
NEXUS_REPOSITORY = "repository-example"
// Jenkins credential id to authenticate to Nexus OSS
NEXUS_CREDENTIAL_ID = "nexus-credentials"
}
stages {
stage ('Initialize') {
steps {
sh '''
echo "PATH = ${PATH}"
echo "M2_HOME = ${M2_HOME}"
'''
}
}
stage("mvn clean deploy") {
steps {
script {
// If you are using Windows then you should use "bat" step
// Since unit testing is out of the scope we skip them
sh "mvn -B clean deploy"
}
}
}
stage ("SonarQube check") {
steps {
script {
sh 'mvn -B sonar:sonar'
}
step {
qualitygate = waitForQualityGate()
if (qualitygate.status != "OK") {
currentBuild.result = "UNSTABLE"
}
}
}
}
}
}

You need to wrap the qualitygate stuff and all inside a script block as shown below:
stage ("SonarQube check") {
steps {
script {
sh 'mvn -B sonar:sonar'
qualitygate = waitForQualityGate()
if (qualitygate.status != "OK") {
currentBuild.result = "UNSTABLE"
}
}
}
}

Related

Skip Stages in Jenkins shared library based on repository

I have a common Jenkins shared library for all the repositories as below.
vars/_publish.groovy
pipeline {
environment {
abc= credentials(’abc')
def= credentials(‘def’)
}
stages {
stage('Build') {
steps{
sh ‘docker build'
}
}
stage('Unit-test') {
steps{
sh ‘mvn test'
}
}
jenkinsfile
#Library('my-shared-library#branch') _
_publish() {
}
I have 10 Repository each has its own Jenkinsfile as shown above which refers to the jenkins shared library(vars/_publish.groovy). I have a condition here that I need to Pass. For few repository I want to skip the Unit test and just execute the build stage. For rest other repository I want both the stages. Is there anyone I can skip the particular stage based on the repository or repository name
Yes it's possible you can use when expression like this
pipeline {
agent any
stages {
stage('Test') {
when { expression { return repositoryName.contains('dev') } } <---------Add put your repository name 'dev' so whenever the repository names is ''dev' then execute this stage
steps {
script {
}
}
}
}
}
def repositoryName() {
def repositoryName = ['dev', 'test'] <----Add here the 10 repo name
return repositoryName
}
Here in my case repo names are dev and test so you can add yours accondigly
I would decorate my shared library and Jenkinsfile like this to achieve your scenario.
vars/_publish.groovy
def call(body={}) {
def pipelineParams = [:]
body.resolveStrategy = Closure.DELEGATE_FIRST
body.delegate = pipelineParams
body()
pipeline {
agent any;
stages {
stage('build') {
steps {
echo "BUILD"
}
}
stage('unitest') {
when {
anyOf {
equals expected: true, actual: pipelineParams.isEmpty();
equals expected: false, actual: pipelineParams.skipUnitest
}
}
steps {
echo "UNITEST"
}
}
}
}
}
I am enabling my shared library to accept parameter from Jenkinsfile and with when{} DSL deciding whether to skip unitest stage or not
Jenkinsfile
If your Jenkins file from the repo has below details, will skip the unitest stage
#Library('jenkins-shared-library')_
_publish(){
skipUnitest = true
}
below both scenario will run the unitest stage
#Library('jenkins-shared-library')_
_publish(){
skipUnitest = false
}
and
#Library('jenkins-shared-library')_
_publish(){
}

How to install .NetCore dotnet (not MSBuid plugin) to Jenkins

I was assigned to create CI/CD workflow for our project combining Openshift + Jenkins pipeline. I can build by using following:
stage('build') {
steps {
script {
openshift.withCluster() {
openshift.withProject() {
def buildSelector = openshift.selector("bc", "test")
buildSelector.startBuild()
buildSelector.logs('-f')
}
}
} // script
} // steps
} // stage
But I want to also use dotnet restore and other commands but pipeline returns:
/var/lib/jenkins/jobs/test-namespace/jobs/test-pipeline/workspace#tmp/durable-4265d26a/script.sh: line 1: dotnet: command not found
also when trying to use
agent {
docker { image 'mcr.microsoft.com/dotnet/aspnet:3.1' }
}
/var/lib/jenkins/jobs/test-namespace/jobs/test-pipeline/workspace#tmp/durable-4265d26a/script.sh: line 1: docker: command not found
This is my current script
pipeline {
agent {
node {
label ''
}
}
options {
// set a timeout of 20 minutes for this pipeline
timeout(time: 20, unit: 'MINUTES')
}
stage('build') {
steps {
script {
openshift.withCluster() {
openshift.withProject() {
def buildSelector = openshift.selector("bc", "test")
buildSelector.startBuild()
buildSelector.logs('-f')
}
}
} // script
} // steps
} // stage
stage('clean'){
steps {
script{
echo "${workspace} I want to call dotnet clean"
}
} // steps
} // stage
stage('restore'){
steps {
script{
echo "${workspace} I want to call dotnet restore"
}
} // steps
} // stage
stage('tests'){
steps {
script{
echo "${workspace} I want to call dotnet test *.sln"
}
} // steps
} // stage
stage('deploy') {
steps {
script {
openshift.withCluster() {
openshift.withProject() {
def deploySelector = openshift.selector("dc", "test")
deploySelector.startDeploy()
deploySelector.logs('-f')
}
}
} // script
} // steps
} // stage
}
}
How can I install those binaries to Jenkins? I am using minishift on MacOS.

Is it possible to check if checked out from a specific repository in a Jenkins declarative pipeline?

I would like to have a release stage in my Jenkinsfile that only runs when it's checked out from the original repository. This is to avoid error messages on cloned repositories, because of missing keys etc. there.
stage('Release')
{
when
{
allOf
{
// TODO Check for repository url https://github.com/PowerStat/TemplateEngine.git
branch 'master'
}
}
steps
{
script
{
if (isUnix())
{
sh 'mvn --batch-mode release:clean'
sh 'mvn --batch-mode release:prepare'
sh 'mvn --batch-mode release:perform'
}
else
{
bat 'mvn --batch-mode release:clean'
bat 'mvn --batch-mode release:prepare'
bat 'mvn --batch-mode release:perform'
}
}
}
}
I have studied Pipeline Syntax: when but have no idea how to do the test I would like to have.
Also I thought about using an environment variable Global Variable Reference, but found non with the repository URL in it.
So my question is: how to implement this check in a decalarative pipeline?
You can get remote repository URL from git config remote.origin.url command. You can execute this command using expression directive inside the when block - it defines a closure that returns a boolean value.
Consider the following example:
def expectedRemoteUrl = "https://github.com/PowerStat/TemplateEngine.git"
pipeline {
agent any
stages {
stage("Release") {
when {
allOf {
branch 'tmp'
expression {
def remoteUrl = isUnix() ?
sh(script: "git config remote.origin.url", returnStdout: true)?.trim() :
bat(script: "git config remote.origin.url", returnStdout: true)?.trim()
return expectedRemoteUrl == remoteUrl
}
}
}
steps {
echo "Do your release steps here..."
}
}
}
}
Alternatively, if git command is not available in the node that runs the pipeline, you can get the remote repository URL with scm.userRemoteConfigs?.first()?.url. Consider the following example:
def expectedRemoteUrl = "https://github.com/PowerStat/TemplateEngine.git"
pipeline {
agent any
stages {
stage("Release") {
when {
allOf {
branch 'tmp'
expression {
def remoteUrl = scm.userRemoteConfigs?.first()?.url
return expectedRemoteUrl == remoteUrl
}
}
}
steps {
echo "Do your release steps here..."
}
}
}
}

Declarative pipeline to check the build step = Failure then trigger next build step, but not fail the job.

I am trying to fail a build step in Jenkinsfile with failed results = failure. Once the step is failed it triggers my rollback job. Tried many different things, but had no luck. Any help would be greatly appreciated.
pipeline {
agent any
stages {
stage('Git Checkout') {
steps {
script {
git 'somegit-repo'
sh'''
mvn package
'''
echo currentBuild.result
catchError {
build 'rollback'
}
}
}
}
}
One way is to use a shell script and with exit 1 statement
e.g.
sh "exit 1"
Or you can use error step
error('Failing build because...')
See https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#error-error-signal
Use a try catch block
node {
stage("Run scripts") {
try {
<some command/script>
} catch (error) {
<rollback command/script>
}
}
}
Thank you so much. This seems to work!
stages {
stage("some test") {
steps{
script {
git 'mygitrepo.git'
try {
sh''' mvn test '''
} catch (error) {
script {
def job = build job: 'rollback-job'
}
}
}
}
}
If you check the cleaning and notifications page
You can do a post step and get rid of all the try/catch stuff and get a cleaner Jenkinsfile
pipeline {
agent any
stages {
stage('No-op') {
steps {
sh 'ls'
}
}
}
post {
always {
echo 'One way or another, I have finished'
deleteDir() /* clean up our workspace */
}
success {
echo 'I succeeeded!'
}
unstable {
echo 'I am unstable :/'
}
failure {
echo 'I failed :('
}
changed {
echo 'Things were different before...'
}
}
}

Declarative pipeline when condition in post

As far as declarative pipelines go in Jenkins, I'm having trouble with the when keyword.
I keep getting the error No such DSL method 'when' found among steps. I'm sort of new to Jenkins 2 declarative pipelines and don't think I am mixing up scripted pipelines with declarative ones.
The goal of this pipeline is to run mvn deploy after a successful Sonar run and send out mail notifications of a failure or success. I only want the artifacts to be deployed when on master or a release branch.
The part I'm having difficulties with is in the post section. The Notifications stage is working great. Note that I got this to work without the when clause, but really need it or an equivalent.
pipeline {
agent any
tools {
maven 'M3'
jdk 'JDK8'
}
stages {
stage('Notifications') {
steps {
sh 'mkdir tmpPom'
sh 'mv pom.xml tmpPom/pom.xml'
checkout([$class: 'GitSCM', branches: [[name: 'origin/master']], doGenerateSubmoduleConfigurations: false, submoduleCfg: [], userRemoteConfigs: [[url: 'https://repository.git']]])
sh 'mvn clean test'
sh 'rm pom.xml'
sh 'mv tmpPom/pom.xml ../pom.xml'
}
}
}
post {
success {
script {
currentBuild.result = 'SUCCESS'
}
when {
branch 'master|release/*'
}
steps {
sh 'mvn deploy'
}
sendNotification(recipients,
null,
'https://link.to.sonar',
currentBuild.result,
)
}
failure {
script {
currentBuild.result = 'FAILURE'
}
sendNotification(recipients,
null,
'https://link.to.sonar',
currentBuild.result
)
}
}
}
In the documentation of declarative pipelines, it's mentioned that you can't use when in the post block. when is allowed only inside a stage directive.
So what you can do is test the conditions using an if in a script:
post {
success {
script {
if (env.BRANCH_NAME == 'master')
currentBuild.result = 'SUCCESS'
}
}
// failure block
}
Using a GitHub Repository and the Pipeline plugin I have something along these lines:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh '''
make
'''
}
}
}
post {
always {
sh '''
make clean
'''
}
success {
script {
if (env.BRANCH_NAME == 'master') {
emailext (
to: 'engineers#green-planet.com',
subject: "${env.JOB_NAME} #${env.BUILD_NUMBER} master is fine",
body: "The master build is happy.\n\nConsole: ${env.BUILD_URL}.\n\n",
attachLog: true,
)
} else if (env.BRANCH_NAME.startsWith('PR')) {
// also send email to tell people their PR status
} else {
// this is some other branch
}
}
}
}
}
And that way, notifications can be sent based on the type of branch being built. See the pipeline model definition and also the global variable reference available on your server at http://your-jenkins-ip:8080/pipeline-syntax/globals#env for details.
Ran into the same issue with post. Worked around it by annotating the variable with #groovy.transform.Field. This was based on info I found in the Jenkins docs for defining global variables.
e.g.
#!groovy
pipeline {
agent none
stages {
stage("Validate") {
parallel {
stage("Ubuntu") {
agent {
label "TEST_MACHINE"
}
steps {{
sh "run tests command"
recordFailures('Ubuntu', 'test-results.xml')
junit 'test-results.xml'
}
}
}
}
}
post {
unsuccessful {
notify()
}
}
}
// Make testFailures global so it can be accessed from a 'post' step
#groovy.transform.Field
def testFailures = [:]
def recordFailures(key, resultsFile) {
def failures = ... parse test-results.xml script for failures ...
if (failures) {
testFailures[key] = failures
}
}
def notify() {
if (testFailures) {
... do something here ...
}
}

Resources