diff --git a/resources/default_pipeline_environment.yml b/resources/default_pipeline_environment.yml index 1a7b95c89..ca57ffeff 100644 --- a/resources/default_pipeline_environment.yml +++ b/resources/default_pipeline_environment.yml @@ -16,6 +16,12 @@ general: from: 'origin/master' to: 'HEAD' format: '%b' + rfc: + docker: + image: 'rfc' + options: [] + envVars: {} + pullImage: true githubApiUrl: 'https://api.github.com' githubServerUrl: 'https://github.com' gitSshKeyCredentialsId: '' #needed to allow sshagent to run with local ssh key @@ -363,8 +369,14 @@ steps: failIfStatusIsNotInDevelopment: true transportRequestCreate: developmentSystemId: null + verbose: false transportRequestUploadFile: + acceptUnixStyleLineEndings: true + codePage: 'UTF-8' + failOnWarning: true + verbose: false transportRequestRelease: + verbose: false uiVeri5ExecuteTests: failOnError: false dockerEnvVars: {} diff --git a/src/com/sap/piper/cm/BackendType.groovy b/src/com/sap/piper/cm/BackendType.groovy index d3a9dacae..1ab4ccb3b 100644 --- a/src/com/sap/piper/cm/BackendType.groovy +++ b/src/com/sap/piper/cm/BackendType.groovy @@ -1,5 +1,5 @@ package com.sap.piper.cm; public enum BackendType { - SOLMAN, CTS, NONE + SOLMAN, CTS, RFC, NONE } diff --git a/src/com/sap/piper/cm/ChangeManagement.groovy b/src/com/sap/piper/cm/ChangeManagement.groovy index fa3c2332d..97c41c396 100644 --- a/src/com/sap/piper/cm/ChangeManagement.groovy +++ b/src/com/sap/piper/cm/ChangeManagement.groovy @@ -2,6 +2,7 @@ package com.sap.piper.cm import com.sap.piper.GitUtils +import groovy.json.JsonSlurper import hudson.AbortException @@ -63,7 +64,7 @@ public class ChangeManagement implements Serializable { } boolean isChangeInDevelopment(String changeId, String endpoint, String credentialsId, String clientOpts = '') { - int rc = executeWithCredentials(BackendType.SOLMAN, endpoint, credentialsId, 'is-change-in-development', ['-cID', "'${changeId}'", '--return-code'], + int rc = executeWithCredentials(BackendType.SOLMAN, [:], endpoint, credentialsId, 'is-change-in-development', ['-cID', "'${changeId}'", '--return-code'], false, clientOpts) as int @@ -78,7 +79,7 @@ public class ChangeManagement implements Serializable { String createTransportRequestCTS(String transportType, String targetSystemId, String description, String endpoint, String credentialsId, String clientOpts = '') { try { - def transportRequest = executeWithCredentials(BackendType.CTS, endpoint, credentialsId, 'create-transport', + def transportRequest = executeWithCredentials(BackendType.CTS, [:], endpoint, credentialsId, 'create-transport', ['-tt', transportType, '-ts', targetSystemId, '-d', "\"${description}\""], true, clientOpts) @@ -91,7 +92,7 @@ public class ChangeManagement implements Serializable { String createTransportRequestSOLMAN(String changeId, String developmentSystemId, String endpoint, String credentialsId, String clientOpts = '') { try { - def transportRequest = executeWithCredentials(BackendType.SOLMAN, endpoint, credentialsId, 'create-transport', ['-cID', changeId, '-dID', developmentSystemId], + def transportRequest = executeWithCredentials(BackendType.SOLMAN, [:], endpoint, credentialsId, 'create-transport', ['-cID', changeId, '-dID', developmentSystemId], true, clientOpts) return (transportRequest as String)?.trim() @@ -100,86 +101,311 @@ public class ChangeManagement implements Serializable { } } - void uploadFileToTransportRequest(BackendType type, String changeId, String transportRequestId, String applicationId, String filePath, String endpoint, String credentialsId, String cmclientOpts = '') { + String createTransportRequestRFC( + Map docker, + String endpoint, + String developmentInstance, + String developmentClient, + String credentialsId, + String description, + boolean verbose) { - def args = null + def command = 'cts createTransportRequest' + def args = [ + TRANSPORT_DESCRIPTION: description, + ABAP_DEVELOPMENT_INSTANCE: developmentInstance, + ABAP_DEVELOPMENT_CLIENT: developmentClient, + VERBOSE: verbose, + ] - if(type == BackendType.SOLMAN) { - args = ['-cID', changeId, - '-tID', transportRequestId, - applicationId, "\"$filePath\""] - } else if (type == BackendType.CTS) { - args = ['-tID', transportRequestId, - "\"$filePath\""] - } else { - throw new IllegalArgumentException("Invalid backend type: ${type}") + try { + + def transportRequestId = executeWithCredentials( + BackendType.RFC, + docker, + endpoint, + credentialsId, + command, + args, + true) + + return new JsonSlurper().parseText(transportRequestId).REQUESTID + + } catch(AbortException ex) { + throw new ChangeManagementException( + "Cannot create transport request: ${ex.getMessage()}", ex) } - - int rc = executeWithCredentials(type, - endpoint, - credentialsId, - 'upload-file-to-transport', - args, - false, - cmclientOpts) as int - - if(rc == 0) { - return - } else { - throw new ChangeManagementException("Cannot upload file '$filePath' for change document '$changeId' with transport request '$transportRequestId'. Return code from cmclient: $rc.") - } - } - def executeWithCredentials(BackendType type, String endpoint, String credentialsId, String command, List args, boolean returnStdout = false, String clientOpts = '') { + void uploadFileToTransportRequestSOLMAN( + String changeId, + String transportRequestId, + String applicationId, + String filePath, + String endpoint, + String credentialsId, + String cmclientOpts = '') { + + def args = [ + '-cID', changeId, + '-tID', transportRequestId, + applicationId, "\"$filePath\"" + ] + + int rc = executeWithCredentials( + BackendType.SOLMAN, + [:], + endpoint, + credentialsId, + 'upload-file-to-transport', + args, + false, + cmclientOpts) as int + + if(rc != 0) { + throw new ChangeManagementException( + "Cannot upload file into transport request. Return code from cm client: $rc.") + } + } + + void uploadFileToTransportRequestCTS( + String transportRequestId, + String filePath, + String endpoint, + String credentialsId, + String cmclientOpts = '') { + + def args = [ + '-tID', transportRequestId, + "\"$filePath\"" + ] + + int rc = executeWithCredentials( + BackendType.CTS, + [:], + endpoint, + credentialsId, + 'upload-file-to-transport', + args, + false, + cmclientOpts) as int + + if(rc != 0) { + throw new ChangeManagementException( + "Cannot upload file into transport request. Return code from cm client: $rc.") + } + } + + void uploadFileToTransportRequestRFC( + Map docker, + String transportRequestId, + String applicationName, + String filePath, + String endpoint, + String credentialsId, + String developmentInstance, + String developmentClient, + String applicationDescription, + String abapPackage, + String codePage, + boolean acceptUnixStyleEndOfLine, + boolean failOnWarning, + boolean verbose) { + + def args = [ + ABAP_DEVELOPMENT_INSTANCE: developmentInstance, + ABAP_DEVELOPMENT_CLIENT: developmentClient, + ABAP_APPLICATION_NAME: applicationName, + ABAP_APPLICATION_DESC: applicationDescription, + ABAP_PACKAGE: abapPackage, + ZIP_FILE_URL: filePath, + CODE_PAGE: codePage, + ABAP_ACCEPT_UNIX_STYLE_EOL: acceptUnixStyleEndOfLine ? 'X' : '-', + FAIL_UPLOAD_ON_WARNING: Boolean.toString(failOnWarning), + VERBOSE: Boolean.toString(verbose), + ] + + int rc = executeWithCredentials( + BackendType.RFC, + docker, + endpoint, + credentialsId, + "cts uploadToABAP:${transportRequestId}", + args, + false) as int + + if(rc != 0) { + throw new ChangeManagementException( + "Cannot upload file into transport request. Return code from rfc client: $rc.") + } + } + + def executeWithCredentials( + BackendType type, + Map docker, + String endpoint, + String credentialsId, + String command, + def args, + boolean returnStdout = false, + String clientOpts = '') { + + def script = this.script script.withCredentials([script.usernamePassword( credentialsId: credentialsId, passwordVariable: 'password', usernameVariable: 'username')]) { - def cmScript = getCMCommandLine(type, endpoint, script.username, script.password, - command, args, - clientOpts) Map shArgs = [:] + if(returnStdout) shArgs.put('returnStdout', true) else shArgs.put('returnStatus', true) - shArgs.put('script', cmScript) + def result = 1 - // user and password are masked by withCredentials - script.echo """[INFO] Executing command line: "${cmScript}".""" - return script.sh(shArgs) + switch(type) { + + case BackendType.RFC: + + if(! (args in Map)) { + throw new IllegalArgumentException("args expected as Map for backend types ${[BackendType.RFC]}") + } + + shArgs.script = command + + args = args.plus([ + ABAP_DEVELOPMENT_SERVER: endpoint, + ABAP_DEVELOPMENT_USER: script.username, + ABAP_DEVELOPMENT_PASSWORD: script.password, + ]) + + // user and password are masked by withCredentials + script.echo """[INFO] Executing command line: "${shArgs.script}".""" + + script.dockerExecute( + script: script, + dockerImage: docker.image, + dockerOptions: docker.options, + dockerEnvVars: (docker.envVars?:[:]).plus(args), + dockerPullImage: docker.pullImage) { + + result = script.sh(shArgs) + + } + + break + + case BackendType.SOLMAN: + case BackendType.CTS: + + if(! (args in Collection)) + throw new IllegalArgumentException("args expected as Collection for backend types ${[BackendType.SOLMAN, BackendType.CTS]}") + + shArgs.script = getCMCommandLine(type, endpoint, script.username, script.password, + command, args, + clientOpts) + + // user and password are masked by withCredentials + script.echo """[INFO] Executing command line: "${shArgs.script}".""" + + result = script.sh(shArgs) + + break + } + + return result } } - void releaseTransportRequest(BackendType type,String changeId, String transportRequestId, String endpoint, String credentialsId, String clientOpts = '') { + void releaseTransportRequestSOLMAN( + String changeId, + String transportRequestId, + String endpoint, + String credentialsId, + String clientOpts = '') { - def cmd - List args = [] + def cmd = 'release-transport' + def args = [ + '-cID', + changeId, + '-tID', + transportRequestId, + ] - if(type == BackendType.SOLMAN) { - cmd = 'release-transport' - args << '-cID' - args << changeId - } else if(type == BackendType.CTS) { - cmd = 'export-transport' - } else { - throw new IllegalStateException("Invalid backend type: '${type}'") - } + int rc = executeWithCredentials( + BackendType.SOLMAN, + [:], + endpoint, + credentialsId, + cmd, + args, + false, + clientOpts) as int - args << '-tID' - args << transportRequestId - - int rc = executeWithCredentials(type, endpoint, credentialsId, cmd, args, false, clientOpts) as int - if(rc == 0) { - return - } else { + if(rc != 0) { throw new ChangeManagementException("Cannot release Transport Request '$transportRequestId'. Return code from cmclient: $rc.") } } + void releaseTransportRequestCTS( + String transportRequestId, + String endpoint, + String credentialsId, + String clientOpts = '') { + + def cmd = 'export-transport' + def args = [ + '-tID', + transportRequestId, + ] + + int rc = executeWithCredentials( + BackendType.CTS, + [:], + endpoint, + credentialsId, + cmd, + args, + false) as int + + if(rc != 0) { + throw new ChangeManagementException("Cannot release Transport Request '$transportRequestId'. Return code from cmclient: $rc.") + } + } + + void releaseTransportRequestRFC( + Map docker, + String transportRequestId, + String endpoint, + String developmentInstance, + String developmentClient, + String credentialsId, + boolean verbose) { + + def cmd = "cts releaseTransport:${transportRequestId}" + def args = [ + ABAP_DEVELOPMENT_INSTANCE: developmentInstance, + ABAP_DEVELOPMENT_CLIENT: developmentClient, + VERBOSE: verbose, + ] + + int rc = executeWithCredentials( + BackendType.RFC, + docker, + endpoint, + credentialsId, + cmd, + args, + false) as int + + if(rc != 0) { + throw new ChangeManagementException("Cannot release Transport Request '$transportRequestId'. Return code from rfcclient: $rc.") + } + + } + String getCMCommandLine(BackendType type, String endpoint, String username, diff --git a/test/groovy/TransportRequestCreateTest.groovy b/test/groovy/TransportRequestCreateTest.groovy index ad4b863e4..fad0ed08a 100644 --- a/test/groovy/TransportRequestCreateTest.groovy +++ b/test/groovy/TransportRequestCreateTest.groovy @@ -1,3 +1,10 @@ +import static org.hamcrest.Matchers.allOf +import static org.hamcrest.Matchers.containsString + +import java.util.Map + +import org.hamcrest.Matchers +import org.hamcrest.core.StringContains import org.junit.Before import org.junit.Rule import org.junit.Test @@ -54,7 +61,7 @@ public class TransportRequestCreateTest extends BasePiperTest { } @Test - public void changeIdNotProvidedTest() { + public void changeIdNotProvidedSOLANTest() { thrown.expect(IllegalArgumentException) thrown.expectMessage("Change document id not provided (parameter: 'changeDocumentId' or via commit history).") @@ -73,7 +80,7 @@ public class TransportRequestCreateTest extends BasePiperTest { } @Test - public void developmentSystemIdNotProvidedTest() { + public void developmentSystemIdNotProvidedSOLMANTest() { thrown.expect(IllegalArgumentException) thrown.expectMessage("ERROR - NO VALUE AVAILABLE FOR developmentSystemId") @@ -82,7 +89,7 @@ public class TransportRequestCreateTest extends BasePiperTest { } @Test - public void createTransportRequestFailureTest() { + public void createTransportRequestFailureSOLMANTest() { ChangeManagement cm = new ChangeManagement(nullScript) { @@ -154,8 +161,7 @@ public class TransportRequestCreateTest extends BasePiperTest { String description, String endpoint, String credentialsId, - String clientOpts -) { + String clientOpts) { result.transportType = transportType result.targetSystemId = targetSystemId result.description = description @@ -186,6 +192,120 @@ public class TransportRequestCreateTest extends BasePiperTest { assert loggingRule.log.contains("[INFO] Transport Request '001' has been successfully created.") } + @Test + public void createTransportRequestSuccessRFCTest() { + + def result = [:] + + ChangeManagement cm = new ChangeManagement(nullScript) { + + String createTransportRequestRFC( + Map docker, + String endpoint, + String developmentInstance, + String developmentClient, + String credentialsId, + String description, + boolean verbose) { + + result.docker = docker + result.endpoint = endpoint + result.developmentClient = developmentClient + result.developmentInstance= developmentInstance + result.credentialsId = credentialsId + result.description = description + result.verbose = verbose + + return '001' + } + } + + stepRule.step.transportRequestCreate( + script: nullScript, + changeManagement: [ + type: 'RFC', + rfc: [ + developmentInstance: '01', + developmentClient: '001', + ], + endpoint: 'https://example.org/rfc', + ], + developmentSystemId: '001', + description: '', + cmUtils: cm, + verbose: true) + + assert nullScript.commonPipelineEnvironment.getTransportRequestId() == '001' + assert result == [ + docker: [ + image: 'rfc', + options: [], + envVars: [:], + pullImage: true + ], + endpoint: 'https://example.org/rfc', + developmentClient: '001', + developmentInstance: '01', + credentialsId: 'CM', + description: '', + verbose: true + ] + + assert loggingRule.log.contains("[INFO] Creating transport request.") + assert loggingRule.log.contains("[INFO] Transport Request '001' has been successfully created.") + } + + @Test + public void createTransportRequestFailureRFCTest() { + + thrown.expect(AbortException) + thrown.expectMessage('upload failed') + + ChangeManagement cm = new ChangeManagement(nullScript) { + + String createTransportRequestRFC( + Map docker, + String endpoint, + String developmentClient, + String developmentInstance, + String credentialsId, + String description, + boolean verbose) { + + throw new ChangeManagementException('upload failed') + } + } + + stepRule.step.transportRequestCreate( + script: nullScript, + changeManagement: [ + type: 'RFC', + rfc: [ + developmentInstance: '01', + developmentClient: '001', + ], + endpoint: 'https://example.org/rfc', + ], + developmentSystemId: '001', + description: '', + cmUtils: cm) + } + + @Test + public void createTransportRequestSanityChecksRFCTest() { + + thrown.expect(IllegalArgumentException) + thrown.expectMessage(allOf( + containsString('changeManagement/rfc/developmentInstance'), + containsString('changeManagement/rfc/developmentClient'), + )) + stepRule.step.transportRequestCreate( + script: nullScript, + changeManagement: [ + type: 'RFC', + ]) + } + @Test public void cmIntegrationSwichtedOffTest() { diff --git a/test/groovy/TransportRequestReleaseTest.groovy b/test/groovy/TransportRequestReleaseTest.groovy index 960cf2dff..b28895926 100644 --- a/test/groovy/TransportRequestReleaseTest.groovy +++ b/test/groovy/TransportRequestReleaseTest.groovy @@ -1,3 +1,7 @@ +import static org.hamcrest.Matchers.allOf +import static org.hamcrest.Matchers.containsString + +import org.hamcrest.Matchers import org.junit.Before import org.junit.Rule import org.junit.Test @@ -10,6 +14,7 @@ import com.sap.piper.cm.ChangeManagementException import util.BasePiperTest import util.JenkinsCredentialsRule +import util.JenkinsDockerExecuteRule import util.JenkinsStepRule import util.JenkinsLoggingRule import util.JenkinsReadYamlRule @@ -48,7 +53,7 @@ public class TransportRequestReleaseTest extends BasePiperTest { } @Test - public void changeIdNotProvidedTest() { + public void changeDocumentIdNotProvidedSOLMANTest() { ChangeManagement cm = new ChangeManagement(nullScript) { String getChangeDocumentId(String from, @@ -84,14 +89,14 @@ public class TransportRequestReleaseTest extends BasePiperTest { } @Test - public void releaseTransportRequestFailureTest() { + public void releaseTransportRequestFailsSOLMANTest() { thrown.expect(AbortException) thrown.expectMessage("Something went wrong") ChangeManagement cm = new ChangeManagement(nullScript) { - void releaseTransportRequest(BackendType type, + void releaseTransportRequestSOLMAN( String changeId, String transportRequestId, String endpoint, @@ -106,7 +111,257 @@ public class TransportRequestReleaseTest extends BasePiperTest { } @Test - public void releaseTransportRequestSuccessTest() { + public void releaseTransportRequestFailsCTSTest() { + + thrown.expect(AbortException) + thrown.expectMessage("Something went wrong") + + nullScript + .commonPipelineEnvironment + .configuration + .general + .changeManagement + .type = 'CTS' + + ChangeManagement cm = new ChangeManagement(nullScript) { + + void releaseTransportRequestCTS( + String transportRequestId, + String endpoint, + String credentialsId, + String clientOpts) { + + throw new ChangeManagementException('Something went wrong') + } + } + + stepRule.step.transportRequestRelease( + script: nullScript, + transportRequestId: '001', + cmUtils: cm) + } + + @Test + public void releaseTransportRequestSuccessRFCTest() { + + def receivedParameters + + nullScript + .commonPipelineEnvironment + .configuration + .general + .changeManagement = + [ + credentialsId: 'CM', + type: 'RFC', + endpoint: 'https://example.org/rfc', + rfc: [ + dockerImage: 'rfc', + dockerOptions: [], + ], + ] + + ChangeManagement cm = new ChangeManagement(nullScript) { + void releaseTransportRequestRFC( + Map docker, + String transportRequestId, + String endpoint, + String developmentInstance, + String developmentClient, + String credentialsId, + boolean verbose) { + + receivedParameters = [ + docker: docker, + transportRequestId: transportRequestId, + endpoint: endpoint, + developmentInstance: developmentInstance, + developmentClient: developmentClient, + credentialsId: credentialsId, + verbose: verbose, + ] + } + } + + stepRule.step.transportRequestRelease( + script: nullScript, + transportRequestId: '002', + changeManagement: [ + rfc: [ + developmentClient: '003', + developmentInstance: '002', + ] + ], + verbose: true, + cmUtils: cm) + + assert receivedParameters == [ + docker: [ + image: 'rfc', + options: [], + envVars: [:], + pullImage: true, + ], + transportRequestId: '002', + endpoint: 'https://example.org/rfc', + developmentInstance: '002', + developmentClient: '003', + credentialsId: 'CM', + 'verbose': true, + ] + } + + @Test + public void releaseTransportRequestSuccessCTSTest() { + + def receivedParameters + + nullScript + .commonPipelineEnvironment + .configuration + .general + .changeManagement = + [ + credentialsId: 'CM', + type: 'CTS', + endpoint: 'https://example.org/cts' + ] + + ChangeManagement cm = new ChangeManagement(nullScript) { + void releaseTransportRequestCTS( + String transportRequestId, + String endpoint, + String credentialsId, + String clientOpts = '') { + + receivedParameters = [ + transportRequestId: transportRequestId, + endpoint: endpoint, + credentialsId: credentialsId, + clientOpts: clientOpts + ] + } + } + + stepRule.step.transportRequestRelease( + script: nullScript, + transportRequestId: '002', + cmUtils: cm) + + assert receivedParameters == [ + transportRequestId: '002', + endpoint: 'https://example.org/cts', + credentialsId: 'CM', + clientOpts: '' + ] + } + + @Test + public void releaseTransportRequestFailsRFCTest() { + + thrown.expect(AbortException) + thrown.expectMessage('Failed releasing transport request.') + + nullScript + .commonPipelineEnvironment + .configuration + .general + .changeManagement = + [ + credentialsId: 'CM', + type: 'RFC', + endpoint: 'https://example.org/rfc', + rfc: [dockerImage: 'rfc'] + ] + + ChangeManagement cm = new ChangeManagement(nullScript) { + void releaseTransportRequestRFC( + Map docker, + String transportRequestId, + String endpoint, + String developmentInstance, + String developmentClient, + String credentialsId, + boolean verbose) { + + throw new ChangeManagementException('Failed releasing transport request.') + } + } + + stepRule.step.transportRequestRelease( + script: nullScript, + transportRequestId: '002', + changeManagement: [ + rfc: [ + developmentClient: '003', + developmentInstance: '002' + ] + ], + cmUtils: cm) + + } + + @Test + public void releaseTransportRequestSanityChecksSOLMANTest() { + + thrown.expect(IllegalArgumentException) + thrown.expectMessage(allOf( + containsString('ERROR - NO VALUE AVAILABLE FOR'), + containsString('changeManagement/endpoint'))) + + // changeDocumentId and transportRequestId are not checked + // by the sanity checks here since they are looked up from + // commit history in case they are not provided. + + nullScript + .commonPipelineEnvironment + .configuration = null + + stepRule.step.transportRequestRelease( + script: nullScript, + changeManagement: [type: 'SOLMAN'] + ) + } + + @Test + public void releaseTransportRequestSanityChecksCTSTest() { + + thrown.expect(IllegalArgumentException) + thrown.expectMessage(allOf( + containsString('ERROR - NO VALUE AVAILABLE FOR'), + containsString('changeManagement/endpoint'))) + + nullScript + .commonPipelineEnvironment + .configuration = null + + stepRule.step.transportRequestRelease( + script: nullScript, + changeManagement: [type: 'CTS'] + ) + } + + @Test + public void releaseTransportRequestSanityChecksRFCTest() { + + thrown.expect(IllegalArgumentException) + thrown.expectMessage(allOf( + containsString('ERROR - NO VALUE AVAILABLE FOR:'), + containsString('changeManagement/endpoint'), + containsString('developmentClient'))) + + nullScript + .commonPipelineEnvironment + .configuration = null + + stepRule.step.transportRequestRelease( + script: nullScript, + changeManagement: [type: 'RFC'], + transportRequestId: '002') + } + + @Test + public void releaseTransportRequestSuccessSOLMANTest() { // Here we test only the case where the transportRequestId is // provided via parameters. The other cases are tested by @@ -118,14 +373,13 @@ public class TransportRequestReleaseTest extends BasePiperTest { Map receivedParams = [:] ChangeManagement cm = new ChangeManagement(nullScript) { - void releaseTransportRequest(BackendType type, + void releaseTransportRequestSOLMAN( String changeId, String transportRequestId, String endpoint, String credentialsId, String clientOpts) { - receivedParams.type = type receivedParams.changeId = changeId receivedParams.transportRequestId = transportRequestId receivedParams.endpoint = endpoint @@ -136,7 +390,7 @@ public class TransportRequestReleaseTest extends BasePiperTest { stepRule.step.transportRequestRelease(script: nullScript, changeDocumentId: '001', transportRequestId: '002', cmUtils: cm) - assert receivedParams == [type: BackendType.SOLMAN, + assert receivedParams == [ changeId: '001', transportRequestId: '002', endpoint: 'https://example.org/cm', diff --git a/test/groovy/TransportRequestUploadFileTest.groovy b/test/groovy/TransportRequestUploadFileTest.groovy index f3fb7aa62..e7ade0d5e 100644 --- a/test/groovy/TransportRequestUploadFileTest.groovy +++ b/test/groovy/TransportRequestUploadFileTest.groovy @@ -1,11 +1,17 @@ +import static org.hamcrest.Matchers.allOf +import static org.hamcrest.Matchers.containsString + +import java.util.List import java.util.Map +import org.hamcrest.Matchers import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import org.junit.rules.RuleChain +import com.sap.piper.JenkinsUtils import com.sap.piper.cm.BackendType import com.sap.piper.cm.ChangeManagement import com.sap.piper.cm.ChangeManagementException @@ -119,10 +125,10 @@ public class TransportRequestUploadFileTest extends BasePiperTest { } @Test - public void uploadFileToTransportRequestFailureTest() { + public void uploadFileToTransportRequestSOLMANFailureTest() { ChangeManagement cm = new ChangeManagement(nullScript) { - void uploadFileToTransportRequest(BackendType type, + void uploadFileToTransportRequestSOLMAN( String changeId, String transportRequestId, String applicationId, @@ -152,19 +158,14 @@ public class TransportRequestUploadFileTest extends BasePiperTest { loggingRule.expect("[INFO] File '/path' has been successfully uploaded to transport request '002'.") ChangeManagement cm = new ChangeManagement(nullScript) { - void uploadFileToTransportRequest(BackendType type, - String changeId, + void uploadFileToTransportRequestCTS( String transportRequestId, - String applicationId, String filePath, String endpoint, String credentialsId, String cmclientOpts) { - cmUtilReceivedParams.type = type - cmUtilReceivedParams.changeId = changeId cmUtilReceivedParams.transportRequestId = transportRequestId - cmUtilReceivedParams.applicationId = applicationId cmUtilReceivedParams.filePath = filePath cmUtilReceivedParams.endpoint = endpoint cmUtilReceivedParams.credentialsId = credentialsId @@ -180,10 +181,7 @@ public class TransportRequestUploadFileTest extends BasePiperTest { assert cmUtilReceivedParams == [ - type: BackendType.CTS, - changeId: null, transportRequestId: '002', - applicationId: null, filePath: '/path', endpoint: 'https://example.org/cm', credentialsId: 'CM', @@ -191,6 +189,166 @@ public class TransportRequestUploadFileTest extends BasePiperTest { ] } + @Test + public void uploadFileToTransportRequestRFCSanityChecksTest() { + + thrown.expect(IllegalArgumentException) + thrown.expectMessage(allOf( + containsString('NO VALUE AVAILABLE FOR'), + containsString('applicationUrl'), + containsString('developmentInstance'), + containsString('developmentClient'), + containsString('applicationDescription'), + containsString('abapPackage'), + containsString('applicationName'))) + + stepRule.step.transportRequestUploadFile(script: nullScript, + transportRequestId: '123456', //no sanity check, can be read from git history + changeManagement: [type: 'RFC'], + ) + } + + @Test + public void uploadFileToTransportRequestRFCSuccessTest() { + + def cmUtilsReceivedParams + + nullScript.commonPipelineEnvironment.configuration = + [general: + [changeManagement: + [ + endpoint: 'https://example.org/rfc' + ] + ] + ] + + def cm = new ChangeManagement(nullScript) { + + void uploadFileToTransportRequestRFC( + Map docker, + String transportRequestId, + String applicationId, + String applicationURL, + String endpoint, + String credentialsId, + String developmentInstance, + String developmentClient, + String applicationDescription, + String abapPackage, + String codePage, + boolean acceptUnixStyleLineEndings, + boolean failUploadOnWarning, + boolean verbose) { + + cmUtilsReceivedParams = [ + docker: docker, + transportRequestId: transportRequestId, + applicationName: applicationId, + applicationURL: applicationURL, + endpoint: endpoint, + credentialsId: credentialsId, + developmentInstance: developmentInstance, + developmentClient: developmentClient, + applicationDescription: applicationDescription, + abapPackage: abapPackage, + codePage: codePage, + acceptUnixStyleLineEndings: acceptUnixStyleLineEndings, + failUploadOnWarning: failUploadOnWarning, + ] + } + } + + stepRule.step.transportRequestUploadFile(script: nullScript, + applicationUrl: 'http://example.org/blobstore/xyz.zip', + codePage: 'UTF-9', + acceptUnixStyleLineEndings: true, + transportRequestId: '123456', + changeManagement: [ + type: 'RFC', + rfc: [ + developmentClient: '002', + developmentInstance: '001' + ] + ], + applicationName: '42', + applicationDescription: 'Lorem ipsum', + abapPackage: 'XYZ', + cmUtils: cm,) + + assert cmUtilsReceivedParams == + [ + docker: [ + image: 'rfc', + options: [], + envVars: [:], + pullImage: true + ], + transportRequestId: '123456', + applicationName: '42', + applicationURL: 'http://example.org/blobstore/xyz.zip', + endpoint: 'https://example.org/rfc', + credentialsId: 'CM', + developmentInstance: '001', + developmentClient: '002', + applicationDescription: 'Lorem ipsum', + abapPackage:'XYZ', + codePage: 'UTF-9', + acceptUnixStyleLineEndings: true, + failUploadOnWarning: true, + ] + } + + @Test + public void uploadFileToTransportRequestRFCUploadFailsTest() { + + thrown.expect(AbortException) + thrown.expectMessage('upload failed') + + def cm = new ChangeManagement(nullScript) { + + void uploadFileToTransportRequestRFC( + Map docker, + String transportRequestId, + String applicationId, + String applicationURL, + String endpoint, + String credentialsId, + String developmentInstance, + String developmentClient, + String applicationDescription, + String abapPackage, + String codePage, + boolean acceptUnixStyleLineEndings, + boolean failOnUploadWarning, + boolean verbose) { + throw new ChangeManagementException('upload failed') + } + } + + stepRule.step.transportRequestUploadFile(script: nullScript, + applicationUrl: 'http://example.org/blobstore/xyz.zip', + codePage: 'UTF-9', + acceptUnixStyleLineEndings: true, + transportRequestId: '123456', + changeManagement: [ + type: 'RFC', + rfc: [ + docker: [ + image: 'rfc', + options: [], + envVars: [:], + pullImage: false, + ], + developmentClient: '002', + developmentInstance: '001', + ] + ], + applicationName: '42', + applicationDescription: 'Lorem ipsum', + abapPackage: 'XYZ', + cmUtils: cm,) + } + @Test public void uploadFileToTransportRequestSOLMANSuccessTest() { @@ -202,7 +360,7 @@ public class TransportRequestUploadFileTest extends BasePiperTest { loggingRule.expect("[INFO] File '/path' has been successfully uploaded to transport request '002' of change document '001'.") ChangeManagement cm = new ChangeManagement(nullScript) { - void uploadFileToTransportRequest(BackendType type, + void uploadFileToTransportRequestSOLMAN( String changeId, String transportRequestId, String applicationId, @@ -211,7 +369,6 @@ public class TransportRequestUploadFileTest extends BasePiperTest { String credentialsId, String cmclientOpts) { - cmUtilReceivedParams.type = type cmUtilReceivedParams.changeId = changeId cmUtilReceivedParams.transportRequestId = transportRequestId cmUtilReceivedParams.applicationId = applicationId @@ -231,7 +388,6 @@ public class TransportRequestUploadFileTest extends BasePiperTest { assert cmUtilReceivedParams == [ - type: BackendType.SOLMAN, changeId: '001', transportRequestId: '002', applicationId: 'app', @@ -243,14 +399,14 @@ public class TransportRequestUploadFileTest extends BasePiperTest { } @Test - public void uploadFileToTransportRequestSuccessApplicationIdFromConfigurationTest() { + public void uploadFileToTransportRequestSOLMANSuccessApplicationIdFromConfigurationTest() { nullScript.commonPipelineEnvironment.configuration.put(['steps', [transportRequestUploadFile: [applicationId: 'AppIdfromConfig']]]) ChangeManagement cm = new ChangeManagement(nullScript) { - void uploadFileToTransportRequest(BackendType type, + void uploadFileToTransportRequestSOLMAN( String changeId, String transportRequestId, String applicationId, @@ -274,13 +430,13 @@ public class TransportRequestUploadFileTest extends BasePiperTest { } @Test - public void uploadFileToTransportRequestFilePathFromParameters() { + public void uploadFileToTransportRequestSOLMANFilePathFromParameters() { // this one is not used when file path is provided via signature nullScript.commonPipelineEnvironment.setMtarFilePath('/path2') ChangeManagement cm = new ChangeManagement(nullScript) { - void uploadFileToTransportRequest(BackendType type, + void uploadFileToTransportRequestSOLMAN( String changeId, String transportRequestId, String applicationId, @@ -304,13 +460,13 @@ public class TransportRequestUploadFileTest extends BasePiperTest { } @Test - public void uploadFileToTransportRequestFilePathFromCommonPipelineEnvironment() { + public void uploadFileToTransportRequestSOLMANFilePathFromCommonPipelineEnvironment() { // this one is used since there is nothing in the signature nullScript.commonPipelineEnvironment.setMtarFilePath('/path2') ChangeManagement cm = new ChangeManagement(nullScript) { - void uploadFileToTransportRequest(BackendType type, + void uploadFileToTransportRequestSOLMAN( String changeId, String transportRequestId, String applicationId, @@ -333,13 +489,13 @@ public class TransportRequestUploadFileTest extends BasePiperTest { } @Test - public void uploadFileToTransportRequestUploadFailureTest() { + public void uploadFileToTransportRequestSOLMANUploadFailureTest() { thrown.expect(AbortException) thrown.expectMessage('Upload failure.') ChangeManagement cm = new ChangeManagement(nullScript) { - void uploadFileToTransportRequest(BackendType type, + void uploadFileToTransportRequestSOLMAN( String changeId, String transportRequestId, String applicationId, @@ -362,7 +518,7 @@ public class TransportRequestUploadFileTest extends BasePiperTest { @Test public void invalidBackendTypeTest() { thrown.expect(AbortException) - thrown.expectMessage('Invalid backend type: \'DUMMY\'. Valid values: [SOLMAN, CTS, NONE]. ' + + thrown.expectMessage('Invalid backend type: \'DUMMY\'. Valid values: [SOLMAN, CTS, RFC, NONE]. ' + 'Configuration: \'changeManagement/type\'.') stepRule.step.transportRequestUploadFile(script: nullScript, diff --git a/test/groovy/com/sap/piper/cm/ChangeManagementTest.groovy b/test/groovy/com/sap/piper/cm/ChangeManagementTest.groovy index cf32ab220..cad42129d 100644 --- a/test/groovy/com/sap/piper/cm/ChangeManagementTest.groovy +++ b/test/groovy/com/sap/piper/cm/ChangeManagementTest.groovy @@ -1,12 +1,13 @@ package com.sap.piper.cm - import static org.hamcrest.Matchers.allOf +import static org.hamcrest.Matchers.contains import static org.hamcrest.Matchers.containsString import static org.hamcrest.Matchers.equalTo import static org.hamcrest.Matchers.hasItem import static org.hamcrest.Matchers.is import static org.hamcrest.Matchers.not import static org.junit.Assert.assertThat +import static org.junit.Assert.assertEquals import org.hamcrest.Matchers import org.junit.Assert @@ -22,6 +23,7 @@ import util.JenkinsLoggingRule import util.JenkinsScriptLoaderRule import util.JenkinsShellCallRule import util.JenkinsCredentialsRule +import util.JenkinsDockerExecuteRule import util.Rules import hudson.AbortException @@ -32,6 +34,7 @@ public class ChangeManagementTest extends BasePiperTest { private JenkinsShellCallRule script = new JenkinsShellCallRule(this) private JenkinsLoggingRule logging = new JenkinsLoggingRule(this) + private JenkinsDockerExecuteRule dockerExecuteRule = new JenkinsDockerExecuteRule(this) @Rule public RuleChain rules = Rules.getCommonRules(this) @@ -39,6 +42,7 @@ public class ChangeManagementTest extends BasePiperTest { .around(script) .around(logging) .around(new JenkinsCredentialsRule(this).withCredentials('me','user','password')) + .around(dockerExecuteRule) @Test public void testRetrieveChangeDocumentIdOutsideGitWorkTreeTest() { @@ -167,6 +171,57 @@ public void testGetCommandLineWithCMClientOpts() { } + @Test + public void testCreateTransportRequestRFCSucceeds() { + + script.setReturnValue('cts createTransportRequest', '{"REQUESTID":"XYZK9000004"}') + + def transportRequestId = new ChangeManagement(nullScript).createTransportRequestRFC( + [image: 'rfc', options: []], + 'https://example.org/rfc', // endpoint + '01', // instance + '001', // client + 'me', // credentialsId + 'Lorem ipsum', // description + true // verbose + ) + + assert dockerExecuteRule.dockerParams.dockerImage == 'rfc' + + assert dockerExecuteRule.dockerParams.dockerEnvVars == [ + TRANSPORT_DESCRIPTION: 'Lorem ipsum', + ABAP_DEVELOPMENT_INSTANCE: '01', + ABAP_DEVELOPMENT_CLIENT: '001', + ABAP_DEVELOPMENT_SERVER: 'https://example.org/rfc', + ABAP_DEVELOPMENT_USER: 'user', + ABAP_DEVELOPMENT_PASSWORD: 'password', + VERBOSE: true + ] + + assert transportRequestId == 'XYZK9000004' + + } + + @Test + public void testCreateTransportRequestRFCFails() { + + thrown.expect(ChangeManagementException) + thrown.expectMessage('Cannot create transport request: script returned exit code 3') + + script.setReturnValue('cts createTransportRequest', + { throw new AbortException('script returned exit code 3')}) + + def transportRequestId = new ChangeManagement(nullScript).createTransportRequestRFC( + [image: 'rfc', options: []], + 'https://example.org/rfc', // endpoint + '001', // client + '01', // instance + 'me', // credentialsId + 'Lorem ipsum', // description + true, //verbose + ) + } + @Test public void testCreateTransportRequestCTSSucceeds() { @@ -185,32 +240,13 @@ public void testGetCommandLineWithCMClientOpts() { } - @Test - public void testCreateTransportRequestFails() { - - script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*upload-file-to-transport.*', 1) - - thrown.expect(ChangeManagementException) - thrown.expectMessage('Cannot upload file \'/path\' for change document \'001\''+ - ' with transport request \'002\'. Return code from cmclient: 1.') - - new ChangeManagement(nullScript).uploadFileToTransportRequest(BackendType.SOLMAN, - '001', - '002', - 'XXX', - '/path', - 'https://example.org/cm', - 'me') - } - @Test public void testUploadFileToTransportSucceedsSOLMAN() { // the regex provided below is an implicit check that the command line is fine. script.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'upload-file-to-transport.*-cID 001 -tID 002 XXX "/path"', 0) - new ChangeManagement(nullScript).uploadFileToTransportRequest( - BackendType.SOLMAN, + new ChangeManagement(nullScript).uploadFileToTransportRequestSOLMAN( '001', '002', 'XXX', @@ -228,11 +264,8 @@ public void testGetCommandLineWithCMClientOpts() { // the regex provided below is an implicit check that the command line is fine. script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '-t CTS upload-file-to-transport -tID 002 "/path"', 0) - new ChangeManagement(nullScript).uploadFileToTransportRequest( - BackendType.CTS, - null, + new ChangeManagement(nullScript).uploadFileToTransportRequestCTS( '002', - null, '/path', 'https://example.org/cm', 'me') @@ -242,15 +275,85 @@ public void testGetCommandLineWithCMClientOpts() { } @Test - public void testUploadFileToTransportFails() { + public void testUploadFileToTransportSucceedsRFC() { + + new ChangeManagement(nullScript).uploadFileToTransportRequestRFC( + [image:'rfc', options: [], pullImage: true], + '002', //transportRequestId + '001', // applicationId + 'https://example.org/mypath/deployArtifact.zip', + 'https://example.org/rfc', + 'me', + '00', //developmentInstance + '001', // developmentClient + 'Lorem ipsum', // applicationDescription + 'XYZ', // abapPackage + 'UTF-9', //codePage + true, // accept unix style EOL + true, // failUploadOnWarning + false, // verbose + ) + + + assert dockerExecuteRule.dockerParams.dockerImage == 'rfc' + assert dockerExecuteRule.dockerParams.dockerPullImage == true + + assert dockerExecuteRule.dockerParams.dockerEnvVars == + [ + ABAP_DEVELOPMENT_INSTANCE: '00', + ABAP_DEVELOPMENT_CLIENT: '001', + ABAP_APPLICATION_NAME: '001', + ABAP_APPLICATION_DESC: 'Lorem ipsum', + ABAP_PACKAGE: 'XYZ', + ZIP_FILE_URL: 'https://example.org/mypath/deployArtifact.zip', + ABAP_DEVELOPMENT_SERVER: 'https://example.org/rfc', + ABAP_DEVELOPMENT_USER: 'user', + ABAP_DEVELOPMENT_PASSWORD: 'password', + CODE_PAGE: 'UTF-9', + ABAP_ACCEPT_UNIX_STYLE_EOL: 'X', + FAIL_UPLOAD_ON_WARNING: 'true', + VERBOSE: 'false' + ] + + assertThat(script.shell, contains('cts uploadToABAP:002')) + } + + @Test + public void testUploadFileToTransportFailsRFC() { thrown.expect(ChangeManagementException) - thrown.expectMessage("Cannot upload file '/path' for change document '001' with transport request '002'. " + - "Return code from cmclient: 1.") + thrown.expectMessage('Cannot upload file into transport request. Return code from rfc client: 1.') + + script.setReturnValue('cts uploadToABAP:002', 1) + + new ChangeManagement(nullScript).uploadFileToTransportRequestRFC( + [:], + '002', //transportRequestId + '001', // applicationId + 'https://example.org/mypath/deployArtifact.zip', + 'https://example.org/rfc', + 'me', + '00', //developmentInstance + '001', // developmentClient + 'Lorem ipsum', // applicationDescription + 'XYZ', // abapPackage + 'UTF-9', // codePage + true, // accept unix style EOL + true, // failUploadOnWarning + false, // verbose + ) + } + + @Test + public void testUploadFileToTransportFailsSOLMAN() { + + thrown.expect(ChangeManagementException) + thrown.expectMessage("Cannot upload file into transport request. " + + "Return code from cm client: 1.") script.setReturnValue(JenkinsShellCallRule.Type.REGEX,, 'upload-file-to-transport', 1) - new ChangeManagement(nullScript).uploadFileToTransportRequest(BackendType.SOLMAN, + new ChangeManagement(nullScript).uploadFileToTransportRequestSOLMAN( '001', '002', 'XXX', @@ -265,8 +368,7 @@ public void testGetCommandLineWithCMClientOpts() { // the regex provided below is an implicit check that the command line is fine. script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '-t SOLMAN release-transport.*-cID 001.*-tID 002', 0) - new ChangeManagement(nullScript).releaseTransportRequest( - BackendType.SOLMAN, + new ChangeManagement(nullScript).releaseTransportRequestSOLMAN( '001', '002', 'https://example.org', @@ -283,9 +385,7 @@ public void testGetCommandLineWithCMClientOpts() { // the regex provided below is an implicit check that the command line is fine. script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '-t CTS export-transport.*-tID 002', 0) - new ChangeManagement(nullScript).releaseTransportRequest( - BackendType.CTS, - null, + new ChangeManagement(nullScript).releaseTransportRequestCTS( '002', 'https://example.org', 'me', @@ -296,7 +396,31 @@ public void testGetCommandLineWithCMClientOpts() { } @Test - public void testReleaseTransportRequestFails() { + public void testReleaseTransportRequestSucceedsRFC() { + + new ChangeManagement(nullScript).releaseTransportRequestRFC( + [:], + '002', + 'https://example.org', + '002', + '001', + 'me', + true) + + assert dockerExecuteRule.dockerParams.dockerEnvVars == [ + ABAP_DEVELOPMENT_SERVER: 'https://example.org', + ABAP_DEVELOPMENT_USER: 'user', + ABAP_DEVELOPMENT_PASSWORD: 'password', + ABAP_DEVELOPMENT_CLIENT: '001', + ABAP_DEVELOPMENT_INSTANCE: '002', + VERBOSE: true, + ] + + assertThat(script.shell, hasItem('cts releaseTransport:002')) + } + + @Test + public void testReleaseTransportRequestFailsSOLMAN() { thrown.expect(ChangeManagementException) thrown.expectMessage("Cannot release Transport Request '002'. Return code from cmclient: 1.") @@ -304,16 +428,13 @@ public void testGetCommandLineWithCMClientOpts() { // the regex provided below is an implicit check that the command line is fine. script.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'release-transport.*-cID 001.*-tID 002', 1) - new ChangeManagement(nullScript).releaseTransportRequest( - BackendType.SOLMAN, + new ChangeManagement(nullScript).releaseTransportRequestSOLMAN( '001', '002', 'https://example.org', - 'me', - 'openSesame') + 'me') } - private GitUtils gitUtilsMock(boolean insideWorkTree, String[] changeIds) { return new GitUtils() { public boolean insideWorkTree() { diff --git a/vars/transportRequestCreate.groovy b/vars/transportRequestCreate.groovy index 1dcb94c4a..04dd373f8 100644 --- a/vars/transportRequestCreate.groovy +++ b/vars/transportRequestCreate.groovy @@ -23,6 +23,7 @@ import hudson.AbortException 'developmentSystemId', // SOLMAN 'targetSystem', // CTS 'transportType', // CTS + 'verbose', // RFC ] @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus(['changeDocumentId']) @@ -38,6 +39,7 @@ void call(parameters = [:]) { ChangeManagement cm = parameters.cmUtils ?: new ChangeManagement(script) ConfigurationHelper configHelper = ConfigurationHelper.newInstance(this) + .collectValidationFailures() .loadStepDefaults() .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS) .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS) @@ -60,6 +62,9 @@ void call(parameters = [:]) { .withMandatoryProperty('transportType', null, { backendType == BackendType.CTS}) .withMandatoryProperty('targetSystem', null, { backendType == BackendType.CTS}) .withMandatoryProperty('description', null, { backendType == BackendType.CTS}) + .withMandatoryProperty('changeManagement/rfc/developmentInstance', null, {backendType == BackendType.RFC}) + .withMandatoryProperty('changeManagement/rfc/developmentClient', null, {backendType == BackendType.RFC}) + .withMandatoryProperty('verbose', null, {backendType == BackendType.RFC}) def changeDocumentId = null @@ -88,7 +93,8 @@ void call(parameters = [:]) { creatingMessage << '.' echo creatingMessage.join() - try { + + try { if(backendType == BackendType.SOLMAN) { transportRequestId = cm.createTransportRequestSOLMAN( configuration.changeDocumentId, @@ -104,6 +110,15 @@ void call(parameters = [:]) { configuration.changeManagement.endpoint, configuration.changeManagement.credentialsId, configuration.changeManagement.clientOpts) + } else if (backendType == BackendType.RFC) { + transportRequestId = cm.createTransportRequestRFC( + configuration.changeManagement.rfc.docker, + configuration.changeManagement.endpoint, + configuration.changeManagement.rfc.developmentInstance, + configuration.changeManagement.rfc.developmentClient, + configuration.changeManagement.credentialsId, + configuration.description, + configuration.verbose) } else { throw new IllegalArgumentException("Invalid backend type: '${backendType}'.") } diff --git a/vars/transportRequestRelease.groovy b/vars/transportRequestRelease.groovy index 334251021..9d87b185d 100644 --- a/vars/transportRequestRelease.groovy +++ b/vars/transportRequestRelease.groovy @@ -25,6 +25,7 @@ import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrati @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([ 'changeDocumentId', 'transportRequestId', + 'verbose', ]) void call(parameters = [:]) { @@ -49,12 +50,16 @@ void call(parameters = [:]) { if(backendType == BackendType.NONE) return configHelper + .collectValidationFailures() .withMandatoryProperty('changeManagement/clientOpts') .withMandatoryProperty('changeManagement/credentialsId') .withMandatoryProperty('changeManagement/endpoint') .withMandatoryProperty('changeManagement/git/to') .withMandatoryProperty('changeManagement/git/from') .withMandatoryProperty('changeManagement/git/format') + .withMandatoryProperty('changeManagement/rfc/developmentInstance', null, { backendType == BackendType.RFC}) + .withMandatoryProperty('changeManagement/rfc/developmentClient', null, { backendType == BackendType.RFC}) + .withMandatoryProperty('verbose', null, { backendType == BackendType.RFC}) configuration = configHelper.use() @@ -89,13 +94,44 @@ void call(parameters = [:]) { echo closingMessage.join() try { - cm.releaseTransportRequest(backendType, - configuration.changeDocumentId, - configuration.transportRequestId, - configuration.changeManagement.endpoint, - configuration.changeManagement.credentialsId, - configuration.changeManagement.clientOpts) + switch(backendType) { + + case BackendType.SOLMAN: + + cm.releaseTransportRequestSOLMAN( + configuration.changeDocumentId, + configuration.transportRequestId, + configuration.changeManagement.endpoint, + configuration.changeManagement.credentialsId, + configuration.changeManagement.clientOpts) + break + + case BackendType.CTS: + + cm.releaseTransportRequestCTS( + configuration.transportRequestId, + configuration.changeManagement.endpoint, + configuration.changeManagement.credentialsId, + configuration.changeManagement.clientOpts) + break + + case BackendType.RFC: + + cm.releaseTransportRequestRFC( + configuration.changeManagement.rfc.docker, + configuration.transportRequestId, + configuration.changeManagement.endpoint, + configuration.changeManagement.rfc.developmentInstance, + configuration.changeManagement.rfc.developmentClient, + configuration.changeManagement.credentialsId, + configuration.verbose) + break + + default: + + throw new IllegalArgumentException("Invalid backend type: '${backendType}'.") + } } catch(ChangeManagementException ex) { throw new AbortException(ex.getMessage()) } diff --git a/vars/transportRequestUploadFile.groovy b/vars/transportRequestUploadFile.groovy index ceae10712..ec853b70b 100644 --- a/vars/transportRequestUploadFile.groovy +++ b/vars/transportRequestUploadFile.groovy @@ -21,12 +21,19 @@ import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrati ] @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([ - 'applicationId' + 'applicationName', // RFC + 'applicationId', // SOLMAN + 'applicationDescription', + 'filePath', // SOLMAN, CTS + 'applicationUrl', // RFC + 'abapPackage', + 'codePage', //RFC + 'acceptUnixStyleLineEndings', // RFC + 'verbose', // RFC ]) @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([ 'changeDocumentId', - 'filePath', 'transportRequestId']) void call(parameters = [:]) { @@ -51,6 +58,7 @@ void call(parameters = [:]) { if(backendType == BackendType.NONE) return configHelper + .collectValidationFailures() .withMandatoryProperty('changeManagement/changeDocumentLabel') .withMandatoryProperty('changeManagement/clientOpts') .withMandatoryProperty('changeManagement/credentialsId') @@ -59,7 +67,22 @@ void call(parameters = [:]) { .withMandatoryProperty('changeManagement/git/from') .withMandatoryProperty('changeManagement/git/to') .withMandatoryProperty('changeManagement/git/format') - .withMandatoryProperty('filePath') + .withMandatoryProperty('filePath', null, { backendType in [BackendType.SOLMAN, BackendType.CTS] }) + .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 == BackendType.RFC }) + .withMandatoryProperty('applicationId', null, {backendType == BackendType.SOLMAN}) + .withMandatoryProperty('applicationName', null, {backendType == BackendType.RFC}) + .withMandatoryProperty('failOnWarning', null, {backendType == BackendType.RFC}) + .withMandatoryProperty('verbose', null, {backendType == BackendType.RFC}) new Utils().pushToSWA([ step: STEP_NAME, @@ -85,14 +108,15 @@ void call(parameters = [:]) { configHelper .withMandatoryProperty('changeDocumentId', "Change document id not provided (parameter: \'changeDocumentId\' or via commit history).") - .withMandatoryProperty('applicationId') } configuration = configHelper .withMandatoryProperty('transportRequestId', "Transport request id not provided (parameter: \'transportRequestId\' or via commit history).") .use() - def uploadingMessage = ["[INFO] Uploading file '${configuration.filePath}' to transport request '${configuration.transportRequestId}'"] + def uploadingMessage = ['[INFO] Uploading file ' + + "'${backendType == BackendType.RFC ? configuration.applicationUrl : configuration.filePath}' " + + "to transport request '${configuration.transportRequestId}'"] if(backendType == BackendType.SOLMAN) uploadingMessage << " of change document '${configuration.changeDocumentId}'" uploadingMessage << '.' @@ -101,22 +125,55 @@ void call(parameters = [:]) { try { + switch(backendType) { - cm.uploadFileToTransportRequest(backendType, - configuration.changeDocumentId, - configuration.transportRequestId, - configuration.applicationId, - configuration.filePath, - configuration.changeManagement.endpoint, - configuration.changeManagement.credentialsId, - configuration.changeManagement.clientOpts) + case BackendType.SOLMAN: + cm.uploadFileToTransportRequestSOLMAN( + configuration.changeDocumentId, + configuration.transportRequestId, + configuration.applicationId, + configuration.filePath, + configuration.changeManagement.endpoint, + configuration.changeManagement.credentialsId, + configuration.changeManagement.clientOpts) + break + case BackendType.CTS: + cm.uploadFileToTransportRequestCTS( + configuration.transportRequestId, + configuration.filePath, + configuration.changeManagement.endpoint, + configuration.changeManagement.credentialsId, + configuration.changeManagement.clientOpts) + break + case BackendType.RFC: + + cm.uploadFileToTransportRequestRFC( + configuration.changeManagement.rfc.docker ?: [], + configuration.transportRequestId, + configuration.applicationName, + configuration.applicationUrl, + configuration.changeManagement.endpoint, + configuration.changeManagement.credentialsId, + configuration.changeManagement.rfc.developmentInstance, + configuration.changeManagement.rfc.developmentClient, + configuration.applicationDescription, + configuration.abapPackage, + configuration.codePage, + configuration.acceptUnixStyleLineEndings, + configuration.failOnWarning, + configuration.verbose + ) + + break + + } } catch(ChangeManagementException ex) { throw new AbortException(ex.getMessage()) } - def uploadedMessage = ["[INFO] File '${configuration.filePath}' has been successfully uploaded to transport request '${configuration.transportRequestId}'"] + def uploadedMessage = ["[INFO] File '${backendType == BackendType.RFC ? configuration.applicationUrl : configuration.filePath}' has been successfully uploaded to transport request '${configuration.transportRequestId}'"] if(backendType == BackendType.SOLMAN) uploadedMessage << " of change document '${configuration.changeDocumentId}'" uploadedMessage << '.'