Everyone, I am looking for build log for every stage that I have executed in the pipeline.
Below is my build stage.
Stage('Build'){
bat 'mvn -f workspace/pom.xml clean install'
emailtext body: '', subect:'build is done', to:'xxxx'
}
I have configured emailing in the stage but it is just giving the normal email. But our requirement is we need to get a complete build. Could you please let me know what can be done to get complete build log.
You need mainly two things.
First, to log somehow which stages have run already. Then, you can use post actions to notify, whatever the way you want to do it.
This is just one way.
If you need to log the stages in error you need to catch the steps and set the right build log. Otherwise you can just skip the try catches, and send the completed stages.
def buildLog = "Stages Completed:"
def failedStageLog = ""
pipeline {
agent any
stages {
stage('Hello 1') {
steps {
script {
try{ //catch errors
echo 'Hello World 1'
}catch(e){ //define your message
failedStageLog = "Hello 1"
error("Failing pipeline") //force to exit on failed stage caught
}
buildLog = buildLog+" Hello 1"
}
}
}
stage('Hello 2') {
steps {
script{
try{ //catch errors
echo 'Hello World 2'
}catch(e){ //define your message
failedStageLog = "Hello 2"
error("Failing pipeline") //force to exit on failed stage caught
}
buildLog = buildLog+", Hello 2"
}
}
}
}
post{
success{
println buildLog // parse and send email
}
unsuccessful{
println "Error on pipeline stage: $failedStageLog. $buildLog " // parse and send email
}
}
}
Output example
Success Message: Pipeline status: SUCESS. Stages Completed: Hello 1, Hello 2
Error Message: Pipeline status: UNSUCESSFUL. Failed stage: Hello 2. Stages Completed: Hello 1
I am rather new to Jenkins. I am trying to run a UnitTest.exe and to check the value of the return code of it. In the JenkinsFile:
stage('Unit Tests')
{
steps{
script{
def statusCode = bat script: "UnitTest.exe", returnStatus:true
echo statusCode
}
}
}
I am able to see the output of the program (all the std::cout), but I am unable to print out the return value statusCode
as #zett42 said,
instead of using echo statusCode using
echo "$statusCode"
instead should do the trick
I am conducting some tests in my pipeline. My aim is that if an error file exists the build should fail. But if for some reason the tests experienced an exception and didn't write either an error or successful file, the pipeline should also fail. If neither of the conditions for failure are met, I would like the an upstream job to execute.
I wrote it in stage and initially it looked like this:
stage('system tests') {
steps {
dir(project_root) {
def error_exists = sh(
script: 'ls error.txt', returnStatus: true
)
if (error_exists == 0) {
currentBuild.result = 'FAILED'
return
}
build job: 'my-job;
}
}
}
The above code works. When the tests being executed wrote an error file, the pipeline fails. I then tried to modify the code to cater for the outcome where neither error or success files are written.
stage('system tests') {
steps {
dir(project_root) {
def error_exists = sh(
script: 'ls error.txt', returnStatus: true
)
def success_exists = sh(
script: 'ls success.txt', returnStatus: true
)
if (error_exists == 0) {
currentBuild.result = 'FAILED'
return
} else if (success_exists == 1 && error_exists == 1) {
currentBuild.result = 'FAILED'
return
}
build job: 'my-job;
}
}
}
I simulated a situation where neither file was written and the pipeline didn't fail, and instead it triggered the upstream build. Why am I not entering the else if clause` if the result of both shell scripts is false? I took the logical operators from here and I think they should be met (The code below is output from the shell scripts in the new-job pipeline)
[new-job] Running shell script
+ ls error.txt
ls: cannot access error.txt: no such file or directory
[new-job] Running shell script
+ ls success.txt
ls: cannot access success.txt: no such file or directory
If these files do not exist then sh jenkins step returns error code 2. You should rewrite your 'if condition' like that:
success_exists == 2 && error_exists == 2
But, I think that in your case this code is more suitable:
stage('system tests') {
steps {
dir(project_root) {
def error_exists = sh(
script: 'ls error.txt', returnStatus: true
)
def success_exists = sh(
script: 'ls success.txt', returnStatus: true
)
if (error_exists == 0) {
currentBuild.result = 'FAILED'
return
} else if (success_exists != 0 && error_exists != 0) {
currentBuild.result = 'FAILED'
return
}
build job: 'my-job;
}
}
Because there may be other reasons for not being able to find the file (lack of access, etc).
I am sure I am not the only one who is interested in how to handle something like this: docker build stage in Jenkins pipeline fails with Unexpected EOF (there can be a lot of reasons, in my case the docker daemon was restarted on the slave)
appImage = docker.build ("${projectName}:${env.BRANCH_NAME}-${gitCommit}", "--build-arg APP_ENV=${appEnv} --build-arg SKIP_LINT=true .")
The deploy phase kicks in, because the Unexpected EOF does not actually throw any error, there is no exception to catch so the build status is null.
I know that it's not a regular situation but still how can we handle smth like this so that the following stages do not run in case the build is interrupted.
Additional details:
#JRichardsz , thanks for the answer! Usually currentBuild.result . defaults to null e.g. https://issues.jenkins-ci.org/browse/JENKINS-46325 so unless you set it to success explicitly upon successful stage's execution , it will be null. But all in all the same can be achieved with try catch like :
if (deployableBranches.contains(env.BRANCH_NAME)) {
try {
stage('Build image') {
ansiColor('xterm') {
appImage = docker.build
("${projectName}:${env.BRANCH_NAME}-${gitCommit}", "--build-arg
SKIP_LINT=true .")
}
}
stage('Push image') {
docker.withRegistry("${registryUrl}", "${dockerCredsId}") {
appImage.push()
appImage.push "${env.BRANCH_NAME}-latest"
}
}
stage('Deploy') {
build job: 'kubernetes-deploy', parameters: [
/////
]
}
} catch (e) {
// A shell step returns with a nonzero exit code
// When pipeline is in a shell step, and a user presses abort
if (e.getMessage().contains('script returned exit code 143')) {
currentBuild.result = "ABORTED"
} else {
currentBuild.result = "FAILED"
}
throw e
} finally {
// Success or failure or abort, always send notifications
stage('Send deployment status') {
helpers.sendDeploymentStatus(projectName, currentBuild.result,
helpers.getCommitHashShort())
}
}
}
But the issue is that stage('Build image') may exit without any error code like it was in my case.
I had a similar requirement : "If some rule is executed in stage A, following stages must not run"
This worked for me :
def flag;
node {
stage('A') {
flag = 1;
}
stage('B') {
// exit this stage if flag == 1
if(flag == 1){
return;
}
//start of stage B tasks
...
}
}
Also you could use some jenkins variable like currentBuild.result instead of flag like this :
node {
stage('A') {
//stage A tasks
//this stage could modify currentBuild.result variable
}
stage('B') {
// exit this stage if currentBuild.result is null , empty, "FAILURE", etc
if(currentBuild.result == null ||
currentBuild.result == "" ||
currentBuild.result=="FAILURE" ){
return;
}
//stage B tasks
}
}
I have a Jenkins pipeline which has multiple stages, for example:
node("nodename") {
stage("Checkout") {
git ....
}
stage("Check Preconditions") {
...
if(!continueBuild) {
// What do I put here? currentBuild.xxx ?
}
}
stage("Do a lot of work") {
....
}
}
I want to be able to cancel (not fail) the build if certain preconditions are not met and there is no actual work to be done. How can I do this? I know the currentBuild variable is available, but I can't find the documentation for it.
You can mark the build as ABORTED, and then use the error step to cause the build to stop:
if (!continueBuild) {
currentBuild.result = 'ABORTED'
error('Stopping early…')
}
In the Stage View, this will show that the build stopped at this stage, but the build overall will be marked as aborted, rather than failed (see the grey icon for build #9):
After some testing I came up with the following solution:
def autoCancelled = false
try {
stage('checkout') {
...
if (your condition) {
autoCancelled = true
error('Aborting the build to prevent a loop.')
}
}
} catch (e) {
if (autoCancelled) {
currentBuild.result = 'ABORTED'
echo('Skipping mail notification')
// return here instead of throwing error to keep the build "green"
return
}
// normal error handling
throw e
}
This will result into following stage view:
failed stage
If you don't like the failed stage, you have to use return. But be aware you have to skip each stage or wrapper.
def autoCancelled = false
try {
stage('checkout') {
...
if (your condition) {
autoCancelled = true
return
}
}
if (autoCancelled) {
error('Aborting the build to prevent a loop.')
// return would be also possible but you have to be sure to quit all stages and wrapper properly
// return
}
} catch (e) {
if (autoCancelled) {
currentBuild.result = 'ABORTED'
echo('Skipping mail notification')
// return here instead of throwing error to keep the build "green"
return
}
// normal error handling
throw e
}
The result:
custom error as indicator
You can also use a custom message instead of a local variable:
final autoCancelledError = 'autoCancelled'
try {
stage('checkout') {
...
if (your condition) {
echo('Aborting the build to prevent a loop.')
error(autoCancelledError)
}
}
} catch (e) {
if (e.message == autoCancelledError) {
currentBuild.result = 'ABORTED'
echo('Skipping mail notification')
// return here instead of throwing error to keep the build "green"
return
}
// normal error handling
throw e
}
Following this documentation from Jenkins, you should be able to generate an error to stop the build and set the build result like this:
currentBuild.result = 'ABORTED'
Hope that helps.
The thing that we use is:
try {
input 'Do you want to abort?'
} catch (Exception err) {
currentBuild.result = 'ABORTED';
return;
}
The "return" at the end makes sure that no further code is executed.
I handled in a declarative way as shown below:
Based on catchError block it will execute post block.
If post result falls under failure category, the error block will be executed to stop upcoming stages like Production, PreProd etc.
pipeline {
agent any
stages {
stage('Build') {
steps {
catchError {
sh '/bin/bash path/To/Filename.sh'
}
}
post {
success {
echo 'Build stage successful'
}
failure {
echo 'Compile stage failed'
error('Build is aborted due to failure of build stage')
}
}
}
stage('Production') {
steps {
sh '/bin/bash path/To/Filename.sh'
}
}
}
}
Inspired by all the answers I have put all the stuff together into one Scripted Pipeline. Keep in mind this is not a Declarative Pipeline.
To get this example working you will need:
QuickFIX form this answer Jenkins CI Pipeline Scripts not permitted to use method groovy.lang.GroovyObject
discord notifier plugin - https://plugins.jenkins.io/discord-notifier/
Discord channel webhook url filled in the code
The idea I had was to abort the pipeline if it is "replayed" vs started by "run button"(in branches tab of Jenskins BlueOcean):
def isBuildAReplay() {
// https://stackoverflow.com/questions/51555910/how-to-know-inside-jenkinsfile-script-that-current-build-is-an-replay/52302879#52302879
def replyClassName = "org.jenkinsci.plugins.workflow.cps.replay.ReplayCause"
currentBuild.rawBuild.getCauses().any{ cause -> cause.toString().contains(replyClassName) }
}
node {
try {
stage('check replay') {
if (isBuildAReplay()) {
currentBuild.result = 'ABORTED'
error 'Biuld REPLAYED going to EXIT (please use RUN button)'
} else {
echo 'NOT replay'
}
}
stage('simple stage') {
echo 'hello from simple stage'
}
stage('error stage') {
//error 'hello from simple error'
}
stage('unstable stage') {
unstable 'hello from simple unstable'
}
stage('Notify sucess') {
//Handle SUCCESS|UNSTABLE
discordSend(description: "${currentBuild.currentResult}: Job ${env.JOB_NAME} \nBuild: ${env.BUILD_NUMBER} \nMore info at: \n${env.BUILD_URL}", footer: 'No-Code', unstable: true, link: env.BUILD_URL, result: "${currentBuild.currentResult}", title: "${JOB_NAME} << CLICK", webhookURL: 'https://discordapp.com/api/webhooks/')
}
} catch (e) {
echo 'This will run only if failed'
if(currentBuild.result == 'ABORTED'){
//Handle ABORTED
discordSend(description: "${currentBuild.currentResult}: Job ${env.JOB_NAME} \nBuild: ${env.BUILD_NUMBER} \nMore info at: \n${env.BUILD_URL}\n\nERROR.toString():\n"+e.toString()+"\nERROR.printStackTrace():\n"+e.printStackTrace()+" ", footer: 'No-Code', unstable: true, link: env.BUILD_URL, result: "ABORTED", title: "${JOB_NAME} << CLICK", webhookURL: 'https://discordapp.com/api/webhooks/')
throw e
}else{
//Handle FAILURE
discordSend(description: "${currentBuild.currentResult}: Job ${env.JOB_NAME} \nBuild: ${env.BUILD_NUMBER} \nMore info at: \n${env.BUILD_URL}\n\nERROR.toString():\n"+e.toString()+"\nERROR.printStackTrace():\n"+e.printStackTrace()+" ", footer: 'No-Code', link: env.BUILD_URL, result: "FAILURE", title: "${JOB_NAME} << CLICK", webhookURL: 'https://discordapp.com/api/webhooks/')
throw e
}
} finally {
echo 'I will always say Hello again!'
}
}
Main trick was the order of lines to achive abort state:
currentBuild.result = 'ABORTED'
error 'Biuld REPLAYED going to EXIT (please use RUN button)'
First set the state then throw an exception.
In the catch block both work:
currentBuild.result
currentBuild.currentResult
If you're able to approve the constructor for FlowInterruptedException, then you can do the following:
throw new FlowInterruptedException(Result.ABORTED, new UserInterruption(getCurrentUserId()))
You can add to your shared library repo a file var/abortError.groovy:
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
import jenkins.model.CauseOfInterruption.UserInterruption
def call(message)
{
currentBuild.displayName = "#${env.BUILD_NUMBER} $message"
echo message
currentBuild.result = 'ABORTED'
throw new FlowInterruptedException(Result.ABORTED, new UserInterruption(env.BUILD_USER_ID))
}
Then you can use it this way (after importing library):
abortError("some message")
Note that if you se following error in console logs:
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new org.jenkinsci.plugins.workflow.steps.FlowInterruptedException hudson.model.Result jenkins.model.CauseOfInterruption[]
You need follow the link form log and approve security exception.
You can go to the script console of Jenkins and run the following to abort a hung / any Jenkins job build/run:
Jenkins .instance.getItemByFullName("JobName")
.getBuildByNumber(JobNumber)
.finish(hudson.model.Result.ABORTED, new java.io.IOException("Aborting build"));
This is the way to abort the currently running build pipeline in Jenkins UI(in Build History there is a cancel button), for capture:
The Executor.interrupt(Result) method is the cleanest, most direct way I could find to stop a build prematurely and choose the result.
script {
currentBuild.getRawBuild().getExecutor().interrupt(Result.ABORTED)
sleep(1) // Interrupt is not blocking and does not take effect immediately.
}
Pros:
Works in a declarative pipeline just as well as a scripted one.
No try/catch or exceptions to handle.
Marks the calling stage and any successive stages as green/passing in the UI.
Cons:
Requires a number of in-process script approvals, including one that is considered insecure. Approve and use with caution.
Taken from my answer on devops.stackexchange.com.
As for currentBuild, have a look at the docs for the RunWrapper class.