I have a scripted jenkins pipeline with the code like this.
func_stage_1() {
try {
stage1
} catch {
}
}
func_stage_1()
Initially when I did not have the stage inside function, pipeline used to fail if a stage failed and exceptions were printed. After putting it inside function, it continues the whole pipeline even though one stage fails. How to fix this?
Main functionality behind adding exception logic is to continue the process even though the stage is failed.
If you want to make the remaining process stop, if exception occurred then you have to do it in below way.
func_stage_1() {
try {
stage1
} catch(Exception err {
error "${err}" // stops the execution of remaining stages by throwing the exception
}
}
func_stage_1()
Related
Sometimes our Jenkins stage fails with the following error:
Emulator did not finish booting within 600 seconds, aborting
This usually happens because the VM has entered some type of low memory state and any subsequent attempts to boot the emulator on that VM will failure. So in this scenario, I'd like to automatically re-execute the entire stage as a whole (should hopefully automatically be assigned a new VM). How can I achieve this?
There's options { retry(3) }
stage("android-ui-tests") {
options {
retry(3)
}
steps {
// run stage..
}
}
But AFAIK, this is not conditional. An API like the following would be ideal:
options {
retry(3) {
if(exception.contains("Emulator did not finish booting")) {
// `true` to retry
return true
}
return false
}
}
Does anything like this exist? Or maybe a post condition that could inspect the failure and trigger a retry?
I am able to skip a stage using when condition successfully in jenkins declarative pipeline but I want to early abort the build if a set of conditions are not met. I tried putting when block at top level inside stages and outside stages as well but it gives syntax error saying "Expected stage" and "Undefined section when" respectively. Can anyone suggest how can I make it work ?
when {
anyOf {
not {
equals expected: true, actual: params.boolean_parameter
}
not{
equals expected: '', actual: params.string_parameter
}
}
}
In declarative pipelines the when directive can be used only on stages.
To solve your issue you can just create a dummy stage for aborting the pipeline in case the condition is not meant, in that step you can use a regular when directive and inside the steps of the stage just use the error keyword for aborting the build with a relevant message (see the error documentation).
Something like:
pipeline {
agent any
stages {
stage('Validate Conditions') {
when {
anyOf {
not {
equals expected: true, actual: params.boolean_parameter
}
not{
equals expected: '', actual: params.string_parameter
}
}
}
steps {
error("Aborting the build because conditions are not met")
}
}
... // rest of pipeline
}
}
This way if conditions are not met the build will be aborted, however the post section will still be executed allowing you to send notifications and so if needed.
I have another question about Pipelines this time about error handling using try/catch. What I am doing is using the "try" outside the stage so I can easily tell which stages failed and which passed. And this has worked brilliantly.
I need to now worry about logging and success/failure for all our logs. So here is my dilemma: I want to it build (try) then error check (catch) then output SUCCESS if it has built and checked for errors. If the error check (catch) catches errors, then output to log FAILURE. I am sure the solution is staring at me in the face and I am missing it. This is what I have (simple version) that is not very elegant:
env.STAGE_STATUS = ""
try {
stage ('Build Setup') {
echo "Did this work?"
}
} catch (errors) {
echo "This did not work!"
env.STAGE_STATUS = "FAIL"
}
if ("%STAGE_STATUS%" != "FAIL") {
echo "This did work!"
}
As always thanks for any assistance.
Using try/catch/finally inside stage looks more elegant and at least more readable. Secondary if you want to fail build (which is basically same cause in your sample you are failing stage, which is also failing the job itself) use following var currentBuild.result, which is btw globally accessible. Saying so, I would go for this code:
stage('Build Setup') {
try {
echo 'Did this work?'
} catch {
echo 'This did not work!'
currentBuild.result = 'FAILED'
} finally {
if (currentBuild.result != 'FAILED') {
echo 'This did work!'
}
}
}
I am looking for a generic way to determine the name of the failed stage at the end of a Jenkins scripted Pipeline.
Please note that this is different than Determine Failed Stage in Jenkins Declaritive Pipeline which is about declarative pipeline.
Also note that use of try/catch inside each stage is out of question because it would make the pipeline script impossible to read. This is because we have like 10-15 stages which are stored in multiple files and they are compiled using JJB to create the final pipeline script. They are already complex so I need a clean approach on finding which stage failed.
U could also create a custom step in a shared library, a super_stage
Quick example:
// vars/super_stage.groovy
def call(name, body) {
try {
stage(name) {
body()
}
} catch(e) {
register_failed_stage(name, e)
throw e
}
}
In that way you can 'reuse' the same exception handler.
In your scripted pipeline you would then use it like:
super_stage("mystage01") {
//do stuff
}
Source
Use a GraphListener:
def listener = new GraphListener.Synchronous(){
#NonCPS
void onNewHead(FlowNode node){
if (node instanceof StepStartNode){
// before steps execution
}else if (node instanceof StepEndNode){
// after steps execution
}
}
def execution = (FlowExecution) currentBuild.getRawBuild().getExecution()
execution.addListener(listener)
You are going to need a few helper functions in order to make it work, for example StepStartNode and StepEndNode gets called twice so you have to filter the one with the label. Also variables like env are available inside the listener so you can store anything in there to be picked up later.
This answer is pretty generic but I've found that is useful in many of the stackoverflow questions regarding doing something before/after some stage (or in all).
You cannot try/catch exceptions inside the pipeline as this approach is not a wrapper for the stage but just a listener that gets executed once per each line instruction but you can just record the stage at the begining and at the end check currentBuild.result to see if the stage failed. You can do pretty much anything at this point.
At some point with the FlowExecution you have access to the pipeline script, I don't know if it's writtable at that point but it would be awesome to rewrite the pipeline to actually try/catch the stages. If you do something in this line please let me know ;)
I'm using a nested try-catch block to define a jenkins pipeline. At the execution time, if I have another try-catch block in the parent try-catch block and something goes wrong in the child try-catch block, it will jump to the child catch block then again will continue executing the code in the parent try-catch block.
I have tried setting the currentBuild.result='Failure' and error "Error occurred" but still, it will proceed with the execution. I want the pipeline status to be a failure and terminate the execution of the rest of the code.
try{
stage('stage1'){
//do something
}
try{
stage('stage2'){
//do something
}
}catch(Exception err1){
error "Error Occurred"
currentBuild.result='Failure'
}
}catch(Exception ex){
// Do something if stage 1 fails
}
If the stage 2 fails, it shouldn't jump to the stage 1's catch statement. Can someone please suggest me a good way to achieve this ?
This should also answer your question.
A single return after setting currentBuild.result = 'Failure' should work for you. Take care, that the return is outside of a stage, or else it will just exit the stage.