2019-02-05 16:37:59 +02:00
import com.sap.piper.ConfigurationHelper
2019-07-03 10:13:26 +02:00
import com.sap.piper.GenerateStageDocumentation
import com.sap.piper.JenkinsUtils
2020-08-28 16:11:35 +02:00
import com.sap.piper.StageNameProvider
2019-02-05 16:37:59 +02:00
import com.sap.piper.Utils
2020-09-28 10:44:56 +02:00
import com.sap.piper.k8s.ContainerMap
2019-02-05 16:37:59 +02:00
import groovy.transform.Field
import static com . sap . piper . Prerequisites . checkScript
@Field String STEP_NAME = getClass ( ) . getName ( )
2020-08-28 16:11:35 +02:00
@Field String TECHNICAL_STAGE_NAME = 'init'
2019-02-05 16:37:59 +02:00
@Field Set GENERAL_CONFIG_KEYS = [
2019-07-03 10:13:26 +02:00
/ * *
* Defines the build tool used .
* @possibleValues ` docker ` , ` kaniko ` , ` maven ` , ` mta , ` ` npm `
* /
2019-02-05 16:37:59 +02:00
'buildTool' ,
2020-09-28 10:44:56 +02:00
/ * *
* Defines the library resource containing the container map .
* /
'containerMapResource' ,
/ * *
* Enable automatic inference of build tool ( maven , npm , mta ) based on existing project files .
* If this is set to true , it is not required to provide the ` buildTool ` parameter in the ` general ` section of the pipeline configuration .
* /
'inferBuildTool' ,
2020-10-05 19:34:43 +02:00
/ * *
* Enables automatic inference from the build descriptor in case projectName is not configured .
* /
'inferProjectName' ,
2020-09-28 10:44:56 +02:00
/ * *
* Defines the library resource containing the legacy configuration definition .
* /
'legacyConfigSettings' ,
2019-07-03 10:13:26 +02:00
/ * *
* Defines the main branch for your pipeline . * * Typically this is the ` master ` branch , which does not need to be set explicitly . * * Only change this in exceptional cases
* /
2019-02-05 16:37:59 +02:00
'productiveBranch' ,
2020-10-05 19:34:43 +02:00
/ * *
* Name of the project , e . g . used for the name of lockable resources .
* /
'projectName' ,
2020-09-28 10:44:56 +02:00
/ * *
2021-04-30 10:14:14 +02:00
* Specify to execute artifact versioning in a kubernetes pod .
* @possibleValues ` true ` , ` false `
* /
'runArtifactVersioningOnPod' ,
/ * *
* Defines the library resource containing stage /step initialization settings. Those define conditions when certain steps/ stages will be activated . * * Caution: changing the default will break the standard behavior of the pipeline - thus only relevant when including ` Init ` stage into custom pipelines ! * *
2020-09-28 10:44:56 +02:00
* /
'stageConfigResource' ,
2019-07-03 10:13:26 +02:00
/ * *
* Defines the library resource containing the stash settings to be performed before and after each stage . * * Caution: changing the default will break the standard behavior of the pipeline - thus only relevant when including ` Init ` stage into custom pipelines ! * *
* /
2019-02-05 16:37:59 +02:00
'stashSettings' ,
2019-07-03 10:13:26 +02:00
/ * *
* Whether verbose output should be produced .
* @possibleValues ` true ` , ` false `
* /
2019-02-05 16:37:59 +02:00
'verbose'
]
2019-07-03 10:13:26 +02:00
@Field STAGE_STEP_KEYS = [ ]
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS . plus ( STAGE_STEP_KEYS )
2020-09-28 10:44:56 +02:00
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS . plus ( [
/ * *
* Enables the use of technical stage names .
* /
'useTechnicalStageNames' ,
2020-11-12 21:35:59 +02:00
/ * *
* Provides a clone from the specified repository .
* This map contains attributes , such as , ` branches ` , ` extensions ` , ` userRemoteConfigs ` etc .
* Example: ` [ $class : 'GitSCM' , branches: [ [ name: < branch_to_be_cloned > ] ] , userRemoteConfigs: [ [ credentialsId: < credential_to_access_repository > , url: < repository_url > ] ] ] ` .
* /
'checkoutMap' ,
2021-02-11 17:21:57 +02:00
/ * *
* The map returned from a Jenkins git checkout . Used to set the git information in the
* common pipeline environment .
* /
'scmInfo' ,
/ * *
* Optional skip of checkout if checkout was done before this step already .
* @possibleValues ` true ` , ` false `
* /
'skipCheckout' ,
2021-09-08 08:13:32 +02:00
/ * *
* Mandatory if you skip the checkout . Then you need to unstash your workspace to get the e . g . configuration .
* /
'stashContent' ,
2020-10-05 12:12:06 +02:00
/ * *
* Optional path to the pipeline configuration file defining project specific settings .
* /
'configFile' ,
/ * *
* Optional list of file names which will be extracted from library resources and which serve as source for
* default values for the pipeline configuration . These are merged with and override built - in defaults , with
* a parameter supplied by the last resource file taking precedence over the same parameter supplied in an
* earlier resource file or built - in default .
* /
'customDefaults' ,
/ * *
* Optional list of file paths or URLs which must point to YAML content . These work exactly like
* ` customDefaults ` , but from local or remote files instead of library resources . They are merged with and
* take precedence over ` customDefaults ` .
* /
'customDefaultsFromFiles'
2020-09-28 10:44:56 +02:00
] )
2019-02-05 16:37:59 +02:00
2019-07-03 10:13:26 +02:00
/ * *
* This stage initializes the pipeline run and prepares further execution .
*
* It will check out your repository and perform some steps to initialize your pipeline run .
* /
@GenerateStageDocumentation ( defaultStageName = 'Init' )
2019-02-05 16:37:59 +02:00
void call ( Map parameters = [ : ] ) {
def script = checkScript ( this , parameters ) ? : this
def utils = parameters . juStabUtils ? : new Utils ( )
2020-09-28 10:44:56 +02:00
if ( parameters . useTechnicalStageNames ) {
StageNameProvider . instance . useTechnicalStageNames = true
}
2020-08-28 16:11:35 +02:00
def stageName = StageNameProvider . instance . getStageName ( script , parameters , this )
2019-02-05 16:37:59 +02:00
2020-03-19 11:49:28 +02:00
piperStageWrapper ( script: script , stageName: stageName , stashContent: [ ] , ordinal: 1 , telemetryDisabled: true ) {
2021-02-11 17:21:57 +02:00
def skipCheckout = parameters . skipCheckout
if ( skipCheckout ! = null & & ! ( skipCheckout instanceof Boolean ) ) {
error "[${STEP_NAME}] Parameter skipCheckout has to be of type boolean. Instead got '${skipCheckout.class.getName()}'"
}
def scmInfo = parameters . scmInfo
if ( skipCheckout & & ! scmInfo ) {
error "[${STEP_NAME}] Need am scmInfo map retrieved from a checkout. " +
"If you want to skip the checkout the scm info needs to be provided by you with parameter scmInfo, " +
"for example as follows:\n" +
" def scmInfo = checkout scm\n" +
" piperPipelineStageInit script:this, skipCheckout: true, scmInfo: scmInfo"
}
if ( ! skipCheckout ) {
scmInfo = checkout ( parameters . checkoutMap ? : scm )
}
2021-09-08 08:13:32 +02:00
else {
def stashContent = parameters . stashContent
if ( stashContent = = null | | stashContent . size ( ) = = 0 ) {
error "[${STEP_NAME}] needs stashes if you skip checkout"
}
utils . unstashAll ( stashContent )
}
2019-02-05 16:37:59 +02:00
2020-11-11 11:44:49 +02:00
setupCommonPipelineEnvironment ( script: script , customDefaults: parameters . customDefaults , scmInfo: scmInfo ,
2020-10-05 12:12:06 +02:00
configFile: parameters . configFile , customDefaultsFromFiles: parameters . customDefaultsFromFiles )
2019-02-05 16:37:59 +02:00
Map config = ConfigurationHelper . newInstance ( this )
. loadStepDefaults ( )
. mixinGeneralConfig ( script . commonPipelineEnvironment , GENERAL_CONFIG_KEYS )
. mixinStageConfig ( script . commonPipelineEnvironment , stageName , STEP_CONFIG_KEYS )
. mixin ( parameters , PARAMETER_KEYS )
. addIfEmpty ( 'stageConfigResource' , 'com.sap.piper/pipeline/stageDefaults.yml' )
. addIfEmpty ( 'stashSettings' , 'com.sap.piper/pipeline/stashSettings.yml' )
2020-09-28 10:44:56 +02:00
. addIfEmpty ( 'buildTool' , script . commonPipelineEnvironment . buildTool )
2019-02-05 16:37:59 +02:00
. withMandatoryProperty ( 'buildTool' )
. use ( )
2020-09-28 10:44:56 +02:00
if ( config . legacyConfigSettings ) {
Map legacyConfigSettings = readYaml ( text: libraryResource ( config . legacyConfigSettings ) )
2020-11-09 11:15:43 +02:00
checkForLegacyConfiguration ( script: script , legacyConfigSettings: legacyConfigSettings )
2020-09-28 10:44:56 +02:00
}
String buildTool = checkBuildTool ( config )
2020-10-05 19:34:43 +02:00
script . commonPipelineEnvironment . projectName = config . projectName
if ( ! script . commonPipelineEnvironment . projectName & & config . inferProjectName ) {
script . commonPipelineEnvironment . projectName = inferProjectName ( script , buildTool )
}
2020-09-28 10:44:56 +02:00
if ( Boolean . valueOf ( env . ON_K8S ) & & config . containerMapResource ) {
ContainerMap . instance . initFromResource ( script , config . containerMapResource , buildTool )
}
2021-02-11 17:21:57 +02:00
initStashConfiguration ( script , config . stashSettings , config . verbose ? : false )
2019-02-05 16:37:59 +02:00
if ( config . verbose ) {
echo "piper-lib-os configuration: ${script.commonPipelineEnvironment.configuration}"
}
// telemetry reporting
utils . pushToSWA ( [ step: STEP_NAME ] , config )
piperInitRunStageConfiguration script: script , stageConfigResource: config . stageConfigResource
2019-07-03 10:13:26 +02:00
// CHANGE_ID is set only for pull requests
if ( env . CHANGE_ID ) {
List prActions = [ ]
//get trigger action from comment like /piper action
def jenkinsUtils = new JenkinsUtils ( )
def commentTriggerAction = jenkinsUtils . getIssueCommentTriggerAction ( )
if ( commentTriggerAction ! = null ) prActions . add ( commentTriggerAction )
try {
prActions . addAll ( pullRequest . getLabels ( ) . asList ( ) )
} catch ( ex ) {
echo "[${STEP_NAME}] GitHub labels could not be retrieved from Pull Request, please make sure that credentials are maintained on multi-branch job."
}
setPullRequestStageStepActivation ( script , config , prActions )
}
2019-02-05 16:37:59 +02:00
if ( env . BRANCH_NAME = = config . productiveBranch ) {
2019-05-10 06:47:44 +02:00
if ( parameters . script . commonPipelineEnvironment . configuration . runStep ? . get ( 'Init' ) ? . slackSendNotification ) {
slackSendNotification script: script , message: "STARTED: Job <${env.BUILD_URL}|${URLDecoder.decode(env.JOB_NAME, java.nio.charset.StandardCharsets.UTF_8.name())} ${env.BUILD_DISPLAY_NAME}>" , color: 'WARNING'
}
2020-11-16 17:38:17 +02:00
Map prepareVersionParams = [ script: script ]
if ( config . inferBuildTool ) {
prepareVersionParams . buildTool = buildTool
}
2021-04-30 10:14:14 +02:00
if ( env . ON_K8S & & ! config . runArtifactVersioningOnPod ) {
2020-11-16 17:38:17 +02:00
// We force dockerImage: "" for the K8S case to avoid the execution of artifactPrepareVersion in a K8S Pod.
// Since artifactPrepareVersion may need the ".git" folder in order to push a tag, it would need to be part of the stashing.
// There are however problems with tar-ing this folder, which results in a failure to copy the stash back -- without a failure of the pipeline.
// This then also has the effect that any changes made to the build descriptors by the step (updated version) are not visible in the relevant stashes.
2020-09-28 10:44:56 +02:00
// In addition, a mvn executable is available on the Jenkins instance which can be used directly instead of executing the command in a container.
2020-11-16 17:38:17 +02:00
prepareVersionParams . dockerImage = ""
2020-09-28 10:44:56 +02:00
}
2020-11-16 17:38:17 +02:00
artifactPrepareVersion prepareVersionParams
2019-02-05 16:37:59 +02:00
}
pipelineStashFilesBeforeBuild script: script
}
}
2020-10-05 19:34:43 +02:00
private String inferProjectName ( Script script , String buildTool ) {
switch ( buildTool ) {
case 'maven' :
def pom = script . readMavenPom file: 'pom.xml'
return "${pom.groupId}-${pom.artifactId}"
case 'npm' :
Map packageJson = script . readJSON file: 'package.json'
return packageJson . name
case 'mta' :
Map mta = script . readYaml file: 'mta.yaml'
return mta . ID
}
script . error "Cannot infer projectName. Project buildTool was none of the expected ones 'mta', 'maven', or 'npm'."
}
2020-09-28 10:44:56 +02:00
private String checkBuildTool ( config ) {
2019-02-05 16:37:59 +02:00
def buildDescriptorPattern = ''
2020-09-28 10:44:56 +02:00
String buildTool = config . buildTool
switch ( buildTool ) {
2019-02-05 16:37:59 +02:00
case 'maven' :
buildDescriptorPattern = 'pom.xml'
break
case 'npm' :
buildDescriptorPattern = 'package.json'
break
case 'mta' :
buildDescriptorPattern = 'mta.yaml'
break
}
if ( buildDescriptorPattern & & ! findFiles ( glob: buildDescriptorPattern ) ) {
2020-12-14 16:02:49 +02:00
error "[${STEP_NAME}] buildTool configuration '${config.buildTool}' does not fit to your project, please set buildTool as general setting in your .pipeline/config.yml correctly, see also https://sap.github.io/jenkins-library/configuration/"
2019-02-05 16:37:59 +02:00
}
2020-09-28 10:44:56 +02:00
return buildTool
2019-02-05 16:37:59 +02:00
}
2020-09-28 10:44:56 +02:00
private void initStashConfiguration ( script , stashSettings , verbose ) {
Map stashConfiguration = readYaml ( text: libraryResource ( stashSettings ) )
if ( verbose ) echo "Stash config: ${stashConfiguration}"
2019-02-05 16:37:59 +02:00
script . commonPipelineEnvironment . configuration . stageStashes = stashConfiguration
}
2019-07-03 10:13:26 +02:00
private void setPullRequestStageStepActivation ( script , config , List actions ) {
if ( script . commonPipelineEnvironment . configuration . runStep = = null )
script . commonPipelineEnvironment . configuration . runStep = [ : ]
if ( script . commonPipelineEnvironment . configuration . runStep [ config . pullRequestStageName ] = = null )
script . commonPipelineEnvironment . configuration . runStep [ config . pullRequestStageName ] = [ : ]
actions . each { action - >
if ( action . startsWith ( config . labelPrefix ) )
action = action . minus ( config . labelPrefix )
def stepName = config . stepMappings [ action ]
if ( stepName ) {
script . commonPipelineEnvironment . configuration . runStep . "${config.pullRequestStageName}" . "${stepName}" = true
}
}
}