1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/vars/piperExecuteBin.groovy

277 lines
11 KiB
Groovy
Raw Normal View History

import com.sap.piper.BashUtils
import com.sap.piper.DebugReport
import com.sap.piper.DefaultValueCache
import com.sap.piper.JenkinsUtils
import com.sap.piper.MapUtils
import com.sap.piper.PiperGoUtils
import com.sap.piper.Utils
import com.sap.piper.analytics.InfluxData
import groovy.transform.Field
import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = getClass().getName()
void call(Map parameters = [:], String stepName, String metadataFile, List credentialInfo, boolean failOnMissingReports = false, boolean failOnMissingLinks = false, boolean failOnError = false) {
Map handlePipelineStepErrorsParameters = [stepName: stepName, stepParameters: parameters]
if (failOnError) {
handlePipelineStepErrorsParameters.failOnError = true
}
handlePipelineStepErrors(handlePipelineStepErrorsParameters) {
Script script = checkScript(this, parameters) ?: this
def jenkinsUtils = parameters.jenkinsUtilsStub ?: new JenkinsUtils()
def utils = parameters.juStabUtils ?: new Utils()
String piperGoPath = parameters.piperGoPath ?: './piper'
prepareExecution(script, utils, parameters)
prepareMetadataResource(script, metadataFile)
Map stepParameters = prepareStepParameters(parameters)
echo "Step params $stepParameters"
withEnv([
"PIPER_parametersJSON=${groovy.json.JsonOutput.toJson(stepParameters)}",
"PIPER_correlationID=${env.BUILD_URL}",
//ToDo: check if parameters make it into docker image on JaaS
]) {
String defaultConfigArgs = getCustomDefaultConfigsArg()
String customConfigArg = getCustomConfigArg(script)
echo "PIPER_parametersJSON: ${groovy.json.JsonOutput.toJson(stepParameters)}"
// get context configuration
Map config
handleErrorDetails(stepName) {
config = getStepContextConfig(script, piperGoPath, metadataFile, defaultConfigArgs, customConfigArg)
echo "Context Config: ${config}"
}
// prepare stashes
// first eliminate empty stashes
config.stashContent = utils.unstashAll(config.stashContent)
// then make sure that commonPipelineEnvironment, config, ... is also available when step stashing is active
if (config.stashContent?.size() > 0) {
config.stashContent.add('pipelineConfigAndTests')
config.stashContent.add('piper-bin')
config.stashContent.add('pipelineStepReports')
}
if (parameters.stashNoDefaultExcludes) {
// Merge this parameter which is only relevant in Jenkins context
// (for dockerExecuteOnKubernetes step) and go binary doesn't know about
config.stashNoDefaultExcludes = parameters.stashNoDefaultExcludes
}
dockerWrapper(script, stepName, config) {
handleErrorDetails(stepName) {
script.commonPipelineEnvironment.writeToDisk(script)
utils.unstash('pipelineStepReports')
try {
try {
try {
credentialWrapper(config, credentialInfo) {
sh "${piperGoPath} ${stepName}${defaultConfigArgs}${customConfigArg}"
}
} finally {
jenkinsUtils.handleStepResults(stepName, failOnMissingReports, failOnMissingLinks)
}
} finally {
script.commonPipelineEnvironment.readFromDisk(script)
}
} finally {
InfluxData.readFromDisk(script)
stash name: 'pipelineStepReports', includes: '.pipeline/stepReports/**', allowEmpty: true
}
}
}
}
}
}
// reused in sonarExecuteScan
static void prepareExecution(Script script, Utils utils, Map parameters = [:]) {
def piperGoUtils = parameters.piperGoUtils ?: new PiperGoUtils(script, utils)
piperGoUtils.unstashPiperBin()
utils.unstash('pipelineConfigAndTests')
}
// reused in sonarExecuteScan
static Map prepareStepParameters(Map parameters) {
Map stepParameters = [:].plus(parameters)
stepParameters.remove('script')
stepParameters.remove('jenkinsUtilsStub')
stepParameters.remove('piperGoPath')
stepParameters.remove('juStabUtils')
stepParameters.remove('piperGoUtils')
// When converting to JSON and back again, entries which had a 'null' value will now have a value
// of type 'net.sf.json.JSONNull', for which the Groovy Truth resolves to 'true' in for example if-conditions
return MapUtils.pruneNulls(stepParameters)
}
// reused in sonarExecuteScan
static void prepareMetadataResource(Script script, String metadataFile) {
script.writeFile(file: ".pipeline/tmp/${metadataFile}", text: script.libraryResource(metadataFile))
}
// reused in sonarExecuteScan
static Map getStepContextConfig(Script script, String piperGoPath, String metadataFile, String defaultConfigArgs, String customConfigArg) {
return script.readJSON(text: script.sh(returnStdout: true, script: "${piperGoPath} getConfig --contextConfig --stepMetadata '.pipeline/tmp/${metadataFile}'${defaultConfigArgs}${customConfigArg}"))
}
static String getCustomDefaultConfigs() {
// The default config files were extracted from merged library
// resources by setupCommonPipelineEnvironment.groovy into .pipeline/.
List customDefaults = DefaultValueCache.getInstance().getCustomDefaults()
for (int i = 0; i < customDefaults.size(); i++) {
customDefaults[i] = BashUtils.quoteAndEscape(".pipeline/${customDefaults[i]}")
}
return customDefaults.join(',')
}
// reused in sonarExecuteScan
static String getCustomDefaultConfigsArg() {
String customDefaults = getCustomDefaultConfigs()
if (customDefaults) {
return " --defaultConfig ${customDefaults} --ignoreCustomDefaults"
}
return ''
}
// reused in sonarExecuteScan
static String getCustomConfigArg(def script) {
if (script?.commonPipelineEnvironment?.configurationFile
&& script.commonPipelineEnvironment.configurationFile != '.pipeline/config.yml'
&& script.commonPipelineEnvironment.configurationFile != '.pipeline/config.yaml') {
return " --customConfig ${BashUtils.quoteAndEscape(script.commonPipelineEnvironment.configurationFile)}"
}
return ''
}
// reused in sonarExecuteScan
void dockerWrapper(script, stepName, config, body) {
if (config.dockerImage) {
echo "[INFO] executing pipeline step '${stepName}' with docker image '${config.dockerImage}'"
Map dockerExecuteParameters = [:].plus(config)
dockerExecuteParameters.script = script
dockerExecute(dockerExecuteParameters) {
body()
}
} else {
body()
}
}
// reused in sonarExecuteScan
void credentialWrapper(config, List credentialInfo, body) {
credentialInfo = handleVaultCredentials(config, credentialInfo)
if (credentialInfo.size() > 0) {
def creds = []
def sshCreds = []
credentialInfo.each { cred ->
def credentialsId
if (cred.resolveCredentialsId == false) {
credentialsId = cred.id
} else {
credentialsId = config[cred.id]
}
if (credentialsId) {
switch (cred.type) {
case "file":
creds.add(file(credentialsId: credentialsId, variable: cred.env[0]))
break
case "token":
creds.add(string(credentialsId: credentialsId, variable: cred.env[0]))
break
case "usernamePassword":
creds.add(usernamePassword(credentialsId: credentialsId, usernameVariable: cred.env[0], passwordVariable: cred.env[1]))
break
case "ssh":
sshCreds.add(credentialsId)
break
default:
error("invalid credential type: ${cred.type}")
}
}
}
// remove credentialIds that were probably defaulted and which are not present in jenkins
if (containsVaultConfig(config)) {
creds = removeMissingCredentials(creds, config)
sshCreds = removeMissingCredentials(sshCreds, config)
}
if (sshCreds.size() > 0) {
sshagent (sshCreds) {
withCredentials(creds) {
body()
}
}
} else {
withCredentials(creds) {
body()
}
}
} else {
body()
}
}
List removeMissingCredentials(List creds, Map config) {
return creds.findAll { credentialExists(it, config) }
}
boolean credentialExists(cred, Map config) {
try {
withCredentials([cred]) {
return true
}
} catch (e) {
return false
}
}
boolean containsVaultConfig(Map config) {
def approleIsUsed = config.containsKey('vaultAppRoleTokenCredentialsId') && config.containsKey('vaultAppRoleSecretTokenCredentialsId')
def tokenIsUsed = config.containsKey('vaultTokenCredentialsId')
return approleIsUsed || tokenIsUsed
}
// Injects vaultCredentials if steps supports resolving parameters from vault
List handleVaultCredentials(config, List credentialInfo) {
if (config.containsKey('vaultAppRoleTokenCredentialsId') && config.containsKey('vaultAppRoleSecretTokenCredentialsId')) {
credentialInfo += [[type: 'token', id: 'vaultAppRoleTokenCredentialsId', env: ['PIPER_vaultAppRoleID']],
[type: 'token', id: 'vaultAppRoleSecretTokenCredentialsId', env: ['PIPER_vaultAppRoleSecretID']]]
}
if (config.containsKey('vaultTokenCredentialsId')) {
credentialInfo += [[type: 'token', id: 'vaultTokenCredentialsId', env: ['PIPER_vaultToken']]]
}
return credentialInfo
}
// reused in sonarExecuteScan
void handleErrorDetails(String stepName, Closure body) {
try {
body()
} catch (ex) {
def errorDetailsFileName = "${stepName}_errorDetails.json"
if (fileExists(file: errorDetailsFileName)) {
def errorDetails = readJSON(file: errorDetailsFileName)
def errorCategory = ""
if (errorDetails.category) {
errorCategory = " (category: ${errorDetails.category})"
DebugReport.instance.failedBuild.category = errorDetails.category
}
error "[${stepName}] Step execution failed${errorCategory}. Error: ${errorDetails.error ?: errorDetails.message}"
}
error "[${stepName}] Step execution failed. Error: ${ex}, please see log file for more details."
}
}