github.com/jaylevin/jenkins-library@v1.230.4/vars/tmsUpload.groovy (about) 1 import com.sap.piper.ConfigurationHelper 2 import com.sap.piper.GenerateDocumentation 3 import com.sap.piper.JenkinsUtils 4 import com.sap.piper.JsonUtils 5 import com.sap.piper.Utils 6 import com.sap.piper.integration.TransportManagementService 7 import groovy.transform.Field 8 9 import static com.sap.piper.Prerequisites.checkScript 10 11 @Field String STEP_NAME = getClass().getName() 12 13 @Field Set GENERAL_CONFIG_KEYS = [ 14 /** 15 * Print more detailed information into the log. 16 * @possibleValues `true`, `false` 17 */ 18 'verbose' 19 ] 20 @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([ 21 /** 22 * If specific stashes should be considered, their names need to be passed via the parameter `stashContent`. 23 */ 24 'stashContent', 25 /** 26 * Defines the relative path to *.mtar for the upload to the Transport Management Service. If not specified, it will use the mtar file created in mtaBuild. 27 */ 28 'mtaPath', 29 /** 30 * Defines the name of the node to which the *.mtar file should be uploaded. 31 */ 32 'nodeName', 33 /** 34 * Defines the version of the MTA for which the MTA extension descriptor will be used. You can use an asterisk (*) to accept any MTA version, or use a specific version compliant with SemVer 2.0, e.g. 1.0.0 (see semver.org). If the parameter is not configured, an asterisk is used. 35 */ 36 'mtaVersion', 37 /** 38 * Available only for transports in Cloud Foundry environment. Defines a mapping between a transport node name and an MTA extension descriptor file path that you want to use for the transport node, e.g. nodeExtDescriptorMapping: [nodeName: 'example.mtaext', nodeName2: 'example2.mtaext', …]`. 39 */ 40 'nodeExtDescriptorMapping', 41 /** 42 * Credentials to be used for the file and node uploads to the Transport Management Service. 43 */ 44 'credentialsId', 45 /** 46 * Can be used as the description of a transport request. Will overwrite the default. (Default: Corresponding Git Commit-ID) 47 */ 48 'customDescription', 49 /** 50 * Proxy which should be used for the communication with the Transport Management Service Backend. 51 */ 52 'proxy' 53 ]) 54 @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS + GENERAL_CONFIG_KEYS 55 56 /** 57 * This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Platform Transport Management Service) landscape for further TMS-controlled distribution through a TMS-configured landscape. 58 * TMS lets you manage transports between SAP Cloud Platform accounts in Neo and Cloud Foundry, such as from DEV to TEST and PROD accounts. 59 * For more information, see [official documentation of Transport Management Service](https://help.sap.com/viewer/p/TRANSPORT_MANAGEMENT_SERVICE) 60 * 61 * !!! note "Prerequisites" 62 * * You have subscribed to and set up TMS, as described in [Setup and Configuration of SAP Cloud Platform Transport Management](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/66fd7283c62f48adb23c56fb48c84a60.html), which includes the configuration of a node to be used for uploading an MTA file. 63 * * A corresponding service key has been created, as described in [Set Up the Environment to Transport Content Archives directly in an Application](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/8d9490792ed14f1bbf8a6ac08a6bca64.html). This service key (JSON) must be stored as a secret text within the Jenkins secure store. 64 * 65 */ 66 @GenerateDocumentation 67 void call(Map parameters = [:]) { 68 handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) { 69 70 def script = checkScript(this, parameters) ?: this 71 def utils = parameters.juStabUtils ?: new Utils() 72 def jenkinsUtils = parameters.jenkinsUtilsStub ?: new JenkinsUtils() 73 String stageName = parameters.stageName ?: env.STAGE_NAME 74 75 // load default & individual configuration 76 Map config = ConfigurationHelper.newInstance(this) 77 .loadStepDefaults([:], stageName) 78 .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS) 79 .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS) 80 .mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS) 81 .mixin(parameters, PARAMETER_KEYS) 82 .addIfEmpty('mtaPath', script.commonPipelineEnvironment.mtarFilePath) 83 //mandatory parameters 84 .withMandatoryProperty('mtaPath') 85 .withMandatoryProperty('nodeName') 86 .withMandatoryProperty('credentialsId') 87 .use() 88 89 // telemetry reporting 90 new Utils().pushToSWA([ 91 step : STEP_NAME, 92 stepParamKey1: 'scriptMissing', 93 stepParam1 : parameters?.script == null 94 ], config) 95 96 def jsonUtilsObject = new JsonUtils() 97 98 // make sure that all relevant descriptors, are available in workspace 99 utils.unstashAll(config.stashContent) 100 // make sure that for further execution whole workspace, e.g. also downloaded artifacts are considered 101 config.stashContent = [] 102 103 def customDescription = config.customDescription ? "${config.customDescription}" : "Git CommitId: ${script.commonPipelineEnvironment.getGitCommitId()}" 104 def description = customDescription 105 106 def namedUser = jenkinsUtils.getJobStartedByUserId() ?: config.namedUser 107 108 def nodeName = config.nodeName 109 def mtaPath = config.mtaPath 110 111 def mtaVersion = config.mtaVersion ? "${config.mtaVersion}" : "*" 112 Map nodeExtDescriptorMapping = (config.nodeExtDescriptorMapping && config.nodeExtDescriptorMapping.size()>0) ? config.nodeExtDescriptorMapping : null 113 114 if(!fileExists(mtaPath)) { 115 error("Mta file '${mtaPath}' does not exist.") 116 } 117 118 if (config.verbose) { 119 echo "[TransportManagementService] CredentialsId: '${config.credentialsId}'" 120 echo "[TransportManagementService] Node name: '${nodeName}'" 121 echo "[TransportManagementService] MTA path: '${mtaPath}'" 122 echo "[TransportManagementService] Named user: '${namedUser}'" 123 } 124 125 def tms = parameters.transportManagementService ?: new TransportManagementService(script, config) 126 127 withCredentials([string(credentialsId: config.credentialsId, variable: 'tmsServiceKeyJSON')]) { 128 129 def tmsServiceKey = jsonUtilsObject.jsonStringToGroovyObject(tmsServiceKeyJSON) 130 131 def clientId = tmsServiceKey.uaa.clientid 132 def clientSecret = tmsServiceKey.uaa.clientsecret 133 def uaaUrl = tmsServiceKey.uaa.url 134 def uri = tmsServiceKey.uri 135 136 if (config.verbose) { 137 echo "[TransportManagementService] UAA URL: '${uaaUrl}'" 138 echo "[TransportManagementService] TMS URL: '${uri}'" 139 echo "[TransportManagementService] ClientId: '${clientId}'" 140 } 141 142 def token = tms.authentication(uaaUrl, clientId, clientSecret) 143 144 if(nodeExtDescriptorMapping) { 145 // validate the whole mapping and then throw errors together, 146 // so that user can get them in one pipeline run 147 // put the validation here, because we need uri and token to call tms get nodes api 148 List nodes = tms.getNodes(uri, token).getAt("nodes"); 149 Map mtaYaml = getMtaYaml(script.commonPipelineEnvironment.getValue('mtaBuildToolDesc')); 150 Map nodeIdExtDesMap = validateNodeExtDescriptorMapping(nodeExtDescriptorMapping, nodes, mtaYaml, mtaVersion) 151 152 if(nodeIdExtDesMap) { 153 nodeIdExtDesMap.each{ key, value -> 154 Map mtaExtDescriptor = tms.getMtaExtDescriptor(uri, token, key, mtaYaml.ID, mtaVersion) 155 if(mtaExtDescriptor) { 156 def updateMtaExtDescriptorResponse = tms.updateMtaExtDescriptor(uri, token, key, mtaExtDescriptor.getAt("id"), "${workspace}/${value.get(1)}", mtaVersion, description, namedUser) 157 echo "[TransportManagementService] MTA Extension Descriptor with ID '${updateMtaExtDescriptorResponse.mtaExtId}' successfully updated for Node '${value.get(0)}'." 158 } else { 159 def uploadMtaExtDescriptorToNodeResponse = tms.uploadMtaExtDescriptorToNode(uri, token, key, "${workspace}/${value.get(1)}", mtaVersion, description, namedUser) 160 echo "[TransportManagementService] MTA Extension Descriptor with ID '${uploadMtaExtDescriptorToNodeResponse.mtaExtId}' successfully uploaded to Node '${value.get(0)}'." 161 } 162 } 163 } 164 } 165 166 def fileUploadResponse = tms.uploadFile(uri, token, "${workspace}/${mtaPath}", namedUser) 167 def uploadFileToNodeResponse = tms.uploadFileToNode(uri, token, nodeName, fileUploadResponse.fileId, description, namedUser) 168 echo "[TransportManagementService] File '${fileUploadResponse.fileName}' successfully uploaded to Node '${uploadFileToNodeResponse.queueEntries.nodeName}' (Id: '${uploadFileToNodeResponse.queueEntries.nodeId}')." 169 echo "[TransportManagementService] Corresponding Transport Request: '${uploadFileToNodeResponse.transportRequestDescription}' (Id: '${uploadFileToNodeResponse.transportRequestId}')" 170 } 171 172 } 173 } 174 175 def String getMtaId(String extDescriptorFilePath){ 176 def extDescriptor = readYaml file: extDescriptorFilePath 177 def mtaId = "" 178 if (extDescriptor.extends) { 179 mtaId = extDescriptor.extends 180 } 181 return mtaId 182 } 183 184 def Map getMtaYaml(String mtaBuildToolDesc) { 185 mtaBuildToolDesc = mtaBuildToolDesc?:"mta.yaml" 186 if(fileExists(mtaBuildToolDesc)) { 187 def mtaYaml = readYaml file: mtaBuildToolDesc 188 if (!mtaYaml.ID || !mtaYaml.version) { 189 def errorMsg 190 if (!mtaYaml.ID) { 191 errorMsg = "Property 'ID' is not found in ${mtaBuildToolDesc}." 192 } 193 if (!mtaYaml.version) { 194 errorMsg += "Property 'version' is not found in ${mtaBuildToolDesc}." 195 } 196 error errorMsg 197 } 198 return mtaYaml 199 } else { 200 error "${mtaBuildToolDesc} is not found in the root folder of the project." 201 } 202 } 203 204 def Map validateNodeExtDescriptorMapping(Map nodeExtDescriptorMapping, List nodes, Map mtaYaml, String mtaVersion) { 205 def errorPathList = [] 206 def errorMtaId = [] 207 def errorNodeNameList = [] 208 def errorMsg = "" 209 Map nodeIdExtDesMap = [:] 210 211 if(mtaVersion != "*" && mtaVersion != mtaYaml.version) { 212 errorMsg = "Parameter 'mtaVersion' does not match the MTA version in mta.yaml. " 213 } 214 215 nodeExtDescriptorMapping.each{ key, value -> 216 if(nodes.any {it.name == key}) { 217 nodeIdExtDesMap.put(nodes.find {it.name == key}.getAt("id"), [key, value]) 218 } else { 219 errorNodeNameList.add(key) 220 } 221 222 if(!fileExists(value)) { 223 errorPathList.add(value) 224 } else { 225 if(mtaYaml.ID != getMtaId("${value}")) { 226 errorMtaId.add(value) 227 } 228 } 229 } 230 231 if(!errorPathList.isEmpty() || !errorMtaId.isEmpty() || !errorNodeNameList.isEmpty() ) { 232 if(!errorPathList.isEmpty()) { 233 errorMsg += "MTA extension descriptor files ${errorPathList} don't exist. " 234 } 235 if(!errorMtaId.isEmpty()) { 236 errorMsg += "Parameter [extends] in MTA extension descriptor files ${errorMtaId} is not the same as MTA ID." 237 } 238 if(!errorNodeNameList.isEmpty()) { 239 errorMsg += "Nodes ${errorNodeNameList} don't exist. Please check the node name or create these nodes." 240 } 241 error(errorMsg) 242 } 243 244 return nodeIdExtDesMap 245 }