try/catch/finally masks Jenkinsfile problems in case of groovy compiler exceptions - groovy

I have code similar to the one below in my Jenkinsfile:
node {
checkout scm
// do some stuff
try {
// do some maven magic
} catch (error) {
stage "Cleanup after fail"
emailext attachLog: true, body: "Build failed (see ${env.BUILD_URL}): ${error}", subject: "[JENKINS] ${env.JOB_NAME} failed", to: 'someone#example.com'
throw error
} finally {
step $class: 'JUnitResultArchiver', testResults: '**/TEST-*.xml'
}
}
If the above code fails because of some jenkins-pipeline related errors in the try { } (e.g. using unapproved static method) the script fails silently. When I remove the try/catch/finally I can see the errors.
Am I doing something wrong? Shouldn't rethrowing error make the pipeline errors appear in the log?
EDIT:
I've managed to nail down the problem to groovy syntax, when e.g. I use a variable that hasn't been assigned yet.
Example:
echo foo
If foo is not declared/assigned anywhere Jenkins will fail the build and won't show the reason if it is inside the try/catch/finally which rethrows the exception.

This happens when an additional exception is thrown inside the finally block or before the re-throw inside catch. In these cases the RejectedAccessException is swallowed and script-security does not catch it.

Related

Groovy catch block not catching MultipleCompilationErrorsException

I am trying to catch an exception (MultipleCompilationErrorsException) but am having a hard time doing so (actually I am trying to catch all types of errors and exceptions if that matters). Here is what I have tried:
try {
some erroneous crap here
println("wtf! A")
} catch(Throwable all) {
println("caught!")
}
This works. caught! is shown as the output.
try {
try some erroneous crap here
println("wtf! A")
} catch(Throwable all) {
println("caught!")
}
This code errors out with:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed: /tmp/g.groovy: 2: expecting '{', found 'some' # line
2, column 9.
try some crap here
^
1 error
So now that I have the exception name, I tried:
try {
try some erroneous crap here
println("wtf! A")
} catch(MultipleCompilationErrorsException e) {
println("caught!")
}
This errors out exactly like the above:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed: /tmp/g.groovy: 2: expecting '{', found 'some' # line
2, column 9.
try some crap here
^
1 error
Can someone tell me what I am missing? How does one catch such an error/exception?
"Try Catch's" are generally used to handle exceptions that may pop up during the run time of your code. For example, you can try to run a command that requires a certain plugin/library to be imported but if the user doesn't have the respective plugin/library, then the "catch" will handle this exception.
In your case, it seems that you are trying to handle an actual error with the code syntax within your try block. The try block cannot run at all if the syntax is not correct (this would be the compilation error). My best advice would be to try running what ever is inside your try block first to see if it will throw an exception and then implement a try catch block.

get error code from called devenv.exe in jenkins pipeline

I just try to erase all Freestyle Jobs from our Jenkins Server. Therefore I call our VS builds directly from the Pipeline job:
bat """chcp 1252 & "PATHTOVS\\devenv.com" /rebuild Release^|$buildBranch $WORKSPACE\\SOLUTION.sln >> ${buildBranch}_$CPNUM_PARAM.txt"""
Now I am wondering how to differentieate between the three Build States (SUCCESS/UNSTABLE/FAILED). Until now I am using a try/catch block. But this isnt very clean and also does not provides the UNStABLE state.
try{
#buildcall
state = 'SUCCESS'
}catch(e){
state = 'FAILED'
}
Unfortuantely I am not sure which error codes from devenv.exe can be retrieved and how to perform this.
Solved it the following way:
try{
//do something
}
}catch(e){
String error = "${e}"
println error
}

How to perform actions for failed builds in Jenkinsfile

Is there a way to perform cleanup (or rollback) if the build in Jenkinsfile failed?
I would like to inform our Atlassian Stash instance that the build failed (by doing a curl at the correct URL).
Basically it would be a post step when build status is set to fail.
Should I use try {} catch ()? If so, what exception type should I catch?
Since 2017-02-03, Declarative Pipeline Syntax 1.0 can be used to achieve this post build step functionality.
It is a new syntax for constructing Pipelines, that extends Pipeline with a pre-defined structure and some new steps that enable users to define agents, post actions, environment settings, credentials and stages.
Here is a sample Jenkinsfile with declarative syntax:
pipeline {
agent label:'has-docker', dockerfile: true
environment {
GIT_COMMITTER_NAME = "jenkins"
GIT_COMMITTER_EMAIL = "jenkins#jenkins.io"
}
stages {
stage("Build") {
steps {
sh 'mvn clean install -Dmaven.test.failure.ignore=true'
}
}
stage("Archive"){
steps {
archive "*/target/**/*"
junit '*/target/surefire-reports/*.xml'
}
}
}
post {
always {
deleteDir()
}
success {
mail to:"me#example.com", subject:"SUCCESS: ${currentBuild.fullDisplayName}", body: "Yay, we passed."
}
failure {
mail to:"me#example.com", subject:"FAILURE: ${currentBuild.fullDisplayName}", body: "Boo, we failed."
}
}
}
The post code block is what handles that post step action
Declarative Pipeline Syntax reference is here
I'm currently also searching for a solution to this problem. So far the best I could come up with is to create a wrapper function that runs the pipeline code in a try catch block. If you also want to notify on success you can store the Exception in a variable and move the notification code to a finally block. Also note that you have to rethrow the exception so Jenkins considers the build as failed. Maybe some reader finds a more elegant approach to this problem.
pipeline('linux') {
stage 'Pull'
stage 'Deploy'
echo "Deploying"
throw new FileNotFoundException("Nothing to pull")
// ...
}
def pipeline(String label, Closure body) {
node(label) {
wrap([$class: 'TimestamperBuildWrapper']) {
try {
body.call()
} catch (Exception e) {
emailext subject: "${env.JOB_NAME} - Build # ${env.BUILD_NUMBER} - FAILURE (${e.message})!", to: "me#me.com",body: "..."
throw e; // rethrow so the build is considered failed
}
}
}
}
I manage to solve it by using try:finally. In case of this stage raises an error the stage will be red and finally run the code but if the stage is okay, the stage will be green and finally will run too.
stage('Tests'){
script{
try{
sh """#!/bin/bash -ex
docker stop \$(docker ps -a -q)
docker rm \$(docker ps -a -q)
export DOCKER_TAG=${DOCKER_TAG}
docker-compose -p ${VISUAL_TESTING_PROJECT_TAG} build test
docker-compose -p ${VISUAL_TESTING_PROJECT_TAG} up --abort-on-container-exit --exit-code-from test
"""
}
finally{
sh """#!/bin/bash -ex
export DOCKER_TAG=${DOCKER_TAG}
docker-compose -p ${VISUAL_TESTING_PROJECT_TAG} down
"""
}
}
}

Multithreading code testing by Spock

I want to verify exception throwing in one of my running threads. This is piece of my test code:
then:
def e = thrown(RequestFormatException)
e.message == "Incorrect first line: INCORRECT LINE"
When I run this I get next messages:
Exception in thread "Thread-1" by.westside.staircase.core.exception.RequestFormatException: Incorrect first line: INCORRECT LINE
at by.westside.staircase.core.util.HttpUtil.parseHttpRequest(HttpUtil.kt:19)
at by.westside.staircase.core.server.ServerThread.run(ServerThread.kt:26)
at java.lang.Thread.run(Thread.java:745)
Expected exception of type 'by.westside.staircase.core.exception.RequestFormatException', but no exception was thrown
at org.spockframework.lang.SpecInternals.checkExceptionThrown(SpecInternals.java:79)
at org.spockframework.lang.SpecInternals.thrownImpl(SpecInternals.java:66)
at by.westside.staircase.core.server.SyncServerSpec.should throw exception in incorrect first line case(SyncServerSpec.groovy:26)
Spock, like JUnit, can only assert on exceptions thrown from the thread executing the test, not "any thread in the application". Your exceptions are not caught by spock, and can't be asserted.
You can play with Thread.uncaughtExceptionHandler but you should probably unit-test the runnable executed in your thread - or implement some error handling in your business logic, and test this part of the code.
I think another option is to actually catch the exception in your test case and assert on that. here is a snippet of my code (written in Groovy Spock):
def exceptionThrown = false
def exceptionMessage
def thread = new Thread( {_ ->
try{
//code you are testing
} catch(Exception e) { // change this to the exception you want to catch
exceptionThrown = true
exceptionMessage = e.getMessage()
}
})
then: "the right exception should be thrown"
exceptionThrown
exceptionMessage = "I am thrown" //this should be your error message
I ran into the same issue and took a simple, hokey route. In the spirit of "good software is testable software" I added a flag and asserted on that, labeling it: // only for testing. Which, of course, will be ignored down the road.
thrown(RequestFormatException)
this should be in your first line after then: as this is the constraint imposed by spock.
Whenever thrown or notThrown is called in it should be the first statement.
Note: thrown and notThrown both return true and hence there should be no comparison operator as well.
Hence, In your case , it should be like below:
then:
thrown(RequestFormatException)

Fail early vs. robust methods

I'm constantly (since years) wondering the most senseful way to implement the following (it's kind of paradoxic for me):
Imagine a function:
DoSomethingWith(value)
{
if (value == null) { // Robust: Check parameter(s) first
throw new ArgumentNullException(value);
}
// Some code ...
}
It's called like:
SomeFunction()
{
if (value == null) { // Fail early
InformUser();
return;
}
DoSomethingWith(value);
}
But, to catch the ArgumentNullException, should I do:
SomeFunction()
{
if (value == null) { // Fail early
InformUser();
return;
}
try { // If throwing an Exception, why not *not* check for it (even if you checked already)?
DoSomethingWith(value);
} catch (ArgumentNullException) {
InformUser();
return;
}
}
or just:
SomeFunction()
{
try { // No fail early anymore IMHO, because you could fail before calling DoSomethingWith(value)
DoSomethingWith(value);
} catch (ArgumentNullException) {
InformUser();
return;
}
}
?
This is a very general question and the right solution depends on the specific code and architecture.
Generally regarding error handling
The main focus should be to catch the exception on the level where you can handle it.
Handling the exceptions at the right place makes the code robust, so the exception doesn't make the application fail and the exception can be handled accordingly.
Failing early makes the application robust, because this helps avoiding inconsistent states.
This also means that there should be a more general try catch block at the root of the execution to catch any non fatal application error which couldn't be handled. Which often means that you as a programmer didn't think of this error source. Later you can extend your code to also handle this error. But the execution root shouldn't be the only place where you think of exception handling.
Your example
In your example regarding ArgumentNullException:
Yes, you should fail early. Whenever your method is invoked with an invalid null argument, you should throw this exception.
But you should never catch this exception, cause it should be possible to avoid it. See this post related to the topic: If catching null pointer exception is not a good practice, is catching exception a good one?
If you are working with user input or input from other systems, then you should validate the input. E.g. you can display validation error on the UI after null checking without throwing an exception. It is always a critical part of error handling how to show the issues to users, so define a proper strategy for your application. You should try to avoid throwing exceptions in the expected program execution flow. See this article: https://msdn.microsoft.com/en-us/library/ms173163.aspx
See general thoughts about exception handling below:
Handling exceptions in your method
If an exception is thrown in the DoSomethingWith method and you can handle it and continue the flow of execution without any issue, then of course you should do those.
This is a pseudo code example for retrying a database operation:
void DoSomethingAndRetry(value)
{
try
{
SaveToDatabase(value);
}
catch(DeadlockException ex)
{
//deadlock happened, we are retrying the SQL statement
SaveToDatabase(value);
}
}
Letting the exception bubble up
Let's assume your method is public. If an exception happens which implies that the method failed and you can't continue execution, then the exception should bubble up, so that the calling code can handle it accordingly. It depends one the use-case how the calling code would react on the exception.
Before letting the exception bubble up you may wrap it into another application specific exception as inner exception to add additional context information. You may also process the exception somehow, E.g log it , or leave the logging to the calling code, depending on your logging architecture.
public bool SaveSomething(value)
{
try
{
SaveToFile(value);
}
catch(FileNotFoundException ex)
{
//process exception if needed, E.g. log it
ProcessException(ex);
//you may want to wrap this exception into another one to add context info
throw WrapIntoNewExceptionWithSomeDetails(ex);
}
}
Documenting possible exceptions
In .NET it is also helpful to define which exceptions your method is throwing and reasons why it might throw it. So that the calling code can take this into consideration. See https://msdn.microsoft.com/en-us/library/w1htk11d.aspx
Example:
/// <exception cref="System.Exception">Thrown when something happens..</exception>
DoSomethingWith(value)
{
...
}
Ignoring exceptions
For methods where you are OK with a failing method and don't want to add a try catch block around it all the time, you could create a method with similar signature:
public bool TryDoSomethingWith(value)
{
try
{
DoSomethingWith(value);
return true;
}
catch(Exception ex)
{
//process exception if needed, e.g. log it
ProcessException(ex);
return false;
}
}

Resources