2019-03-20 12:21:06 +02:00
import com.cloudbees.groovy.cps.NonCPS
2019-03-29 14:12:28 +02:00
import com.sap.piper.GenerateDocumentation
2019-03-20 12:21:06 +02:00
import com.sap.piper.ConfigurationHelper
2019-04-11 11:39:41 +02:00
import com.sap.piper.analytics.InfluxData
2019-03-20 12:21:06 +02:00
2018-10-24 13:36:30 +02:00
import groovy.text.SimpleTemplateEngine
2018-10-09 17:09:55 +02:00
import groovy.transform.Field
2019-04-04 08:38:54 +02:00
import hudson.AbortException
2018-10-09 17:09:55 +02:00
2019-04-05 11:16:34 +02:00
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
2018-11-29 10:54:05 +02:00
@Field STEP_NAME = getClass ( ) . getName ( )
2018-10-09 17:09:55 +02:00
2019-03-20 12:21:06 +02:00
@Field Set GENERAL_CONFIG_KEYS = [ ]
2019-04-04 08:38:54 +02:00
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS . plus ( [
/ * *
* Defines the behavior , in case an error occurs which is handled by this step . When set to ` false ` an error results in an "UNSTABLE" build result and the pipeline can continue .
* @possibleValues ` true ` , ` false `
* /
'failOnError' ,
/** Defines a list of mandatory steps (step names) which have to be successful (=stop the pipeline), even if `failOnError: false` */
2019-04-05 11:16:34 +02:00
'mandatorySteps' ,
/ * *
* Defines a Map containing step name as key and timout in minutes in order to stop an execution after a certain timeout .
* This helps to make pipeline runs more resilient with respect to long running steps .
* * /
'stepTimeouts'
2019-04-04 08:38:54 +02:00
] )
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS . plus ( [
2019-03-29 14:12:28 +02:00
/ * *
2019-04-03 13:16:38 +02:00
* If it is set to true details will be output to the console . See example below .
2019-03-29 14:12:28 +02:00
* @possibleValues ` true ` , ` false `
* /
2019-03-20 12:21:06 +02:00
'echoDetails' ,
2019-03-29 14:12:28 +02:00
/** Defines the url of the library's documentation that will be used to generate the corresponding links to the step documentation.*/
2019-03-20 12:21:06 +02:00
'libraryDocumentationUrl' ,
2019-03-29 14:12:28 +02:00
/** Defines the url of the library's repository that will be used to generate the corresponding links to the step implementation.*/
2019-03-20 12:21:06 +02:00
'libraryRepositoryUrl' ,
2019-04-04 08:38:54 +02:00
/** Defines the name of the step for which the error handling is active. It will be shown in the console log.*/
2019-03-20 12:21:06 +02:00
'stepName' ,
2019-04-04 08:38:54 +02:00
/** Defines the documented step, in case the documentation reference should point to a different step. */
2019-03-20 12:21:06 +02:00
'stepNameDoc' ,
2019-04-04 08:38:54 +02:00
/** Passes the parameters of the step which uses the error handling onto the error handling. The list of parameters is then shown in the console output.*/
2019-03-20 12:21:06 +02:00
'stepParameters'
2019-04-04 08:38:54 +02:00
] )
2019-03-20 12:21:06 +02:00
2019-03-29 14:12:28 +02:00
/ * *
* Used by other steps to make error analysis easier . Lists parameters and other data available to the step in which the error occurs .
* /
@GenerateDocumentation
2018-08-30 16:33:07 +02:00
void call ( Map parameters = [ : ] , body ) {
2019-03-20 12:21:06 +02:00
// load default & individual configuration
2019-05-03 14:06:49 +02:00
def cpe = parameters . stepParameters ? . script ? . commonPipelineEnvironment ? : null
2019-03-20 12:21:06 +02:00
Map config = ConfigurationHelper . newInstance ( this )
. loadStepDefaults ( )
2019-04-04 08:38:54 +02:00
. mixinGeneralConfig ( cpe , GENERAL_CONFIG_KEYS )
. mixinStepConfig ( cpe , STEP_CONFIG_KEYS )
. mixinStageConfig ( cpe , parameters . stepParameters ? . stageName ? : env . STAGE_NAME , STEP_CONFIG_KEYS )
2019-03-20 12:21:06 +02:00
. mixin ( parameters , PARAMETER_KEYS )
. withMandatoryProperty ( 'stepParameters' )
. withMandatoryProperty ( 'stepName' )
. addIfEmpty ( 'stepNameDoc' , parameters . stepName )
. use ( )
2018-10-24 13:36:30 +02:00
def message = ''
2017-07-11 15:12:03 +02:00
try {
2019-03-20 12:21:06 +02:00
if ( config . echoDetails )
echo "--- Begin library step of: ${config.stepName} ---"
2019-04-05 11:16:34 +02:00
if ( ! config . failOnError & & config . stepTimeouts ? . get ( config . stepName ) ) {
timeout ( time: config . stepTimeouts [ config . stepName ] ) {
body ( )
}
} else {
body ( )
}
} catch ( AbortException | FlowInterruptedException ex ) {
2019-04-04 08:38:54 +02:00
if ( config . echoDetails )
2019-04-05 11:16:34 +02:00
message + = formatErrorMessage ( config , ex )
writeErrorToInfluxData ( config , ex )
2019-04-04 08:38:54 +02:00
if ( config . failOnError | | config . stepName in config . mandatorySteps ) {
2019-04-05 11:16:34 +02:00
throw ex
2019-04-04 08:38:54 +02:00
}
2019-05-03 14:06:49 +02:00
2019-04-04 08:38:54 +02:00
if ( config . stepParameters ? . script ) {
config . stepParameters ? . script . currentBuild . result = 'UNSTABLE'
} else {
currentBuild . result = 'UNSTABLE'
}
2019-05-03 14:06:49 +02:00
echo "[${STEP_NAME}] Error in step ${config.stepName} - Build result set to 'UNSTABLE'"
List unstableSteps = cpe ? . getValue ( 'unstableSteps' ) ? : [ ]
if ( ! unstableSteps ) {
unstableSteps = [ ]
}
// add information about unstable steps to pipeline environment
// this helps to bring this information to users in a consolidated manner inside a pipeline
unstableSteps . add ( config . stepName )
cpe ? . setValue ( 'unstableSteps' , unstableSteps )
2019-03-14 14:51:00 +02:00
} catch ( Throwable error ) {
2019-03-20 12:21:06 +02:00
if ( config . echoDetails )
message + = formatErrorMessage ( config , error )
writeErrorToInfluxData ( config , error )
2019-03-14 14:51:00 +02:00
throw error
2017-07-11 15:12:03 +02:00
} finally {
2019-03-20 12:21:06 +02:00
if ( config . echoDetails )
message + = "--- End library step of: ${config.stepName} ---"
2018-10-24 13:36:30 +02:00
echo message
2017-07-11 15:12:03 +02:00
}
}
2019-03-14 14:51:00 +02:00
2019-03-20 12:21:06 +02:00
@NonCPS
private String formatErrorMessage ( Map config , error ) {
Map binding = [
error: error ,
libraryDocumentationUrl: config . libraryDocumentationUrl ,
libraryRepositoryUrl: config . libraryRepositoryUrl ,
stepName: config . stepName ,
stepParameters: config . stepParameters ? . toString ( )
]
return SimpleTemplateEngine
. newInstance ( )
. createTemplate ( libraryResource ( 'com.sap.piper/templates/error.log' ) )
. make ( binding )
. toString ( )
}
private void writeErrorToInfluxData ( Map config , error ) {
2019-04-11 11:39:41 +02:00
if ( InfluxData . getInstance ( ) . getFields ( ) . pipeline_data ? . build_error_message = = null ) {
InfluxData . addTag ( 'pipeline_data' , 'build_error_step' , config . stepName )
InfluxData . addTag ( 'pipeline_data' , 'build_error_stage' , config . stepParameters . script ? . env ? . STAGE_NAME )
InfluxData . addField ( 'pipeline_data' , 'build_error_message' , error . getMessage ( ) )
2019-03-14 14:51:00 +02:00
}
}