I have problems with my Jenkins pipeline. I want to do the following:
if the Build Environment already exists in the Workspace then execute a (incremental) build using the previous Environment.
If that fails retry again with a clean build (delete previous Build Environment, then build again)
I am trying to do this by:
retry(1) {
try {
prepareEnvironment()
setupBuildEnvironment() // sets up environment if it is not present yet
runBuild()
} catch (e) {
echo 'Err: Incremental Build failed with Error: ' + e.toString()
echo ' Trying to build with a clean Workspace'
removeOldBuildEnvironment()
} finally {
cleanupEnvironment()
}
}
When I run this in Jenkins and the runBuild() step fails I get:
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException:
Scripts not permitted to use new java.lang.Exception java.lang.String
I think the problem is the try/catch inside the retry(1) block. Any suggestions how to fix that
I also tried it without the retry. Here I had the problem that if the
bat "..."
step inside runBuild() returns a exception the pipeline Stage is marked as fail even if I catch the exception and the clean build is a success.
Any suggestions?
The error message is not because the try/catch but because of throwing exception in the prepareEnvironment, setupBuildEnvironment or runBuild methods, like throw new Exception("message") which is not allowed in sandbox mode. What is allowed is using the error step like so:
def runBuild() {
// ...
error "ERR"
}
This step will throw a hudson.AbortException with the message specified.
The catch block in you code will catch this exception and print the proper message then invoke removeOldBuildEnvironment
On the other hand with this modification done your script will still not work as expected as the exception is swallowed by the catch block, so the retry step will not execute the code again. To make it work the exception needs to be thrown again from the catch block (note that you have to use retry(2) instead of retry(1))
retry(2) {
try {
prepareEnvironment()
setupBuildEnvironment() // sets up environment if it is not present yet
runBuild()
} catch (e) {
echo 'Err: Incremental Build failed with Error: ' + e.toString()
echo ' Trying to build with a clean Workspace'
removeOldBuildEnvironment()
throw e
} finally {
cleanupEnvironment()
}
}
Go to script approval (in Manage Jenkins, somewhere at the bottom) and approve toString method for Exception.
If you can't find script approval, then install plugin https://wiki.jenkins-ci.org/display/JENKINS/Script+Security+Plugin first.
You might need to visit that page when you see RejectedAccessException.
Try to uncheck the checkbox "Use Groovy Sandbox".
Related
i am trying to use try catch inside stage but getting error as mentioned in subject.
Here i am using build job to call another jenkins pipeline which works without try-catch.
Not sure if we can use try-catch outside shell with build job ?. \n
\n Requirement is to use try catch with build job so that in case of any failure , it will skip this step, echo message and go to next step.
{
stage('Pull Pipeline') {
try {
build job: "../new pipeline/test_dummy", wait: true
}
catch (Exception e) {
echo "release having error"
}
}
}
I have a jenkins job.
It is pretty simple: pull from git, and run the build.
The build is just one step:
Execute window command batch
In my use case, I will need to run some python scripts.
Some will fail, some others will not.
python a.py
python b.py
What does determine the final status of the build?
It seems I can edit that by:
echo #STABLE > build.proprieties
but how are the STABLE/UNSTABLE status assigned if not specified by the user?
What happens if b.py raise an error and fails?
Jenkins interprets a pipeline as failed if a command returns an exit code unequal zero.
Internally the build status is set with currentBuild.currentResult which can have three values: SUCCESS, UNSTABLE, or FAILURE.
If you want to control the failure / success of your pipeline yourself you can catch exceptions / exit codes and manually set the value for currentBuild.currentResult. Plugins also use this attribute to change the result of the pipeline.
For example:
stage {
steps {
script {
try {
sh "exit 1" // will fail the pipeline
sh "exit 0" // would be marked as passed
currentBuild.currentResult = 'SUCCESS'
} catch (Exception e) {
currentBuild.currentResult = 'FAILURE'
// or currentBuild.currentResult = 'UNSTABLE'
}
}
}}
I'm using try catch in my jenkins file, to check to see if a specific error is thrown and if it is do certain functionality
try {
// code that throws an error
} catch (ex) {
echo 'an error occurred'
echo "ex: ${ex}"
if (ex == Exception1) {
// do stuff
}
if (ex == Exception2) {
// do other stuff
}
}
My problem is that the error that is being caught is a hudson.AbortException and the message is 'script returned exit code 1'.
How do I catch the actual error that was thrown rather than the hudson/jenkins wrapper?
If you are running shell script using syntax sh script: 'echo hello' Ref
then you should run it with set +e and set -e,as mentioned in the ref doc. Here set +e and set -e will keep the program running even if you get error in between,which you should handle in shell itself.Returned value will also contain errors if using 2>&1 in shell.
If this returned value contains the Exception you can raise separate error in try itself.
Ex:
try{
def returnedVal = sh script: 'some exception raising code'
if (returnedVal.toLowerCase().contains('exception1')){
error("got Exception1")
}
} catch(Excpetion ex){
//handle Exception
}
"script returned exit code 1" is actually the error message .
You should check the script you are running and modify it to print the inner script error before exit
I'm trying to replicate the equivalent of a conditional stage in Jenkins pipeline using a try / catch around a preceding stage, which then sets a success variable, which is used to trigger the conditional stage.
It appears that a try catch block is the way to go, setting a success var to SUCCESS or FAILED, which is used as part of a when statement later (as part of the conditional stage).
The code I am using is as follows:
pipeline {
agent any
stages {
try{
stage("Run unit tests"){
steps{
sh '''
# Run unit tests without capturing stdout or logs, generates cobetura reports
cd ./python
nosetests3 --with-xcoverage --nocapture --with-xunit --nologcapture --cover-package=application
cd ..
'''
currentBuild.result = 'SUCCESS'
}
}
} catch(Exception e) {
// Do something with the exception
currentBuild.result = 'SUCCESS'
}
stage ('Speak') {
when {
expression { currentBuild.result == 'SUCCESS' }
}
steps{
echo "Hello, CONDITIONAL"
}
}
}
}
The latest syntax error I am receiving is as follows:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
failed:
WorkflowScript: 4: Expected a stage # line 4, column 9.
try{
I've also tried lots of variations.
Am I taking the wrong approach here? This seems like a fairly common requirement.
Thanks.
This might solve your problem depending on what you are going for. Stages are only run when the preceding stages succeed, so if you actually have two stages like in your example, and if you want the second to only run when the first succeeds, you want to ensure that the first stage fails appropriately when tests fail. Catching will prevent the (desirable) failure. Finally will preserve the failure, and can also still be used to grab your test results.
So here, the second stage will only run when the tests pass, and the test results will be recorded regardless:
pipeline {
agent any
stages {
stage("Run unit tests"){
steps {
script {
try {
sh '''
# Run unit tests without capturing stdout or logs, generates cobetura reports
cd ./python
nosetests3 --with-xcoverage --nocapture --with-xunit --nologcapture --cover-package=application
cd ..
'''
} finally {
junit 'nosetests.xml'
}
}
}
}
stage ('Speak') {
steps{
echo "Hello, CONDITIONAL"
}
}
}
}
Note that I'm actually using try in a declarative pipeline, but like StephenKing says, you can't just use try directly (you have to wrap arbitrary groovy code in the script step).
I see on Declarative Pipeline that it's done via "post" section really easy with conditions like 'always', 'failure', ...:
https://jenkins.io/doc/book/pipeline/syntax/#post
But with Scripted Pipeline there are no examples on how it's done:
This link provides an example but only for "always" condition
https://jenkins.io/doc/book/pipeline/jenkinsfile/#handling-failures
I see this docs on how to set that result but I don't understand because with Declarative Pipeline you don't have to set it manually, plugins provided commands handle that for you.
https://support.cloudbees.com/hc/en-us/articles/218554077-How-to-set-current-build-result-in-Pipeline
Can anyone help me with this?
For example if I do this:
node {
try {
error 'Test error'
} catch (ex) {
echo 'Error handled'
}
}
It doesn't trigger the "FAILURE" build status automatically and I don't see the echo. Why?
Your piece of code works as expected :
node { try { error 'Test error' } catch (ex) { echo 'Error handled' } }
gives :
[Pipeline] node
Running on maƮtre in /var/lib/jenkins/workspace/test-pipeline2
[Pipeline] {
[Pipeline] error
[Pipeline] echo
Error handled
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Explanations :
error 'Test error' isn't supposed to log anything. It's equivalent to the Java throw new Exception("Test error"). See https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#code-error-code-error-signal
the catch block catches this exception, and logs the message as expected. After this block, no error is thrown to the Jenkins runner, so the job ended as Successful.
If you want to mark your build as failed, you have to do this explicitly in the catch block. You can also use the catchError block to handle this for you. See : https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#code-catcherror-code-catch-error-and-set-build-result