1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/vars/piperPipelineStageInit.groovy
Kevin Hudemann 80250ab2b9
Extend piperPipelineStageInit to support init of Cloud SDK (#2062)
This change adds necessary functionality to support initialization of
Cloud SDK pipelines. In addition, it adds the support to check the
pipeline configuration for legacy configuration parameters.
2020-09-28 10:44:56 +02:00

281 lines
11 KiB
Groovy

import com.cloudbees.groovy.cps.NonCPS
import com.sap.piper.ConfigurationHelper
import com.sap.piper.GenerateStageDocumentation
import com.sap.piper.JenkinsUtils
import com.sap.piper.LegacyConfigurationCheckUtils
import com.sap.piper.StageNameProvider
import com.sap.piper.Utils
import com.sap.piper.k8s.ContainerMap
import groovy.transform.Field
import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = getClass().getName()
@Field String TECHNICAL_STAGE_NAME = 'init'
@Field Set GENERAL_CONFIG_KEYS = [
/**
* Defines the build tool used.
* @possibleValues `docker`, `kaniko`, `maven`, `mta, ``npm`
*/
'buildTool',
/**
* 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',
/**
* Toggle for initialization of the stash settings for Cloud SDK Pipeline.
* If this is set to true, the stashSettings parameter is **not** configurable.
*/
'initCloudSdkStashSettings',
/**
* Defines the library resource containing the legacy configuration definition.
*/
'legacyConfigSettings',
/**
* 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
*/
'productiveBranch',
/**
* 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!**
*/
'stageConfigResource',
/**
* 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!**
*/
'stashSettings',
/**
* Whether verbose output should be produced.
* @possibleValues `true`, `false`
*/
'verbose'
]
@Field STAGE_STEP_KEYS = []
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS)
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([
/**
* Enables the use of technical stage names.
*/
'useTechnicalStageNames',
])
/**
* 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')
void call(Map parameters = [:]) {
def script = checkScript(this, parameters) ?: this
def utils = parameters.juStabUtils ?: new Utils()
if (parameters.useTechnicalStageNames) {
StageNameProvider.instance.useTechnicalStageNames = true
}
def stageName = StageNameProvider.instance.getStageName(script, parameters, this)
piperStageWrapper (script: script, stageName: stageName, stashContent: [], ordinal: 1, telemetryDisabled: true) {
def scmInfo = checkout scm
setupCommonPipelineEnvironment script: script, customDefaults: parameters.customDefaults
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')
.addIfEmpty('buildTool', script.commonPipelineEnvironment.buildTool)
.withMandatoryProperty('buildTool')
.use()
if (config.legacyConfigSettings) {
Map legacyConfigSettings = readYaml(text: libraryResource(config.legacyConfigSettings))
LegacyConfigurationCheckUtils.checkConfiguration(script, legacyConfigSettings)
}
String buildTool = checkBuildTool(config)
if (Boolean.valueOf(env.ON_K8S) && config.containerMapResource) {
ContainerMap.instance.initFromResource(script, config.containerMapResource, buildTool)
}
//perform stashing based on library resource piper-stash-settings.yml if not configured otherwise or Cloud SDK Pipeline is initialized
if (config.initCloudSdkStashSettings) {
switch (buildTool) {
case 'maven':
initStashConfiguration(script, "com.sap.piper/pipeline/cloudSdkJavaStashSettings.yml", config.verbose?: false)
break
case 'npm':
initStashConfiguration(script, "com.sap.piper/pipeline/cloudSdkJavascriptStashSettings.yml", config.verbose?: false)
break
case 'mta':
initStashConfiguration(script, "com.sap.piper/pipeline/cloudSdkMtaStashSettings.yml", config.verbose?: false)
break
default:
error "[${STEP_NAME}] No stash settings for build tool ${buildTool} can be found. With `initCloudSdkStashSettings` active, only Maven, MTA or NPM projects are supported."
break
}
} else {
initStashConfiguration(script, config.stashSettings, config.verbose?: false)
}
setGitUrlsOnCommonPipelineEnvironment(script, scmInfo.GIT_URL)
script.commonPipelineEnvironment.setGitCommitId(scmInfo.GIT_COMMIT)
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
// 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)
}
if (env.BRANCH_NAME == config.productiveBranch) {
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'
}
if (config.inferBuildTool && env.ON_K8S) {
// We set dockerImage: "" for the K8S case to avoid the execution of artifactPrepareVersion in a K8S Pod.
// In addition, a mvn executable is available on the Jenkins instance which can be used directly instead of executing the command in a container.
artifactPrepareVersion script: script, buildTool: buildTool, dockerImage: ""
} else if (config.inferBuildTool) {
artifactPrepareVersion script: script, buildTool: buildTool
} else {
artifactSetVersion script: script
}
}
pipelineStashFilesBeforeBuild script: script
}
}
private String checkBuildTool(config) {
def buildDescriptorPattern = ''
String buildTool = config.buildTool
switch (buildTool) {
case 'maven':
buildDescriptorPattern = 'pom.xml'
break
case 'npm':
buildDescriptorPattern = 'package.json'
break
case 'mta':
buildDescriptorPattern = 'mta.yaml'
break
}
if (buildDescriptorPattern && !findFiles(glob: buildDescriptorPattern)) {
error "[${STEP_NAME}] buildTool configuration '${config.buildTool}' does not fit to your project, please set buildTool as genereal setting in your .pipeline/config.yml correctly, see also https://sap.github.io/jenkins-library/configuration/"
}
return buildTool
}
private void initStashConfiguration (script, stashSettings, verbose) {
Map stashConfiguration = readYaml(text: libraryResource(stashSettings))
if (verbose) echo "Stash config: ${stashConfiguration}"
script.commonPipelineEnvironment.configuration.stageStashes = stashConfiguration
}
private void setGitUrlsOnCommonPipelineEnvironment(script, String gitUrl) {
Map url = parseUrl(gitUrl)
if (url.protocol in ['http', 'https']) {
script.commonPipelineEnvironment.setGitSshUrl("git@${url.host}:${url.path}")
script.commonPipelineEnvironment.setGitHttpsUrl(gitUrl)
} else if (url.protocol in [ null, 'ssh', 'git']) {
script.commonPipelineEnvironment.setGitSshUrl(gitUrl)
script.commonPipelineEnvironment.setGitHttpsUrl("https://${url.host}/${url.path}")
}
List gitPathParts = url.path.replaceAll('.git', '').split('/')
def gitFolder = 'N/A'
def gitRepo = 'N/A'
switch (gitPathParts.size()) {
case 1:
gitRepo = gitPathParts[0]
break
case 2:
gitFolder = gitPathParts[0]
gitRepo = gitPathParts[1]
break
case { it > 3 }:
gitRepo = gitPathParts[gitPathParts.size()-1]
gitPathParts.remove(gitPathParts.size()-1)
gitFolder = gitPathParts.join('/')
break
}
script.commonPipelineEnvironment.setGithubOrg(gitFolder)
script.commonPipelineEnvironment.setGithubRepo(gitRepo)
}
/*
* Returns the parts of an url.
* Valid keys for the retured map are:
* - protocol
* - auth
* - host
* - port
* - path
*/
@NonCPS
/* private */ Map parseUrl(String url) {
def urlMatcher = url =~ /^((http|https|git|ssh):\/\/)?((.*)@)?([^:\/]+)(:([\d]*))?(\/?(.*))$/
return [
protocol: urlMatcher[0][2],
auth: urlMatcher[0][4],
host: urlMatcher[0][5],
port: urlMatcher[0][7],
path: urlMatcher[0][9],
]
}
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
}
}
}