2018-09-21 16:55:31 +02:00
import static com . sap . piper . Prerequisites . checkScript
2018-01-29 17:47:22 +02:00
import com.cloudbees.groovy.cps.NonCPS
2018-02-01 13:57:25 +02:00
2019-03-28 14:27:41 +02:00
import com.sap.piper.GenerateDocumentation
2018-08-15 11:53:28 +02:00
import com.sap.piper.ConfigurationHelper
2018-02-08 11:21:38 +02:00
import com.sap.piper.MapUtils
2018-08-15 11:53:28 +02:00
import com.sap.piper.Utils
2018-01-29 17:47:22 +02:00
2018-02-01 13:57:25 +02:00
import groovy.transform.Field
2018-11-29 10:54:05 +02:00
@Field def STEP_NAME = getClass ( ) . getName ( )
2018-08-15 11:53:28 +02:00
2018-02-19 13:53:08 +02:00
@Field Set TOOLS = [
2019-03-28 14:27:41 +02:00
/ * *
* Allows to publish the check results .
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'aggregation' ,
/ * *
* Searches and publishes TODOs in files with the [ Task Scanner Plugin ] ( https: //wiki.jenkins-ci.org/display/JENKINS/Task+Scanner+Plugin).
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'tasks' ,
/ * *
* Publishes PMD findings with the [ PMD plugin ] ( https: //plugins.jenkins.io/pmd).
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'pmd' ,
/ * *
* Publishes CPD findings with the [ DRY plugin ] ( https: //plugins.jenkins.io/dry).
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'cpd' ,
/ * *
* Publishes Findbugs findings with the [ Findbugs plugin ] ( https: //plugins.jenkins.io/findbugs).
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'findbugs' ,
/ * *
* Publishes Checkstyle findings with the [ Checkstyle plugin ] ( https: //plugins.jenkins.io/checkstyle).
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'checkstyle' ,
/ * *
* Publishes ESLint findings ( in [ JSLint format ] ( https: //eslint.org/docs/user-guide/formatters/)) with the [Warnings plugin](https://plugins.jenkins.io/warnings).
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'eslint' ,
/ * *
* Publishes PyLint findings with the [ Warnings plugin ] ( https: //plugins.jenkins.io/warnings), pylint needs to run with `--output-format=parseable` option.
* @possibleValues ` true ` , ` false ` , ` Map `
* /
'pylint'
2018-02-16 11:08:48 +02:00
]
2018-01-31 17:56:18 +02:00
2018-08-15 11:53:28 +02:00
@Field Set GENERAL_CONFIG_KEYS = [ ]
2020-12-11 15:49:36 +02:00
@Field Set STEP_CONFIG_KEYS = TOOLS . plus ( [
/ * *
* If it is set to ` true ` the step will archive reports matching the tool specific pattern .
* @possibleValues ` true ` , ` false `
* /
'archive' ,
/ * *
* If it is set to ` true ` the step will fail the build if JUnit detected any failing tests .
* @possibleValues ` true ` , ` false `
* /
'failOnError'
] )
2018-08-15 11:53:28 +02:00
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
2018-01-29 17:47:22 +02:00
/ * *
2019-03-28 14:27:41 +02:00
* This step can publish static check results from various sources .
2018-01-29 17:47:22 +02:00
* /
2019-03-28 14:27:41 +02:00
@GenerateDocumentation
2018-08-30 16:33:07 +02:00
void call ( Map parameters = [ : ] ) {
2018-02-01 13:57:25 +02:00
handlePipelineStepErrors ( stepName: STEP_NAME , stepParameters: parameters ) {
2018-09-21 16:55:31 +02:00
2020-08-26 15:32:58 +02:00
def script = checkScript ( this , parameters ) ? : this
2018-08-15 11:53:28 +02:00
2018-02-08 11:53:48 +02:00
prepare ( parameters )
2020-08-26 15:32:58 +02:00
String stageName = parameters . stageName ? : env . STAGE_NAME
2018-08-15 11:53:28 +02:00
// load default & individual configuration
2018-10-17 11:05:20 +02:00
Map configuration = ConfigurationHelper . newInstance ( this )
2020-08-26 15:32:58 +02:00
. loadStepDefaults ( [ : ] , stageName )
2018-08-15 11:53:28 +02:00
. mixinGeneralConfig ( script . commonPipelineEnvironment , GENERAL_CONFIG_KEYS )
. mixinStepConfig ( script . commonPipelineEnvironment , STEP_CONFIG_KEYS )
2020-08-26 15:32:58 +02:00
. mixinStageConfig ( script . commonPipelineEnvironment , stageName , STEP_CONFIG_KEYS )
2018-08-15 11:53:28 +02:00
. mixin ( parameters , PARAMETER_KEYS )
. use ( )
2018-02-08 11:53:48 +02:00
2020-11-25 16:39:33 +02:00
if ( configuration . aggregation & & configuration . aggregation . active ! = false ) {
error "[ERROR] Configuration of the aggregation view is no longer possible. Migrate any thresholds defined here to tool specific quality gates. (piper-lib/${STEP_NAME})"
}
2019-01-21 09:47:34 +02:00
new Utils ( ) . pushToSWA ( [
step: STEP_NAME ,
stepParamKey1: 'scriptMissing' ,
stepParam1: parameters ? . script = = null
] , configuration )
2018-02-01 13:57:25 +02:00
2018-01-29 17:29:00 +02:00
// JAVA
2021-07-12 10:02:09 +02:00
if ( configuration . pmd . active ) {
report ( pmdParser ( createToolOptions ( configuration . pmd ) ) , configuration . pmd , configuration . archive )
}
if ( configuration . cpd . active ) {
report ( cpd ( createToolOptions ( configuration . cpd ) ) , configuration . cpd , configuration . archive )
}
if ( configuration . findbugs . active ) {
report ( findBugs ( createToolOptions ( configuration . findbugs , [ useRankAsPriority: true ] ) ) , configuration . findbugs , configuration . archive )
}
if ( configuration . checkstyle . active ) {
report ( checkStyle ( createToolOptions ( configuration . checkstyle ) ) , configuration . checkstyle , configuration . archive )
}
2018-01-29 17:29:00 +02:00
// JAVA SCRIPT
2021-07-12 10:02:09 +02:00
if ( configuration . eslint . active ) {
report ( esLint ( createToolOptions ( configuration . eslint ) ) , configuration . eslint , configuration . archive )
}
2018-01-29 17:29:00 +02:00
// PYTHON
2021-07-12 10:02:09 +02:00
if ( configuration . pylint . active ) {
report ( pyLint ( createToolOptions ( configuration . pylint ) ) , configuration . pylint , configuration . archive )
}
2018-02-01 13:57:25 +02:00
// GENERAL
2021-07-12 10:02:09 +02:00
if ( configuration . tasks . active ) {
report ( taskScanner ( createToolOptions ( configuration . tasks , [
includePattern: configuration . tasks . get ( 'pattern' ) ,
highTags: configuration . tasks . get ( 'high' ) ,
normalTags: configuration . tasks . get ( 'normal' ) ,
lowTags: configuration . tasks . get ( 'low' ) ,
] ) . minus ( [ pattern: configuration . tasks . get ( 'pattern' ) ] ) ) , configuration . tasks , configuration . archive )
}
2020-12-11 15:49:36 +02:00
if ( configuration . failOnError & & 'FAILURE' = = script . currentBuild ? . result ) {
script . currentBuild . result = 'FAILURE'
error "[${STEP_NAME}] Some checks failed!"
}
2018-02-01 13:57:25 +02:00
}
}
2020-11-25 16:39:33 +02:00
def report ( tool , settings , doArchive ) {
2021-07-12 10:02:09 +02:00
def options = createOptions ( settings ) . plus ( [ tools: [ tool ] ] )
echo "recordIssues OPTIONS: ${options}"
// publish
recordIssues ( options )
// archive check results
archiveResults ( doArchive & & settings . get ( 'archive' ) , settings . get ( 'pattern' ) , true )
2018-01-29 17:29:00 +02:00
}
def archiveResults ( archive , pattern , allowEmpty ) {
if ( archive ) {
2018-02-01 13:57:25 +02:00
echo "[${STEP_NAME}] archive ${pattern}"
2018-01-29 17:29:00 +02:00
archiveArtifacts artifacts: pattern , allowEmptyArchive: allowEmpty
}
}
2018-01-30 14:15:49 +02:00
@NonCPS
2020-11-25 16:39:33 +02:00
def createOptions ( settings ) {
2018-01-30 14:15:49 +02:00
Map result = [ : ]
2020-11-25 16:39:33 +02:00
result . put ( 'blameDisabled' , true )
result . put ( 'enabledForFailure' , true )
result . put ( 'aggregatingResults' , false )
def qualityGates = [ ]
if ( settings . qualityGates )
qualityGates = qualityGates . plus ( settings . qualityGates )
// handle legacy thresholds
// https://github.com/jenkinsci/warnings-ng-plugin/blob/6602c3a999b971405adda15be03979ce21cb3cbf/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGate.java#L186
def thresholdsList = settings . get ( 'thresholds' , [ : ] )
if ( thresholdsList ) {
for ( String status : [ 'fail' , 'unstable' ] ) {
def thresholdsListPerStatus = thresholdsList . get ( status , [ : ] )
if ( thresholdsListPerStatus ) {
for ( String severity : [ 'all' , 'high' , 'normal' , 'low' ] ) {
def threshold = thresholdsListPerStatus . get ( severity )
if ( threshold = = null )
continue
threshold = threshold . toInteger ( ) + 1
def type = "TOTAL"
if ( severity ! = 'all' )
type + = "_" + severity . toUpperCase ( )
def gate = [ threshold: threshold , type: type , unstable: status = = 'unstable' ]
echo "[WARNING] legacy threshold found, please migrate to quality gate (piper-lib/checksPublishResults)"
echo "legacy threshold transformed to quality gate: ${gate}"
qualityGates = qualityGates . plus ( [ gate ] )
}
}
}
}
result . put ( 'qualityGates' , qualityGates )
// filter empty values
result = result . findAll {
return it . value ! = null & & it . value ! = ''
}
return result
}
@NonCPS
def createToolOptions ( settings , additionalOptions = [ : ] ) {
Map result = [ pattern: settings . get ( 'pattern' ) ]
if ( settings . id )
2020-12-03 15:16:04 +02:00
result . put ( 'id' , settings . id )
2020-11-25 16:39:33 +02:00
if ( settings . name )
result . put ( 'name' , settings . name )
result = result . plus ( additionalOptions )
2018-02-08 11:43:24 +02:00
// filter empty values
result = result . findAll {
return it . value ! = null & & it . value ! = ''
}
2018-01-29 17:29:00 +02:00
return result
}
2018-02-01 13:57:25 +02:00
def prepare ( parameters ) {
2018-02-08 11:51:39 +02:00
// ensure tool maps are initialized correctly
2018-02-16 11:08:48 +02:00
for ( String tool : TOOLS ) {
2018-02-08 11:51:39 +02:00
parameters [ tool ] = toMap ( parameters [ tool ] )
}
2018-02-01 13:57:25 +02:00
return parameters
}
2018-02-08 11:50:11 +02:00
def toMap ( parameter ) {
if ( MapUtils . isMap ( parameter ) )
parameter . put ( 'active' , parameter . active = = null ? true : parameter . active )
else if ( Boolean . TRUE . equals ( parameter ) )
parameter = [ active: true ]
else if ( Boolean . FALSE . equals ( parameter ) )
parameter = [ active: false ]
else
parameter = [ : ]
return parameter
}