Not receiving Failure email from Jenkins - jenkins

Using Jenkins now, this is my post build Pipeline:
pipeline {
agent any
stages {
stage('Stage 1') {
steps {
echo 'Hello this is stage 1'
}
}
stage('Stage 2') {
steps {
echo 'Still here? Well this is stage 2'
}
}
stage('Stage 3') {
steps {
echo 'Almost there ... stage 3'
}
}
stage('Stage 4 - Python') {
steps {
bat 'py atom_python_test.py'
}
}
stage('Stage 5 - Compile C++') {
steps {
catchError {
bat '''
cd C:\Program Files (x86)//Microsoft Visual Studio 12.0//VC
call vcvarsall
cd C://Users//praktikant3//Documents//Visual Studio 2013//Projects//FirstProjectBuiltOnJenkins//FirstProjectBuiltOnJenkins
dir
MSBuild.exe
echo 'Compile Stage successful'
'''
}
}
}
stage('Stage 6 - Build C++') {
steps {
bat '''
cd C://Program Files (x86)//Microsoft Visual Studio 12.0//VC
call vcvarsall
cd C://Users//praktikant3//Documents//Visual Studio 2013//Projects//FirstProjectBuiltOnJenkins//FirstProjectBuiltOnJenkins
dir
MSBuild.exe
'''
}
}
}
post {
success {
mail to: 'SomeEMAIL#company.com',
subject: "Succeeding Pipeline: ${currentBuild.fullDisplayName}",
body: "All is good with ${env.BUILD_URL}"
}
failure {
mail to: 'SomeEMAIL#company.com',
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
}
}
}
The build C++ part works because I the syntax is correct, however in previous attempt I had the directory change using "\" which was not working. I added a "Compile stage" using catchError and one of the cd with a "\" to see if I get notification of failure. From my understanding:
"You should wrap every step that can potentially fail into a catchError function. What this does is:
If an error occurs...
... set build.result to FAILURE...
... andcontinue the build "
but when I intentionally left the back slash the pipeline failed and stopped and the post block did not execute.

Related

Jenkins pipeline: Run all steps in stage, even if the first one fails

I have a series of steps in a stage that I want to run even if the first one fails. I want the stage result to fail and the build to get aborted, but only after all steps have run. For example,
pipeline {
agent any
stages {
stage('Run Test') {
steps {
sh "echo running unit-tests"
sh "echo running linting && false" // failure
sh "echo generating report" // This should still run (It currently doesn't)
publishCoverage adapters: [coberturaAdapter("coverage.xml")] // This should still run (It currently doesn't)
junit 'unit-test.xml' // This should still run (It currently doesn't)
}
}
stage('Deploy') {
steps {
echo "deploying" // This should NOT run
}
}
}
}
The result should be a failed build where the "Run Test" stage failed and the "Deploy" stage did not run. Is this possible?
P.S.
I am NOT asking for the same behavior as in Continue Jenkins pipeline past failed stage. I want to run the steps following the failure, but not any of the stages afterwards. I tried to enclose each of the test steps with catchError (buildResult: 'FAILURE', stageResult: 'FAILURE'), but the "Deploy" stage still runs.
EDIT:
I cannot combine all the steps into one big sh step and capture its return code because some of the steps are not shell commands, but instead jenkins steps like junit and publishCoverage.
A script witha non-zero exit code will always cause a jenkins step to fail. You can use returnStatus as true so that jenkins does not fails the step.
Additionally considering your use case, you could use a post always execution, so that the steps are always carried out.
Please see below reference example:
stage('Run Test') {
steps {
def unit_test_result= sh returnStatus: true, script: 'echo "running unit-tests"'
def lint_result= sh returnStatus: true, script: 'echo "running linting"'
if (unit_test_result!=0 || lint_result!=0 ) {
// If the unit_test_result or lint_result status is not 0 then mark this stage as unstable to continue ahead
// and all later stages will be executed
unstable ('Testing failed')
// You can also mark as failed as below and it will not conintue other stages:
// error ('Testing failed')
}
}
post {
always {
// This block would always be executed inspite of failure
sh "echo generating report"
publishCoverage adapters: [coberturaAdapter("coverage.xml")]
junit 'unit-test.xml'
}
}
}
I found a slightly hacky way to get the behavior I want. The other answers didn't work for me, either because they need all the steps to be sh steps, or they don't stop the deploy stage from running. I used catchError to set the build and stage result. But to prevent the next stage from running, I needed to an explicit call to error if the stage failed.
pipeline {
agent any
stages {
stage('Run Test') {
steps {
script {
// catchError sets the stageResult to FAILED, but does not stop next stages from running
catchError (buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh "echo running unit-tests"
}
catchError (buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh "echo running linting && false" // failure
}
catchError (buildResult: 'FAILURE', stageResult: 'FAILURE') {
sh "echo generating report" // This still runs
}
publishCoverage adapters: [coberturaAdapter("coverage.xml")] // This still runs
junit 'unit-test.xml' // This still runs
if (currentBuild.result == "FAILURE") { // This is needed to stop the next stage from running
error("Stage Failed")
}
}
}
}
stage('Deploy') {
steps {
echo "deploying" // This should NOT run
}
}
}
}
Theoretically you should be able to use sh "<command>||true" It would ignore the error on command and continue. However, Jenkins will not fail as it would ignore the error.
If you don't want Jenkins to ignore the error and want it to stop at the end of the stage, you can do something like: sh "<command>||$error=true" then fail the build based on the $error variable. (sh "$error" might be enough but I am not sure, may require an if statement at the end.) It will be only set to true iff command fails.
Another option is to wrap your build steps in a try-catch block! if there's an exception, i.e. return code of build is not 0 you can catch it, mark the build as unstable and then the rest of the pipeline continues on.
here's an example `
pipeline {
agent {
node {
label 'linux'
}
}
options {
timestamps()
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '3'))
}
tools {
maven 'Maven 3.6.3'
jdk 'jdk11'
}
stages {
stage('CleanWS') {
steps {
cleanWs()
}
}
stage('Build') {
steps {
withMaven(options: [artifactsPublisher(disabled: true)]) {
sh "export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn -f pom.xml clean install -DskipTests -Pregression-test -Dmaven.javadoc.skip=true"
}
}
}
stage('Test') {
steps {
script {
try {
withMaven(options: [artifactsPublisher(disabled: true)]) {
sh "export MAVEN_OPTS=\"-Xmx2048m\" && export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn -B verify -Dmaven.source.skip=true -Dmaven.javadoc.skip=true"
}
} catch (exc) {
currentBuild.result = 'UNSTABLE'
}
}
}
post {
always {
script {
junit "**/surefire-reports/*.xml"
}
}
}
}
stage('Sonar Analyse') {
steps {
script {
withMaven(options: [artifactsPublisher(disabled: true)]) {
withSonarQubeEnv("SonarQube") {
sh "export MAVEN_OPTS=\"-Xmx2048m\" && export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn sonar:sonar"
}
}
}
}
}
stage('Deploy to Nexus') {
steps {
sh "export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn -f pom.xml -B clean deploy -DdeployAtEnd=true -DskipTests"
}
}
}
post {
failure {
script {
emailext(
body: "Please go to ${env.BUILD_URL}/console for more details.",
to: emailextrecipients([developers(), requestor()]),
subject: "Nightly-Build-Pipeline Status is ${currentBuild.result}. ${env.BUILD_URL}"
)
}
}
unstable {
script {
emailext(
body: "Please go to ${env.BUILD_URL}/console for more details.",
to: emailextrecipients([developers(), requestor()]),
subject: "Nightly-Build-Pipeline Build Status is ${currentBuild.result}. ${env.BUILD_URL}"
)
}
}
}
}`

Using multiple JDKs in single scripted pipeline

We have a situation where JDK1.7 is used to compile a project and JDK1.8 is used in sonar pipeline job on the aforementioned compiled code.
Is it possible to use 2 JDKs in a single scripted job. If sonar stage is reached, then JDK 1.8 must be used.
Currently this is our pipeline.
node('jenkins_uat_sdg_1g'){
env.JAVA_HOME="${tool 'JDK1.7_110'}"
env.PATH="${env.JAVA_HOME}/bin:${env.PATH}"
deleteDir()
try{
try{
stage('SCM Code Checkout'){
echo "Checking out source code from SVN..."
echo "successfully checked out from SVN"
}
} catch(error){
println("Unable to checkout...there were some errors!")
currentBuild.result = "FAILURE"
error()
}
try{
stage('Compile & Package Generation'){
echo "Begining to compile the code"
bat label: 'build-maven', script: 'mvn -f pom.xml clean compile install'
echo "Successfully compiled"
}
}catch(error){
println("Unable to compile...there were some errors!")
currentBuild.result = "FAILURE"
error()
}
}
Different pipeline script is used for sonar analysis.
node('jenkins_uat_sdg_1g'){
env.JAVA_HOME="${tool 'JDK1.8'}"
env.PATH="${env.JAVA_HOME}/bin:${env.PATH}"
stage('SCM Code Checkout'){
echo "Checking out source code from SVN..."
echo "successfully checked out from SVN"
}
stage('sonarqube analysis'){
withSonarQubeEnv('SonarServer'){
bat label: 'sonar-analyis', script: '"D:/Apache Build Tools/apache-maven-3.6.1-bin/apache-maven-3.6.1/bin/mvn" org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar -f parent/pom.xml -Dsonar.host.url=http://10.xx.xx.xx:9500 -Dsonar.login=xxxxxxxxxxxxxxxxxxxxxa4b4cf180c6'
}
}
}
stage('Quality Gate'){
timeout(time: 5, unit: 'MINUTES'){
def qg = waitForQualityGate()
if(qg.status != 'OK'){
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
}
Is it possible to have a single script which utilizes two JDKs in a single job.
Regards
You can make use of withEnv step to set one or more environment variables within a block. These are available to any external processes spawned within that scope
The following code works for me where i am accessing different Java versions in different stages:
node('slave1') {
deleteDir()
try {
try {
stage('During Build') {
withEnv(['JAVA_HOME=/usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin']) {
sh '${JAVA_HOME}/java -version'
println("or whatever command you want to run in this block...")
}
}
} catch(error) {
println("Unable to find Java 7!")
currentBuild.result = "FAILURE"
error()
}
try {
stage('During Sonar Analysis') {
withEnv(['JAVA_HOME=/usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin']) {
sh '${JAVA_HOME}/java -version'
println("or whatever command you want to run in this block...")
}
}
} catch(error) {
println("Unable to find Java 8!")
currentBuild.result = "FAILURE"
error()
}
} catch(error) {
println("Last catch block!")
error()
}
}
Note: As you would have noticed above, we are using single quotes in Groovy, so the variable expansion is being done by the Bourne shell, not Jenkins
Output:

How to add email notification in jenkins if the build is failed

I need to add email notification in jenkins for both freestyle and pipeline job if the build is failed
reg. Email-ext plugin
In pipeline job you can use post build actions / try catch with proper step - ref. to mail
pipeline {
agent any
stages {
stage('Test') {
steps {
sh 'echo "Fail!"; exit 1'
}
}
}
post {
always {
echo 'This will always run'
}
success {
echo 'This will run only if successful'
}
failure {
echo 'This will run only if failed'
}
unstable {
echo 'This will run only if the run was marked as unstable'
}
changed {
echo 'This will run only if the state of the Pipeline has changed'
echo 'For example, if the Pipeline was previously failing but is now successful'
}
}
}
or try-catch (scripted way)
try{
//code to handle
} catch (e) {
emailext (
from: 'sender#domain.com',
to: 'recepient#domain.com',
subject: "job failed- ${env.JOB_NAME}, Build #${env.BUILD_NUMBER}, FAILED",
attachLog: true,
body: """
Foooooo text
For current build refer to: ${env.BUILD_URL}
job: ${env.JOB_NAME}
build number: #${env.BUILD_NUMBER}
With ERROR:
${e.message}
For full log refer to
${env.BUILD_URL}
"""
)
throw e
}
Post Build Actions > Email Notification
Part of the Mailer plugin.

Chained multiple pipeline based on 'post' jenkins block

I'm beginner to Jenkins. I have code pipeline structure like this
Repo1 -> Repo2 -> Repo3 -> Deploy
I already created such hierarchy via GUI but I want to create it via pipeline as code.I want to create chain of pipelines where I clone different repos and perform tests on it and then continue to another repo based on current pipeline post result.
This is my jenkinsfile - (psuedo code like as it gives me error to build)
pipeline {
agent any
stages {
stage('Build Repo1') {
steps {
sh 'echo "repo1 build!"'
}
}
stage('Test Repo1') {
steps {
sh 'echo "repo success!"'
}
}
}
post {
success {
pipeline {
agent any
stages {
stage('Build Repo2') {
steps {
sh 'echo "build repo2!"'
}
}
stage('Test Repo2') {
steps {
sh 'echo "test repo2!"'
}
}
}
post {
success {
# continue to generate pipeline for repo3
echo 'This will always run'
}
failure {
echo 'This will run only if failed'
}
}
}
}
failure {
echo 'This will run only if failed'
}
unstable {
echo 'This will run only if the run was marked as unstable'
}
changed {
echo 'This will run only if the state of the Pipeline has changed'
echo 'For example, if the Pipeline was previously failing but is now successful'
}
}
}
Please help!

Set the build name and description from a Jenkins Declarative Pipeline

I would like to set the build name and description from a Jenkins Declarative Pipeline, but can't find the proper way of doing it. I tried using an environment bracket after the pipeline, using a node bracket in an agent bracket, etc. I always get syntax error.
The last version of my Jenkinsfile goes like so:
pipeline {
stages {
stage("Build") {
steps {
echo "Building application..."
bat "%ANT_HOME%/bin/ant.bat clean compile"
currentBuild.name = "MY_VERSION_NUMBER"
currentBuild.description = "MY_PROJECT MY_VERSION_NUMBER"
}
}
stage("Unit Tests") {
steps {
echo "Testing (JUnit)..."
echo "Testing (pitest)..."
bat "%ANT_HOME%/bin/ant.bat run-unit-tests"
}
}
stage("Functional Test") {
steps {
echo "Selenium..."
}
}
stage("Performance Test") {
steps {
echo "JMeter.."
}
}
stage("Quality Analysis") {
steps {
echo "Running SonarQube..."
bat "%ANT_HOME%/bin/ant.bat run-sonarqube-analysis"
}
}
stage("Security Assessment") {
steps {
echo "ZAP..."
}
}
stage("Approval") {
steps {
echo "Approval by a CS03"
}
}
stage("Deploy") {
steps {
echo "Deploying..."
}
}
}
post {
always {
junit '/test/reports/*.xml'
}
failure {
emailext attachLog: true, body: '', compressLog: true, recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'DevelopersRecipientProvider']], subject: '[JENKINS] MY_PROJECT build failed', to: '...recipients...'
}
success {
emailext attachLog: false, body: '', compressLog: false, recipientProviders: [[$class: 'DevelopersRecipientProvider']], subject: '[JENKINS] MY_PROJECT build succeeded', to: '...recipients...'
}
}
}
Error is:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 11: Expected a step # line 11, column 5.
currentBuild.name = "MY_VERSION_NUMBER"
^
WorkflowScript: 12: Expected a step # line 12, column 5.
currentBuild.description = "MY_PROJECT MY_VERSION_NUMBER"
^
Ideally, I'd like to be able to read MY_PROJECT and MY_VERSION_NUMBER from the build.properties file, or from the Jenkins build log. Any guidance about that requirement would be appreciated as well.
UPDATE
Based on the answer I had below, the following worked:
stage("Build") {
steps {
echo "Building application..."
bat "%ANT_HOME%/bin/ant.bat clean compile"
script {
def props = readProperties file: 'build.properties'
currentBuild.displayName = "v" + props['application.version']
}
}
Now the build version is automatically set during the pipeline by reading the build.properties file.
I think this will do what you want. I was able to do it inside a script block:
pipeline {
stages {
stage("Build"){
steps {
script {
currentBuild.displayName = "The name."
currentBuild.description = "The best description."
}
... do whatever.
}
}
}
}
The script is kind of an escape hatch to get out of a declarative pipeline. There is probably a declarative way to do it but i couldn't find it. And one more note. I think you want currentBuild.displayName instead of currentBuild.name In the documentation for Jenkins globals I didn't see a name property under currentBuild.
If you want to set build name to a job from a parameter, you can use
currentBuild.displayName = "${nameOfYourParameter}".
Make sure you use double quotes instead of single quotes.
Job Configuration
Build job with parameter
Build History
REFERENCE: How to set build name in Pipeline job?

Resources