import static com.sap.piper.Prerequisites.checkScript import com.sap.piper.Utils import groovy.transform.Field import com.sap.piper.GenerateDocumentation import com.sap.piper.ConfigurationHelper import com.sap.piper.cm.ChangeManagement import com.sap.piper.cm.BackendType import com.sap.piper.cm.ChangeManagementException import hudson.AbortException import static com.sap.piper.cm.StepHelpers.getTransportRequestId import static com.sap.piper.cm.StepHelpers.getChangeDocumentId import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrationDisabled @Field def STEP_NAME = getClass().getName() @Field Set GENERAL_CONFIG_KEYS = [ 'changeManagement', /** * @see checkChangeInDevelopment * @parentConfigKey changeManagement */ 'changeDocumentLabel', /** * Defines where the transport request is created, e.g. SAP Solution Manager, ABAP System. * @parentConfigKey changeManagement * @possibleValues `SOLMAN`, `CTS`, `RFC` */ 'type', /** * @see checkChangeInDevelopment * @parentConfigKey changeManagement */ 'clientOpts', /** * @see checkChangeInDevelopment * @parentConfigKey changeManagement */ 'credentialsId', /** * @see checkChangeInDevelopment * @parentConfigKey changeManagement */ 'endpoint', /** * @see checkChangeInDevelopment * @parentConfigKey changeManagement */ 'git/from', /** * @see checkChangeInDevelopment * @parentConfigKey changeManagement */ 'git/to', /** * @see checkChangeInDevelopment * @parentConfigKey changeManagement */ 'git/format', /** * @see transportRequestCreate * @parentConfigKey changeManagement */ 'rfc/developmentInstance', /** * @see transportRequestCreate * @parentConfigKey changeManagement */ 'rfc/developmentClient', /** * A pattern used for identifying lines holding the transport request id. * @parentConfigKey changeManagement */ 'transportRequestLabel', /** * Some CTS related transport related steps are cm_client based, others are node based. * For the node based steps the docker image is specified here. * @parentConfigKey changeManagement */ 'cts/nodeDocker/image', /** * The ABAP client. Only for `CTS` * @parentConfigKey changeManagement */ 'client', /** * By default we use a standard node docker image and prepare some fiori related packages * before performing the deployment. For that we need to launch the image with root privileges. * After that, before actually performing the deployment we swith to a non root user. This user * can be specified here. * @parentConfigKey changeManagement */ 'cts/osDeployUser', /** * By default we use a standard node docker iamge and prepare some fiori related packages * performing the deployment. The additional dependencies can be provided here. In case you * use an already prepared docker image which contains the required dependencies, the empty * list can be provided here. Caused hereby installing additional dependencies will be skipped. * * @parentConfigKey changeManagement */ 'cts/deployToolDependencies', /** * A list containing additional options for the npm install call. `-g`, `--global` is always assumed. * Can be used for e.g. providing custom registries (`--registry https://your.registry.com`) or * for providing the verbose flag (`--verbose`) for troubleshooting. * @parentConfigKey changeManagement */ 'cts/npmInstallOpts', /** * The file handed over to `fiori deploy` with flag `-c --config`. * @parentConfigKey changeManagement */ 'cts/deployConfigFile', ] @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([ /** The name of the application. `RFC` and `CTS` only. */ 'applicationName', // RFC, CTS /** The id of the application. Only for `SOLMAN`.*/ 'applicationId', // SOLMAN /** The application description, `RFC` and `CTS` only. For `CTS`: the desription is only taken into account for a new upload. In case of an update the description will not be updated. */ 'applicationDescription', /** The path of the file to upload, Only for `SOLMAN`.*/ 'filePath', // SOLMAN /** The URL where to find the UI5 package to upload to the transport request. Only for `RFC`. */ 'applicationUrl', // RFC /** The ABAP package name of your application. */ 'abapPackage', /** The code page of your ABAP system. E.g. UTF-8. */ 'codePage', //RFC /** If unix style line endings should be accepted. Only for `RFC`.*/ 'acceptUnixStyleLineEndings', // RFC /** @see transportRequestCreate */ 'verbose', // RFC ]) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([ /** @see transportRequestCreate */ 'changeDocumentId', /** The id of the transport request to upload the file. This parameter is only taken into account * when provided via signature to the step. */ 'transportRequestId']) /** Uploads a file to a Transport Request. */ @GenerateDocumentation void call(Map parameters = [:]) { handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) { def script = checkScript(this, parameters) ?: this String stageName = parameters.stageName ?: env.STAGE_NAME ChangeManagement cm = parameters.cmUtils ?: new ChangeManagement(script) ConfigurationHelper configHelper = ConfigurationHelper.newInstance(this) .loadStepDefaults([:], stageName) .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS) .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS) .mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS) .mixin(parameters, PARAMETER_KEYS) .addIfEmpty('filePath', script.commonPipelineEnvironment.getMtarFilePath()) Map configuration = configHelper.use() BackendType backendType = getBackendTypeAndLogInfoIfCMIntegrationDisabled(this, configuration) if(backendType == BackendType.NONE) return configHelper .collectValidationFailures() .withMandatoryProperty('changeManagement/changeDocumentLabel') .withMandatoryProperty('changeManagement/clientOpts') .withMandatoryProperty('changeManagement/credentialsId') .withMandatoryProperty('changeManagement/endpoint') .withMandatoryProperty('changeManagement/client', null, {backendType == BackendType.CTS}) .withMandatoryProperty('changeManagement/type') .withMandatoryProperty('changeManagement/git/from') .withMandatoryProperty('changeManagement/git/to') .withMandatoryProperty('changeManagement/git/format') .withMandatoryProperty('filePath', null, { backendType == BackendType.SOLMAN }) .withMandatoryProperty('applicationUrl', null, { backendType == BackendType.RFC }) .withMandatoryProperty('codePage', null, { backendType == BackendType.RFC }) .withMandatoryProperty('acceptUnixStyleLineEndings', null, { backendType == BackendType.RFC }) .withMandatoryProperty('changeManagement/rfc/developmentInstance', null, { backendType == BackendType.RFC }) .withMandatoryProperty('changeManagement/rfc/developmentClient', null, { backendType == BackendType.RFC }) .withMandatoryProperty('changeManagement/rfc/docker/image', null, {backendType == BackendType.RFC}) .withMandatoryProperty('changeManagement/rfc/docker/options', null, {backendType == BackendType.RFC}) .withMandatoryProperty('changeManagement/rfc/docker/envVars', null, {backendType == BackendType.RFC}) .withMandatoryProperty('changeManagement/rfc/docker/pullImage', null, {backendType == BackendType.RFC}) .withMandatoryProperty('applicationDescription', null, { backendType == BackendType.RFC }) .withMandatoryProperty('abapPackage', null, { backendType in [BackendType.RFC, BackendType.CTS] }) .withMandatoryProperty('applicationId', null, {backendType == BackendType.SOLMAN}) .withMandatoryProperty('applicationName', null, {backendType in [BackendType.RFC, BackendType.CTS]}) .withMandatoryProperty('failOnWarning', null, {backendType == BackendType.RFC}) .withMandatoryProperty('verbose', null, {backendType == BackendType.RFC}) new Utils().pushToSWA([ step: STEP_NAME, stepParamKey1: 'changeManagementType', stepParam1: configuration.changeManagement.type, stepParamKey2: 'scriptMissing', stepParam2: parameters?.script == null ], configuration) def changeDocumentId = null if(backendType == BackendType.SOLMAN) { changeDocumentId = getChangeDocumentId(script, configuration) } def transportRequestId = getTransportRequestId(script, configuration) configHelper .mixin([changeDocumentId: changeDocumentId?.trim() ?: null, transportRequestId: transportRequestId?.trim() ?: null], ['changeDocumentId', 'transportRequestId'] as Set) if(backendType == BackendType.SOLMAN) { configHelper .withMandatoryProperty('changeDocumentId', "Change document id not provided (parameter: \'changeDocumentId\' provided to the step call or via commit history).") } configuration = configHelper .withMandatoryProperty('transportRequestId', "Transport request id not provided (parameter: \'transportRequestId\' provided to the step call or via commit history).") .use() try { switch(backendType) { case BackendType.SOLMAN: echo "[INFO] Uploading file '${configuration.filePath}' to transport request '${configuration.transportRequestId}'" + " of change document '${configuration.changeDocumentId}'." Map paramsUpload = [ script: script, filePath: configuration.filePath, uploadCredentialsId: configuration.changeManagement.credentialsId, endpoint: configuration.changeManagement.endpoint, applicationId: configuration.applicationId, changeDocumentId: configuration.changeDocumentId, transportRequestId: configuration.transportRequestId ] if(configuration.changeManagement.clientOpts) { paramsUpload.cmClientOpts = configuration.changeManagement.clientOpts } paramsUpload = addDockerParams(script, paramsUpload, configuration.changeManagement.solman?.docker) transportRequestUploadSOLMAN(paramsUpload) echo "[INFO] File '${configuration.filePath}' has been successfully uploaded to transport request '${configuration.transportRequestId}'" + " of change document '${configuration.changeDocumentId}'." break case BackendType.CTS: echo "[INFO] Uploading application '${configuration.applicationName}' to transport request '${configuration.transportRequestId}'." Map paramsUpload = [ script: script, transportRequestId: configuration.transportRequestId, endpoint: configuration.changeManagement.endpoint, client: configuration.changeManagement.client, applicationName: configuration.applicationName, description: configuration.applicationDescription, abapPackage: configuration.abapPackage, osDeployUser: configuration.changeManagement.cts.osDeployUser, deployToolDependencies: configuration.changeManagement.cts.deployToolDependencies, npmInstallOpts: configuration.changeManagement.cts.npmInstallOpts, deployConfigFile: configuration.changeManagement.cts.deployConfigFile, uploadCredentialsId: configuration.changeManagement.credentialsId ] paramsUpload = addDockerParams(script, paramsUpload, configuration.changeManagement.cts?.nodeDocker) transportRequestUploadCTS(paramsUpload) echo "[INFO] Application '${configuration.applicationName}' has been successfully uploaded to transport request '${configuration.transportRequestId}'." break case BackendType.RFC: echo "[INFO] Uploading file '${configuration.applicationUrl}' to transport request '${configuration.transportRequestId}'." Map paramsUpload = [script: script, transportRequestId: configuration.transportRequestId, applicationName: configuration.applicationName, applicationUrl: configuration.applicationUrl, endpoint: configuration.changeManagement.endpoint, uploadCredentialsId: configuration.changeManagement.credentialsId, instance: configuration.changeManagement.rfc.developmentInstance, client: configuration.changeManagement.rfc.developmentClient, applicationDescription: configuration.applicationDescription, abapPackage: configuration.abapPackage, codePage: configuration.codePage, acceptUnixStyleLineEndings: configuration.acceptUnixStyleLineEndings, failUploadOnWarning: configuration.failOnWarning, verbose: configuration.verbose ] paramsUpload = addDockerParams(script, paramsUpload, configuration.changeManagement.rfc?.docker) transportRequestUploadRFC(paramsUpload) echo "[INFO] File 'configuration.applicationUrl' has been successfully uploaded to transport request '${configuration.transportRequestId}'." break } } catch(ChangeManagementException ex) { throw new AbortException(ex.getMessage()) } } } Map addDockerParams(Script script, Map parameters, Map docker) { if(docker) { if(docker.image) { parameters.dockerImage = docker.image } if(docker.options) { parameters.dockerOptions = docker.options } if(docker.envVars) { parameters.dockerEnvVars = docker.envVars } if(docker.pullImage != null) { parameters.put('dockerPullImage', docker.pullImage) } } return parameters }