1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-03-03 15:02:35 +02:00

ABAP deploy to front end server via existing fiori upload facilities (#1939)

The approach used up to now did not (... never) work since the uploaded content was always assigned to the `$TMP` package. In the meanwhile there is some fiori tooling available for managing such uploads.

Now we re-use this fiori tooling.

Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>
This commit is contained in:
Marcus Holl 2020-10-21 12:04:11 +02:00 committed by GitHub
parent dc3bf0e68d
commit 4f9bc698f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 520 additions and 74 deletions

View File

@ -64,6 +64,80 @@ The properties can also be configured on a per-step basis:
The parameters can also be provided when the step is invoked. For examples see below.
## CTS Uploads
In order to be able to upload the application, it is required to build the application, e.g. via `npmExecute`
or `mtaBuild`. The content of the app needs to be provided in a folder named `dist` in the root level of the project.
Although the name of the step `transportRequestUploadFile` might suggest something else, in this case a folder needs
to be provided. The application, which is provided in the `dist` folder is zipped and uploaded by the fiori toolset
used for performing the upload.
For `CTS` related uploads we use a node based toolset. When running in a docker environment a standard node
image can be used. In this case the required deploy tool dependencies will be installed prior to the deploy.
It is also possible to provide a docker image which already contains the required deploy tool
dependencies (`config.changeManagement.cts.nodeDocker.image`). In this case an empty list needs to be provided
as `config.changeManagement.cts.deployToolDependencies`. Using an already pre-configured docker image speeds-up
the deployment step, but comes with the disadvantage of having
to maintain and provision the corresponding docker image.
When running in an environment without docker, it is recommanded to install the deploy tools manually on the
system and to provide an empty list for the deploy tool dependencies (`config.changeManagement.cts.deployToolDependencies`).
### Examples
#### Upload based on preconfigured image
```groovy
transportRequestUploadFile script: this,
changeManagement: [
credentialsId: 'CRED_ID', // credentials needs to be defined inside Jenkins
type: 'CTS',
endpoint: 'https://example.org:8000',
client: '001',
cts: [
nodeDocker: [
image: 'docker-image-name',
pullImage: true, // needs to be set to false in case the image is
// only available in the local docker cache (not recommended)
],
npmInstallOpts: [],
deployToolDependencies: [], // empty since we use an already preconfigured image
],
],
applicationName: 'APP',
abapPackage: 'ABABPACKAGE',
transportRequestId: 'XXXK123456', // can be omitted when resolved via commit history
applicationDescription: 'An optional description' // only used in case a new application is deployed
// description is not updated for re-deployments
}
```
#### Upload based on a standard node image
```groovy
transportRequestUploadFile script: this,
changeManagement: [
credentialsId: 'CRED_ID', // credentials needs to be defined inside Jenkins
type: 'CTS',
endpoint: 'https://example.org:8000',
client: '001',
cts: [
npmInstallOpts: [
'--verbose', // might be benefical for troubleshooting
'--registry', 'https://your.npmregistry.org/', // an own registry can be specified here
],
],
],
applicationName: 'APP',
abapPackage: 'ABABPACKAGE',
transportRequestId: 'XXXK123456', // can be omitted when resolved via commit history
applicationDescription: 'An optional description' // only used in case a new application is deployed
// description is not updated for re-deployments
}
```
## Exceptions
* `IllegalArgumentException`:
@ -91,15 +165,15 @@ transportRequestUploadFile(
)
// CTS
// NOTE: CTS upload currently not supported!
transportRequestUploadFile(
script: this,
transportRequestId: '001', // typically provided via git commit history
filePath: '/path',
changeManagement: [
type: 'CTS'
endpoint: 'https://example.org/cm'
]
endpoint: 'https://example.org/cm',
client: '099',
],
applicationName: 'myApp',
abapPackage: 'MYPACKAGE',
)
```

View File

@ -24,6 +24,18 @@ general:
envVars: {}
pullImage: true
cts:
osDeployUser: 'node'
deployToolDependencies:
- '@ui5/cli'
- '@sap/ux-ui5-tooling'
- '@ui5/logger'
- '@ui5/fs'
deployConfigFile: 'ui5-deploy.yaml'
nodeDocker:
image: 'node'
options: []
envVars: {}
pullImage: true
docker:
image: 'ppiper/cm-client'
options: []

View File

@ -172,29 +172,148 @@ public class ChangeManagement implements Serializable {
void uploadFileToTransportRequestCTS(
Map docker,
String transportRequestId,
String filePath,
String endpoint,
String credentialsId,
String cmclientOpts = '') {
String client,
String applicationName,
String description,
String abapPackage, // "package" would be better, but this is a keyword
String osDeployUser,
def deployToolDependencies,
def npmInstallOpts,
String deployConfigFile,
String credentialsId) {
def args = [
'-tID', transportRequestId,
"\"$filePath\""
]
def script = this.script
int rc = executeWithCredentials(
BackendType.CTS,
docker,
endpoint,
credentialsId,
'upload-file-to-transport',
args,
false,
cmclientOpts) as int
def desc = description ?: 'Deployed with Piper based on SAP Fiori tools'
if(rc != 0) {
throw new ChangeManagementException(
"Cannot upload file into transport request. Return code from cm client: $rc.")
if (deployToolDependencies in List) {
deployToolDependencies = deployToolDependencies.join(' ')
}
if (npmInstallOpts in List) {
npmInstallOpts = npmInstallOpts.join(' ')
}
deployToolDependencies = deployToolDependencies.trim()
/*
In case the configuration has been adjusted so that no deployToolDependencies are provided
we assume an image is used, which already contains all dependencies.
In this case we don't invoke npm install and we run the image with the standard user
already, since there is no need for being root. Hence we don't need to switch user also
in the script.
*/
boolean noInstall = deployToolDependencies.isEmpty()
Iterable cmd = ['#!/bin/bash -e']
if (! noInstall) {
cmd << "npm install --global ${npmInstallOpts} ${deployToolDependencies}"
cmd << "su ${osDeployUser}"
} else {
script.echo "[INFO] no deploy dependencies provided. Skipping npm install call. Assuming docker image '${docker?.image}' already contains the dependencies for performing the deployment."
}
Iterable params = []
boolean useConfigFile = true, noConfig = false
if (!deployConfigFile) {
useConfigFile = false
noConfig = !script.fileExists('ui5-deploy.yaml')
} else {
if (script.fileExists(deployConfigFile)) {
// in this case we will use the config file
useConfigFile = true
} else {
if (deployConfigFile == 'ui5-deploy.yaml') {
// in this case this is most likely provided by the piper default config and
// it was not explicitly configured. Hence we assume not having a config file
useConfigFile = false
noConfig = true
} else {
script.error("Configured deploy config file '${deployConfigFile}' does not exists.")
}
}
}
if (noConfig) {
params += ['--noConfig'] // no config file, but we will provide our parameters
}
if (useConfigFile) {
params += ['-c', "\"" + deployConfigFile + "\""]
}
//
// All the parameters below encapsulated in an if statement might also be provided in a config file.
// In case they are empty we don't add to the command line and we trust in the config file.
// In case they are finally missing the fiori deploy toolset will tell us.
//
if (transportRequestId) {
params += ['-t', transportRequestId]
}
if (endpoint) {
params += ['-u', endpoint]
}
if (abapPackage) {
params += ['-p', abapPackage]
}
if (applicationName) {
params += ['-n' , applicationName]
}
if (client) {
params += ['-l', client]
}
params += ['-e', "\"" + desc + "\""]
params += ['-f'] // failfast --> provide return code != 0 in case of any failure
params += ['-y'] // autoconfirm --> no need to press 'y' key in order to confirm the params and trigger the deployment
// Here we provide the names of the environment variable holding username and password. Below we set these values.
params += ['--username', 'ABAP_USER', '--password', 'ABAP_PASSWORD']
def fioriDeployCmd = "fiori deploy ${params.join(' ')}"
script.echo "Executing deploy command: '${fioriDeployCmd}'"
cmd << fioriDeployCmd
script.withCredentials([script.usernamePassword(
credentialsId: credentialsId,
passwordVariable: 'password',
usernameVariable: 'username')]) {
/*
After installing the deploy toolset we switch the user. Since we do not `su` with option `-l` the
environment variables are preserved. Hence the environment variables for user and password are
still available after the user switch.
*/
def dockerEnvVars = docker.envVars ?: [:]
dockerEnvVars += [ABAP_USER: script.username, ABAP_PASSWORD: script.password]
def dockerOptions = docker.options ?: []
if (!noInstall) {
// when we install globally we need to be root, after preparing that we can su node` in the bash script.
// in case there is already a u provided the latest (... what we set here wins).
dockerOptions += ['-u', '0']
}
script.dockerExecute(
script: script,
dockerImage: docker.image,
dockerOptions: dockerOptions,
dockerEnvVars: dockerEnvVars,
dockerPullImage: docker.pullImage) {
script.sh script: cmd.join('\n')
}
}
}

View File

@ -164,48 +164,75 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
@Test
public void uploadFileToTransportRequestCTSSuccessTest() {
loggingRule.expect("[INFO] Uploading file '/path' to transport request '002'.")
loggingRule.expect("[INFO] File '/path' has been successfully uploaded to transport request '002'.")
loggingRule.expect("[INFO] Uploading application 'myApp' to transport request '002'.")
loggingRule.expect("[INFO] Application 'myApp' has been successfully uploaded to transport request '002'.")
ChangeManagement cm = new ChangeManagement(nullScript) {
void uploadFileToTransportRequestCTS(
Map docker,
String transportRequestId,
String filePath,
String endpoint,
String credentialsId,
String cmclientOpts) {
String client,
String appName,
String appDescription,
String abapPackage,
String osDeployUser,
def deployToolsDependencies,
def npmInstallArgs,
String deployConfigFile,
String credentialsId) {
cmUtilReceivedParams.docker = docker
cmUtilReceivedParams.transportRequestId = transportRequestId
cmUtilReceivedParams.filePath = filePath
cmUtilReceivedParams.endpoint = endpoint
cmUtilReceivedParams.client = client
cmUtilReceivedParams.appName = appName
cmUtilReceivedParams.appDescription = appDescription
cmUtilReceivedParams.abapPackage = abapPackage
cmUtilReceivedParams.osDeployUser = osDeployUser
cmUtilReceivedParams.deployToolDependencies = deployToolsDependencies
cmUtilReceivedParams.npmInstallOpts = npmInstallArgs
cmUtilReceivedParams.deployConfigFile = deployConfigFile
cmUtilReceivedParams.credentialsId = credentialsId
cmUtilReceivedParams.cmclientOpts = cmclientOpts
}
}
stepRule.step.transportRequestUploadFile(script: nullScript,
changeManagement: [type: 'CTS'],
changeManagement: [
type: 'CTS',
client: '001',
cts: [
osDeployUser: 'node2',
deployToolDependencies: ['@ui5/cli', '@sap/ux-ui5-tooling', '@ui5/logger', '@ui5/fs', '@dummy/foo'],
npmInstallOpts: ['--verbose'],
]
],
applicationName: 'myApp',
applicationDescription: 'the description',
abapPackage: 'myPackage',
transportRequestId: '002',
filePath: '/path',
cmUtils: cm)
assert cmUtilReceivedParams ==
[
docker: [
image: 'ppiper/cm-client',
image: 'node',
options:[],
envVars:[:],
pullImage:true
],
transportRequestId: '002',
filePath: '/path',
endpoint: 'https://example.org/cm',
client: '001',
appName: 'myApp',
appDescription: 'the description',
abapPackage: 'myPackage',
osDeployUser: 'node2',
deployToolDependencies: ['@ui5/cli', '@sap/ux-ui5-tooling', '@ui5/logger', '@ui5/fs', '@dummy/foo'],
npmInstallOpts: ['--verbose'],
deployConfigFile: 'ui5-deploy.yaml',
credentialsId: 'CM',
cmclientOpts: ''
]
}
@Test

View File

@ -7,6 +7,7 @@ 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
@ -24,6 +25,7 @@ import util.JenkinsScriptLoaderRule
import util.JenkinsShellCallRule
import util.JenkinsCredentialsRule
import util.JenkinsDockerExecuteRule
import util.JenkinsFileExistsRule
import util.Rules
import hudson.AbortException
@ -35,6 +37,7 @@ public class ChangeManagementTest extends BasePiperTest {
private JenkinsShellCallRule script = new JenkinsShellCallRule(this)
private JenkinsLoggingRule logging = new JenkinsLoggingRule(this)
private JenkinsDockerExecuteRule dockerExecuteRule = new JenkinsDockerExecuteRule(this)
private JenkinsFileExistsRule files = new JenkinsFileExistsRule(this)
@Rule
public RuleChain rules = Rules.getCommonRules(this)
@ -43,6 +46,7 @@ public class ChangeManagementTest extends BasePiperTest {
.around(logging)
.around(new JenkinsCredentialsRule(this).withCredentials('me','user','password'))
.around(dockerExecuteRule)
.around(files)
@Test
public void testRetrieveChangeDocumentIdOutsideGitWorkTreeTest() {
@ -291,26 +295,183 @@ public void testGetCommandLineWithCMClientOpts() {
}
@Test
public void testUploadFileToTransportSucceedsCTS() {
public void testUploadFileToTransportSucceedsCTSDeployConfigYamlExists() {
// 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)
files.existingFiles.add('ui5-deploy.yaml')
new ChangeManagement(nullScript).uploadFileToTransportRequestCTS(
[
image: 'ppiper/cmclient',
image: 'node',
pullImage: true
],
'002',
'/path',
'https://example.org/cm',
'me')
'001',
'myApp',
'the description',
'aPackage',
'node2',
['@ui5/cli', '@sap/ux-ui5-tooling', '@ui5/logger', '@ui5/fs', '@dummy/foo'],
['--verbose'],
'ui5-deploy.yaml',
'me',
)
assert dockerExecuteRule.getDockerParams().dockerImage == 'ppiper/cmclient'
assert script.shell[0].contains('npm install --global --verbose @ui5/cli @sap/ux-ui5-tooling @ui5/logger @ui5/fs @dummy/foo')
assert script.shell[0].contains("fiori deploy -c \"ui5-deploy.yaml\" -t 002 -u https://example.org/cm")
assert dockerExecuteRule.getDockerParams().dockerImage == 'node'
assert dockerExecuteRule.getDockerParams().dockerPullImage == true
assert dockerExecuteRule.getDockerParams().dockerEnvVars == [ABAP_USER: "user", ABAP_PASSWORD: 'password']
// we launch the container as root (uid 0) in order to be able to install
// the deploytool. Before deploying we su to another user.
assert dockerExecuteRule.getDockerParams().dockerOptions == ['-u', '0']
}
// no assert for the shell command required here, since the regex registered
// above to the script rule is an implicit check for the command line.
@Test
public void testUploadFileToTransportSucceedsCTSDefaultDeployConfigYamlDoesNotExist() {
// the file does not exist, since it was not explicity added to the files rule
new ChangeManagement(nullScript).uploadFileToTransportRequestCTS(
[
image: 'node',
pullImage: true
],
'002',
'https://example.org/cm',
'001',
'myApp',
'the description',
'aPackage',
'node2',
['@ui5/cli', '@sap/ux-ui5-tooling', '@ui5/logger', '@ui5/fs', '@dummy/foo'],
['--verbose'],
'ui5-deploy.yaml',
'me',
)
// more details already checked with test "testUploadFileToTransportSucceedsCTSDeployConfigYamlExists"
assert script.shell[0].contains("fiori deploy --noConfig -t 002 -u https://example.org/cm")
}
@Test
public void testUploadFileToTransportFailsCTSExplicitlyConfiguredDeployConfigYamlDoesNotExist() {
// the file does not exist, since it was not explicitly added to the files rule
thrown.expect(AbortException)
thrown.expectMessage('Configured deploy config file \'my-deploy.yaml\' does not exists.')
new ChangeManagement(nullScript).uploadFileToTransportRequestCTS(
[
image: 'node',
pullImage: true
],
'002',
'https://example.org/cm',
'001',
'myApp',
'the description',
'aPackage',
'node2',
['@ui5/cli', '@sap/ux-ui5-tooling', '@ui5/logger', '@ui5/fs', '@dummy/foo'],
['--verbose'],
'my-deploy.yaml',
'me',
)
// more details already checked with test "testUploadFileToTransportSucceedsCTSDeployConfigYamlExists"
assert script.shell[0].contains("fiori deploy --noConfig -t 002 -u https://example.org/cm")
}
@Test
public void testUploadFileToTransportSucceesCTSExplicitlyConfiguredDeployConfigYamExists() {
files.existingFiles.add('my-deploy.yaml')
new ChangeManagement(nullScript).uploadFileToTransportRequestCTS(
[
image: 'node',
pullImage: true
],
'002',
'https://example.org/cm',
'001',
'myApp',
'the description',
'aPackage',
'node2',
['@ui5/cli', '@sap/ux-ui5-tooling', '@ui5/logger', '@ui5/fs', '@dummy/foo'],
['--verbose'],
'my-deploy.yaml',
'me',
)
// more details already checked with test "testUploadFileToTransportSucceedsCTSDeployConfigYamlExists"
assert script.shell[0].contains("fiori deploy -c \"my-deploy.yaml\" -t 002 -u https://example.org/cm")
}
@Test
public void testUploadFileToTransportSucceedsEmptyDeployToolDependenciesCTS() {
new ChangeManagement(nullScript).uploadFileToTransportRequestCTS(
[
image: 'fioriDeployImage',
pullImage: true
],
'002',
'https://example.org/cm',
'001',
'myApp',
'aPackage',
'the description',
'node2',
[],
[],
'ui5-deploy.yaml',
'me',
)
assert ! script.shell[0].contains('npm install')
assert ! script.shell[0].contains('su')
assert script.shell[0].contains("fiori deploy")
assert dockerExecuteRule.getDockerParams().dockerImage == 'fioriDeployImage'
assert dockerExecuteRule.getDockerParams().dockerPullImage == true
assert dockerExecuteRule.getDockerParams().dockerEnvVars == [ABAP_USER: "user", ABAP_PASSWORD: 'password']
// we don't start with the root user since there is no need to install something (globally)
assert dockerExecuteRule.getDockerParams().dockerOptions == []
}
@Test
public void testUploadFileToTransportShellFailsCTS() {
thrown.expect(AbortException)
thrown.expectMessage('script returned exit code 1')
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*fiori deploy.*',
{ throw new AbortException('script returned exit code 1') })
new ChangeManagement(nullScript).uploadFileToTransportRequestCTS(
[
image: 'node',
pullImage: true
],
'002',
'https://example.org/cm',
'001',
'myApp',
'aPackage',
'the description',
'node',
'@ui5/cli @sap/ux-ui5-tooling @ui5/logger @ui5/fs',
[],
'ui5-deploy.yaml',
'me',
)
}
@Test

View File

@ -74,16 +74,61 @@ import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrati
* A pattern used for identifying lines holding the transport request id.
* @parentConfigKey changeManagement
*/
'changeManagement/transportRequestLabel'
'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 provide 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([
'applicationName', // RFC
/** 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.*/
'filePath', // SOLMAN, CTS
/** 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. */
@ -133,11 +178,12 @@ void call(Map parameters = [:]) {
.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 in [BackendType.SOLMAN, BackendType.CTS] })
.withMandatoryProperty('filePath', null, { backendType == BackendType.SOLMAN })
.withMandatoryProperty('applicationUrl', null, { backendType == BackendType.RFC })
.withMandatoryProperty('codePage', null, { backendType == BackendType.RFC })
.withMandatoryProperty('acceptUnixStyleLineEndings', null, { backendType == BackendType.RFC })
@ -148,9 +194,9 @@ void call(Map parameters = [:]) {
.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('abapPackage', null, { backendType in [BackendType.RFC, BackendType.CTS] })
.withMandatoryProperty('applicationId', null, {backendType == BackendType.SOLMAN})
.withMandatoryProperty('applicationName', null, {backendType == BackendType.RFC})
.withMandatoryProperty('applicationName', null, {backendType in [BackendType.RFC, BackendType.CTS]})
.withMandatoryProperty('failOnWarning', null, {backendType == BackendType.RFC})
.withMandatoryProperty('verbose', null, {backendType == BackendType.RFC})
@ -184,20 +230,15 @@ void call(Map parameters = [:]) {
"Transport request id not provided (parameter: \'transportRequestId\' provided to the step call or via commit history).")
.use()
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 << '.'
echo uploadingMessage.join()
try {
switch(backendType) {
case BackendType.SOLMAN:
echo "[INFO] Uploading file '${configuration.filePath}' to transport request '${configuration.transportRequestId}'" +
" of change document '${configuration.changeDocumentId}'."
cm.uploadFileToTransportRequestSOLMAN(
configuration.changeManagement.solman?.docker ?: [:],
configuration.changeDocumentId,
@ -207,18 +248,36 @@ void call(Map parameters = [:]) {
configuration.changeManagement.endpoint,
configuration.changeManagement.credentialsId,
configuration.changeManagement.clientOpts)
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}'."
cm.uploadFileToTransportRequestCTS(
configuration.changeManagement.cts?.docker ?: [:],
configuration.changeManagement.cts?.nodeDocker ?: [:],
configuration.transportRequestId,
configuration.filePath,
configuration.changeManagement.endpoint,
configuration.changeManagement.credentialsId,
configuration.changeManagement.clientOpts)
configuration.changeManagement.client,
configuration.applicationName,
configuration.applicationDescription,
configuration.abapPackage,
configuration.changeManagement.cts.osDeployUser,
configuration.changeManagement.cts.deployToolDependencies,
configuration.changeManagement.cts.npmInstallOpts,
configuration.changeManagement.cts.deployConfigFile,
configuration.changeManagement.credentialsId)
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}'."
cm.uploadFileToTransportRequestRFC(
configuration.changeManagement.rfc.docker ?: [:],
configuration.transportRequestId,
@ -236,19 +295,13 @@ void call(Map parameters = [:]) {
configuration.verbose
)
break
echo "[INFO] File 'configuration.applicationUrl' has been successfully uploaded to transport request '${configuration.transportRequestId}'."
break
}
} catch(ChangeManagementException ex) {
throw new AbortException(ex.getMessage())
}
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 << '.'
echo uploadedMessage.join()
}
}