mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-04-13 11:50:43 +02:00
TMS integration (#782)
This commit is contained in:
parent
338314b08a
commit
cb245b1ce2
9
documentation/docs/steps/tmsUpload.md
Normal file
9
documentation/docs/steps/tmsUpload.md
Normal file
@ -0,0 +1,9 @@
|
||||
# ${docGenStepName}
|
||||
|
||||
## ${docGenDescription}
|
||||
|
||||
## ${docGenParameters}
|
||||
|
||||
## ${docGenConfiguration}
|
||||
|
||||
## ${docJenkinsPluginDependencies}
|
@ -535,6 +535,10 @@ steps:
|
||||
active: false
|
||||
checkChangeInDevelopment:
|
||||
failIfStatusIsNotInDevelopment: true
|
||||
tmsUpload:
|
||||
namedUser: 'Piper-Pipeline'
|
||||
stashContent:
|
||||
- 'buildResult'
|
||||
transportRequestCreate:
|
||||
developmentSystemId: null
|
||||
verbose: false
|
||||
|
@ -104,3 +104,7 @@ String getIssueCommentTriggerAction() {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
def getJobStartedByUserId() {
|
||||
return getRawBuild().getCause(hudson.model.Cause.UserIdCause.class)?.getUserId()
|
||||
}
|
||||
|
137
src/com/sap/piper/integration/TransportManagementService.groovy
Normal file
137
src/com/sap/piper/integration/TransportManagementService.groovy
Normal file
@ -0,0 +1,137 @@
|
||||
package com.sap.piper.integration
|
||||
|
||||
import com.sap.piper.JsonUtils
|
||||
|
||||
class TransportManagementService implements Serializable {
|
||||
|
||||
final Script script
|
||||
final Map config
|
||||
|
||||
def jsonUtils = new JsonUtils()
|
||||
|
||||
TransportManagementService(Script script, Map config) {
|
||||
this.script = script
|
||||
this.config = config
|
||||
}
|
||||
|
||||
def authentication(String uaaUrl, String oauthClientId, String oauthClientSecret) {
|
||||
echo("OAuth Token retrieval started.")
|
||||
|
||||
if (config.verbose) {
|
||||
echo("UAA-URL: '${uaaUrl}', ClientId: '${oauthClientId}''")
|
||||
}
|
||||
|
||||
def encodedUsernameColonPassword = "${oauthClientId}:${oauthClientSecret}".bytes.encodeBase64().toString()
|
||||
def urlEncodedFormData = "grant_type=password&" +
|
||||
"username=${urlEncodeAndReplaceSpace(oauthClientId)}&" +
|
||||
"password=${urlEncodeAndReplaceSpace(oauthClientSecret)}"
|
||||
|
||||
def parameters = [
|
||||
url : "${uaaUrl}/oauth/token/?grant_type=client_credentials&response_type=token",
|
||||
httpMode : "POST",
|
||||
requestBody : urlEncodedFormData,
|
||||
customHeaders: [
|
||||
[
|
||||
maskValue: false,
|
||||
name : 'Content-Type',
|
||||
value : 'application/x-www-form-urlencoded'
|
||||
],
|
||||
[
|
||||
maskValue: true,
|
||||
name : 'authorization',
|
||||
value : "Basic ${encodedUsernameColonPassword}"
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
def response = sendApiRequest(parameters)
|
||||
echo("OAuth Token retrieved successfully.")
|
||||
|
||||
return jsonUtils.jsonStringToGroovyObject(response).access_token
|
||||
|
||||
}
|
||||
|
||||
|
||||
def uploadFile(String url, String token, String file, String namedUser) {
|
||||
|
||||
echo("File upload started.")
|
||||
|
||||
if (config.verbose) {
|
||||
echo("URL: '${url}', File: '${file}'")
|
||||
}
|
||||
|
||||
script.sh """#!/bin/sh -e
|
||||
curl -H 'Authorization: Bearer ${token}' -F 'file=@${file}' -F 'namedUser=${namedUser}' -o responseFileUpload.txt --fail '${url}/v2/files/upload'
|
||||
"""
|
||||
|
||||
def responseContent = script.readFile("responseFileUpload.txt")
|
||||
|
||||
if (config.verbose) {
|
||||
echo("${responseContent}")
|
||||
}
|
||||
|
||||
echo("File upload successful.")
|
||||
|
||||
return jsonUtils.jsonStringToGroovyObject(responseContent)
|
||||
|
||||
}
|
||||
|
||||
|
||||
def uploadFileToNode(String url, String token, String nodeName, int fileId, String description, String namedUser) {
|
||||
|
||||
echo("Node upload started.")
|
||||
|
||||
if (config.verbose) {
|
||||
echo("URL: '${url}', NodeName: '${nodeName}', FileId: '${fileId}''")
|
||||
}
|
||||
|
||||
def bodyMap = [nodeName: nodeName, contentType: 'MTA', description: description, storageType: 'FILE', namedUser: namedUser, entries: [[uri: fileId]]]
|
||||
|
||||
def parameters = [
|
||||
url : "${url}/v2/nodes/upload",
|
||||
httpMode : "POST",
|
||||
contentType : 'APPLICATION_JSON',
|
||||
requestBody : jsonUtils.groovyObjectToPrettyJsonString(bodyMap),
|
||||
customHeaders: [
|
||||
[
|
||||
maskValue: true,
|
||||
name : 'authorization',
|
||||
value : "Bearer ${token}"
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
def response = sendApiRequest(parameters)
|
||||
echo("Node upload successful.")
|
||||
|
||||
return jsonUtils.jsonStringToGroovyObject(response)
|
||||
|
||||
}
|
||||
|
||||
private sendApiRequest(parameters) {
|
||||
def defaultParameters = [
|
||||
acceptType : 'APPLICATION_JSON',
|
||||
quiet : !config.verbose,
|
||||
consoleLogResponseBody: !config.verbose,
|
||||
ignoreSslErrors : true,
|
||||
validResponseCodes : "100:399"
|
||||
]
|
||||
|
||||
def response = script.httpRequest(defaultParameters + parameters)
|
||||
|
||||
if (config.verbose) {
|
||||
echo("Received response '${response.content}' with status ${response.status}.")
|
||||
}
|
||||
|
||||
return response.content
|
||||
}
|
||||
|
||||
private echo(message) {
|
||||
script.echo "[${getClass().getSimpleName()}] ${message}"
|
||||
}
|
||||
|
||||
private static String urlEncodeAndReplaceSpace(String data) {
|
||||
return URLEncoder.encode(data, "UTF-8").replace('%20', '+')
|
||||
}
|
||||
|
||||
}
|
182
test/groovy/TmsUploadTest.groovy
Normal file
182
test/groovy/TmsUploadTest.groovy
Normal file
@ -0,0 +1,182 @@
|
||||
import com.sap.piper.JenkinsUtils
|
||||
import com.sap.piper.integration.TransportManagementService
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.Matchers.containsString
|
||||
import static org.hamcrest.Matchers.is
|
||||
import static org.hamcrest.Matchers.not
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
public class TmsUploadTest extends BasePiperTest {
|
||||
|
||||
private ExpectedException thrown = new ExpectedException()
|
||||
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
|
||||
private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this)
|
||||
private JenkinsEnvironmentRule envRule = new JenkinsEnvironmentRule(this)
|
||||
|
||||
def tmsStub
|
||||
def jenkinsUtilsStub
|
||||
def calledTmsMethodsWithArgs = []
|
||||
def uri = "https://dummy-url.com"
|
||||
def uaaUrl = "https://oauth.com"
|
||||
def oauthClientId = "myClientId"
|
||||
def oauthClientSecret = "myClientSecret"
|
||||
def serviceKeyContent = """{
|
||||
"uri": "${uri}",
|
||||
"uaa": {
|
||||
"clientid": "${oauthClientId}",
|
||||
"clientsecret": "${oauthClientSecret}",
|
||||
"url": "${uaaUrl}"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
class JenkinsUtilsMock extends JenkinsUtils {
|
||||
def userId
|
||||
|
||||
JenkinsUtilsMock(userId) {
|
||||
this.userId = userId
|
||||
}
|
||||
|
||||
def getJobStartedByUserId(){
|
||||
return this.userId
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
public RuleChain ruleChain = Rules.getCommonRules(this)
|
||||
.around(thrown)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(stepRule)
|
||||
.around(loggingRule)
|
||||
.around(envRule)
|
||||
.around(new JenkinsCredentialsRule(this)
|
||||
.withCredentials('TMS_ServiceKey', serviceKeyContent))
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
tmsStub = mockTransportManagementService()
|
||||
helper.registerAllowedMethod("unstash", [String.class], { s -> return [s] })
|
||||
}
|
||||
|
||||
@After
|
||||
void tearDown() {
|
||||
calledTmsMethodsWithArgs.clear()
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minimalConfig__isSuccessful() {
|
||||
jenkinsUtilsStub = new JenkinsUtilsMock("Test User")
|
||||
binding.workspace = "."
|
||||
envRule.env.gitCommitId = "testCommitId"
|
||||
|
||||
stepRule.step.tmsUpload(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
jenkinsUtilsStub: jenkinsUtilsStub,
|
||||
transportManagementService: tmsStub,
|
||||
mtaPath: 'dummy.mtar',
|
||||
nodeName: 'myNode',
|
||||
credentialsId: 'TMS_ServiceKey'
|
||||
)
|
||||
|
||||
assertThat(calledTmsMethodsWithArgs[0], is("authentication('${uaaUrl}', '${oauthClientId}', '${oauthClientSecret}')"))
|
||||
assertThat(calledTmsMethodsWithArgs[1], is("uploadFile('${uri}', 'myToken', './dummy.mtar', 'Test User')"))
|
||||
assertThat(calledTmsMethodsWithArgs[2], is("uploadFileToNode('${uri}', 'myToken', 'myNode', '1234', 'Git CommitId: testCommitId')"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] File './dummy.mtar' successfully uploaded to Node 'myNode' (Id: '1000')."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Corresponding Transport Request: 'Git CommitId: testCommitId' (Id: '2000')"))
|
||||
assertThat(loggingRule.log, not(containsString("[TransportManagementService] CredentialsId: 'TMS_ServiceKey'")))
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verboseMode__yieldsMoreEchos() {
|
||||
jenkinsUtilsStub = new JenkinsUtilsMock("Test User")
|
||||
binding.workspace = "."
|
||||
envRule.env.gitCommitId = "testCommitId"
|
||||
|
||||
stepRule.step.tmsUpload(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
jenkinsUtilsStub: jenkinsUtilsStub,
|
||||
transportManagementService: tmsStub,
|
||||
mtaPath: 'dummy.mtar',
|
||||
nodeName: 'myNode',
|
||||
credentialsId: 'TMS_ServiceKey',
|
||||
verbose: true
|
||||
)
|
||||
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] CredentialsId: 'TMS_ServiceKey'"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Node name: 'myNode'"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] MTA path: 'dummy.mtar'"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Named user: 'Test User'"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] UAA URL: '${uaaUrl}'"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] TMS URL: '${uri}'"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] ClientId: '${oauthClientId}'"))
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noUserAvailableInCurrentBuild__usesDefaultUser() {
|
||||
jenkinsUtilsStub = new JenkinsUtilsMock(null)
|
||||
binding.workspace = "."
|
||||
envRule.env.gitCommitId = "testCommitId"
|
||||
|
||||
stepRule.step.tmsUpload(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
jenkinsUtilsStub: jenkinsUtilsStub,
|
||||
transportManagementService: tmsStub,
|
||||
mtaPath: 'dummy.mtar',
|
||||
nodeName: 'myNode',
|
||||
credentialsId: 'TMS_ServiceKey'
|
||||
)
|
||||
|
||||
assertThat(calledTmsMethodsWithArgs[1], is("uploadFile('${uri}', 'myToken', './dummy.mtar', 'Piper-Pipeline')"))
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addCustomDescription__descriptionChanged() {
|
||||
jenkinsUtilsStub = new JenkinsUtilsMock("Test User")
|
||||
binding.workspace = "."
|
||||
envRule.env.gitCommitId = "testCommitId"
|
||||
|
||||
stepRule.step.tmsUpload(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
jenkinsUtilsStub: jenkinsUtilsStub,
|
||||
transportManagementService: tmsStub,
|
||||
mtaPath: 'dummy.mtar',
|
||||
nodeName: 'myNode',
|
||||
credentialsId: 'TMS_ServiceKey',
|
||||
customDescription: 'My custom description for testing.'
|
||||
)
|
||||
|
||||
assertThat(calledTmsMethodsWithArgs[2], is("uploadFileToNode('${uri}', 'myToken', 'myNode', '1234', 'My custom description for testing.')"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Corresponding Transport Request: 'My custom description for testing.' (Id: '2000')"))
|
||||
}
|
||||
|
||||
def mockTransportManagementService() {
|
||||
return new TransportManagementService(nullScript, [:]) {
|
||||
def authentication(String uaaUrl, String oauthClientId, String oauthClientSecret) {
|
||||
calledTmsMethodsWithArgs << "authentication('${uaaUrl}', '${oauthClientId}', '${oauthClientSecret}')"
|
||||
return "myToken"
|
||||
}
|
||||
|
||||
def uploadFile(String url, String token, String file, String namedUser) {
|
||||
calledTmsMethodsWithArgs << "uploadFile('${url}', '${token}', '${file}', '${namedUser}')"
|
||||
return [fileId: 1234, fileName: file]
|
||||
}
|
||||
|
||||
def uploadFileToNode(String url, String token, String nodeName, int fileId, String description, String namedUser) {
|
||||
calledTmsMethodsWithArgs << "uploadFileToNode('${url}', '${token}', '${nodeName}', '${fileId}', '${description}')"
|
||||
return [transportRequestDescription: description, transportRequestId: 2000, queueEntries: [nodeName: 'myNode', nodeId: 1000]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ import org.jenkinsci.plugins.workflow.steps.MissingContextVariableException
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.BasePiperTest
|
||||
import util.JenkinsLoggingRule
|
||||
@ -33,6 +32,8 @@ class JenkinsUtilsTest extends BasePiperTest {
|
||||
|
||||
Map triggerCause
|
||||
|
||||
String userId
|
||||
|
||||
|
||||
@Before
|
||||
void init() throws Exception {
|
||||
@ -60,7 +61,15 @@ class JenkinsUtilsTest extends BasePiperTest {
|
||||
return parentMock
|
||||
}
|
||||
def getCause(type) {
|
||||
return triggerCause
|
||||
if (type == hudson.model.Cause.UserIdCause.class){
|
||||
def userIdCause = new hudson.model.Cause.UserIdCause()
|
||||
userIdCause.metaClass.getUserId = {
|
||||
return userId
|
||||
}
|
||||
return userIdCause
|
||||
} else {
|
||||
return triggerCause
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -109,4 +118,16 @@ class JenkinsUtilsTest extends BasePiperTest {
|
||||
]
|
||||
assertThat(jenkinsUtils.getIssueCommentTriggerAction(), isEmptyOrNullString())
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserId() {
|
||||
userId = 'Test User'
|
||||
assertThat(jenkinsUtils.getJobStartedByUserId(), is('Test User'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserIdNoUser() {
|
||||
userId = null
|
||||
assertThat(jenkinsUtils.getJobStartedByUserId(), isEmptyOrNullString())
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,181 @@
|
||||
package com.sap.piper.integration
|
||||
|
||||
import hudson.AbortException
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.Ignore
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class TransportManagementServiceTest extends BasePiperTest {
|
||||
private ExpectedException thrown = ExpectedException.none()
|
||||
private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this)
|
||||
private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this)
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(new JenkinsErrorRule(this))
|
||||
.around(new JenkinsReadJsonRule(this))
|
||||
.around(shellRule)
|
||||
.around(loggingRule)
|
||||
.around(new JenkinsReadFileRule(this, 'test/resources/TransportManagementService'))
|
||||
.around(thrown)
|
||||
|
||||
@Test
|
||||
void retrieveOAuthToken__successfully() {
|
||||
Map requestParams
|
||||
helper.registerAllowedMethod('httpRequest', [Map.class], { m ->
|
||||
requestParams = m
|
||||
return [content: '{ "access_token": "myOAuthToken" }']
|
||||
})
|
||||
|
||||
def uaaUrl = 'http://dummy.com/oauth'
|
||||
def clientId = 'myId'
|
||||
def clientSecret = 'mySecret'
|
||||
|
||||
def tms = new TransportManagementService(nullScript, [:])
|
||||
def token = tms.authentication(uaaUrl, clientId, clientSecret)
|
||||
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] OAuth Token retrieval started."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] OAuth Token retrieved successfully."))
|
||||
assertThat(token, is('myOAuthToken'))
|
||||
assertThat(requestParams, hasEntry('url', "${uaaUrl}/oauth/token/?grant_type=client_credentials&response_type=token"))
|
||||
assertThat(requestParams, hasEntry('requestBody', "grant_type=password&username=${clientId}&password=${clientSecret}".toString()))
|
||||
assertThat(requestParams.customHeaders[1].value, is("Basic ${"${clientId}:${clientSecret}".bytes.encodeBase64()}"))
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrieveOAuthToken__inVerboseMode__yieldsMoreEchos() {
|
||||
Map requestParams
|
||||
helper.registerAllowedMethod('httpRequest', [Map.class], { m ->
|
||||
requestParams = m
|
||||
return [content: '{ "access_token": "myOAuthToken" }', status: 200]
|
||||
})
|
||||
|
||||
def uaaUrl = 'http://dummy.com/oauth'
|
||||
def clientId = 'myId'
|
||||
def clientSecret = 'mySecret'
|
||||
|
||||
def tms = new TransportManagementService(nullScript, [verbose: true])
|
||||
tms.authentication(uaaUrl, clientId, clientSecret)
|
||||
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] OAuth Token retrieval started."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] UAA-URL: '${uaaUrl}', ClientId: '${clientId}'"))
|
||||
assertThat(loggingRule.log, containsString("Received response '{ \"access_token\": \"myOAuthToken\" }' with status 200."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] OAuth Token retrieved successfully."))
|
||||
}
|
||||
|
||||
@Test
|
||||
void uploadFile__successfully() {
|
||||
|
||||
def url = 'http://dummy.com/oauth'
|
||||
def token = 'myToken'
|
||||
def file = 'myFile.mtar'
|
||||
def namedUser = 'myUser'
|
||||
|
||||
def tms = new TransportManagementService(nullScript, [:])
|
||||
def responseDetails = tms.uploadFile(url, token, file, namedUser)
|
||||
|
||||
def oAuthShellCall = shellRule.shell[0]
|
||||
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] File upload started."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] File upload successful."))
|
||||
assertThat(oAuthShellCall, startsWith("#!/bin/sh -e "))
|
||||
assertThat(oAuthShellCall, endsWith("curl -H 'Authorization: Bearer ${token}' -F 'file=@${file}' -F 'namedUser=${namedUser}' -o responseFileUpload.txt --fail '${url}/v2/files/upload'"))
|
||||
assertThat(responseDetails, hasEntry("fileId", 1234))
|
||||
}
|
||||
|
||||
@Ignore
|
||||
void uploadFile__withHttpErrorResponse__throwsError() {
|
||||
|
||||
def url = 'http://dummy.com/oauth'
|
||||
def token = 'myWrongToken'
|
||||
def file = 'myFile.mtar'
|
||||
def namedUser = 'myUser'
|
||||
|
||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, ".* curl .*", {throw new AbortException()})
|
||||
|
||||
thrown.expect(AbortException.class)
|
||||
|
||||
def tms = new TransportManagementService(nullScript, [:])
|
||||
tms.uploadFile(url, token, file, namedUser)
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void uploadFile__inVerboseMode__yieldsMoreEchos() {
|
||||
|
||||
def url = 'http://dummy.com/oauth'
|
||||
def token = 'myToken'
|
||||
def file = 'myFile.mtar'
|
||||
def namedUser = 'myUser'
|
||||
|
||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, ".* curl .*", '200')
|
||||
|
||||
def tms = new TransportManagementService(nullScript, [verbose: true])
|
||||
tms.uploadFile(url, token, file, namedUser)
|
||||
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] File upload started."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] URL: '${url}', File: '${file}'"))
|
||||
assertThat(loggingRule.log, containsString("\"fileId\": 1234"))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] File upload successful."))
|
||||
}
|
||||
|
||||
@Test
|
||||
void uploadFileToNode__successfully() {
|
||||
Map requestParams
|
||||
helper.registerAllowedMethod('httpRequest', [Map.class], { m ->
|
||||
requestParams = m
|
||||
return [content: '{ "upload": "success" }']
|
||||
})
|
||||
|
||||
def url = 'http://dummy.com/oauth'
|
||||
def token = 'myToken'
|
||||
def nodeName = 'myNode'
|
||||
def fileId = 1234
|
||||
def description = "My description."
|
||||
def namedUser = 'myUser'
|
||||
|
||||
def tms = new TransportManagementService(nullScript, [:])
|
||||
def responseDetails = tms.uploadFileToNode(url, token, nodeName, fileId, description, namedUser)
|
||||
|
||||
def bodyRegEx = /^\{\s+"nodeName":\s+"myNode",\s+"contentType":\s+"MTA",\s+"description":\s+"My\s+description.",\s+"storageType":\s+"FILE",\s+"namedUser":\s+"myUser",\s+"entries":\s+\[\s+\{\s+"uri":\s+1234\s+}\s+]\s+}$/
|
||||
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Node upload started."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Node upload successful."))
|
||||
assertThat(requestParams, hasEntry('url', "${url}/v2/nodes/upload"))
|
||||
assert requestParams.requestBody ==~ bodyRegEx
|
||||
assertThat(requestParams.customHeaders[0].value, is("Bearer ${token}"))
|
||||
assertThat(responseDetails, hasEntry("upload", "success"))
|
||||
}
|
||||
|
||||
@Test
|
||||
void uploadFileToNode__inVerboseMode__yieldsMoreEchos() {
|
||||
Map requestParams
|
||||
helper.registerAllowedMethod('httpRequest', [Map.class], { m ->
|
||||
requestParams = m
|
||||
return [content: '{ "upload": "success" }']
|
||||
})
|
||||
|
||||
def url = 'http://dummy.com/oauth'
|
||||
def token = 'myToken'
|
||||
def nodeName = 'myNode'
|
||||
def fileId = 1234
|
||||
def description = "My description."
|
||||
def namedUser = 'myUser'
|
||||
|
||||
def tms = new TransportManagementService(nullScript, [verbose: true])
|
||||
tms.uploadFileToNode(url, token, nodeName, fileId, description, namedUser)
|
||||
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Node upload started."))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] URL: '${url}', NodeName: '${nodeName}', FileId: '${fileId}'"))
|
||||
assertThat(loggingRule.log, containsString("\"upload\": \"success\""))
|
||||
assertThat(loggingRule.log, containsString("[TransportManagementService] Node upload successful."))
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"access_token": "myOAuthToken"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"fileId": 1234
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"upload": "success"
|
||||
}
|
@ -15,6 +15,8 @@ import static com.sap.piper.Prerequisites.checkScript
|
||||
'healthExecuteCheck',
|
||||
/** For Neo use-cases: Performs deployment to Neo landscape. */
|
||||
'neoDeploy',
|
||||
/** For TMS use-cases: Performs upload to Transport Management Service node*/
|
||||
'tmsUpload',
|
||||
/** Publishes release information to GitHub. */
|
||||
'githubPublishRelease',
|
||||
]
|
||||
@ -60,6 +62,12 @@ void call(Map parameters = [:]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (config.tmsUpload) {
|
||||
durationMeasure(script: script, measurementName: 'upload_release_tms_duration') {
|
||||
tmsUpload script: script
|
||||
}
|
||||
}
|
||||
|
||||
if (config.healthExecuteCheck) {
|
||||
healthExecuteCheck script: script
|
||||
}
|
||||
|
131
vars/tmsUpload.groovy
Normal file
131
vars/tmsUpload.groovy
Normal file
@ -0,0 +1,131 @@
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.GenerateDocumentation
|
||||
import com.sap.piper.JenkinsUtils
|
||||
import com.sap.piper.JsonUtils
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.integration.TransportManagementService
|
||||
import groovy.transform.Field
|
||||
|
||||
import static com.sap.piper.Prerequisites.checkScript
|
||||
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = [
|
||||
/**
|
||||
* Print more detailed information into the log.
|
||||
* @possibleValues `true`, `false`
|
||||
*/
|
||||
'verbose'
|
||||
]
|
||||
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
|
||||
/**
|
||||
* If specific stashes should be considered, their names need to be passed via the parameter `stashContent`.
|
||||
*/
|
||||
'stashContent',
|
||||
/**
|
||||
* Defines the path to *.mtar for the upload to the Transport Management Service.
|
||||
*/
|
||||
'mtaPath',
|
||||
/**
|
||||
* Defines the name of the node to which the *.mtar file should be uploaded.
|
||||
*/
|
||||
'nodeName',
|
||||
/**
|
||||
* Credentials to be used for the file and node uploads to the Transport Management Service.
|
||||
*/
|
||||
'credentialsId',
|
||||
/**
|
||||
* Can be used as the description of a transport request. Will overwrite the default. (Default: Corresponding Git Commit-ID)
|
||||
*/
|
||||
'customDescription'
|
||||
])
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
/**
|
||||
* This step allows you to upload an MTA file (multi-target application archive) into a TMS (SAP Cloud Platform Transport Management Service) landscape for further TMS-controlled distribution through a TMS-configured landscape.
|
||||
* TMS lets you manage transports between SAP Cloud Platform accounts in Neo and Cloud Foundry, such as from DEV to TEST and PROD accounts.
|
||||
* For more information, see [official documentation of Transport Management Service](https://help.sap.com/viewer/p/TRANSPORT_MANAGEMENT_SERVICE)
|
||||
*
|
||||
* !!! note "Prerequisites"
|
||||
* * You have subscribed to and set up TMS, as described in [Setup and Configuration of SAP Cloud Platform Transport Management](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/66fd7283c62f48adb23c56fb48c84a60.html), which includes the configuration of a node to be used for uploading an MTA file.
|
||||
* * A corresponding service key has been created, as described in [Set Up the Environment to Transport Content Archives directly in an Application](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/8d9490792ed14f1bbf8a6ac08a6bca64.html). This service key (JSON) must be stored as a secret text within the Jenkins secure store.
|
||||
*
|
||||
*/
|
||||
@GenerateDocumentation
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
def script = checkScript(this, parameters) ?: this
|
||||
def utils = parameters.juStabUtils ?: new Utils()
|
||||
def jenkinsUtils = parameters.jenkinsUtilsStub ?: new JenkinsUtils()
|
||||
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName ?: env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
//mandatory parameters
|
||||
.withMandatoryProperty('mtaPath')
|
||||
.withMandatoryProperty('nodeName')
|
||||
.withMandatoryProperty('credentialsId')
|
||||
.use()
|
||||
|
||||
// telemetry reporting
|
||||
new Utils().pushToSWA([
|
||||
step : STEP_NAME,
|
||||
stepParamKey1: 'scriptMissing',
|
||||
stepParam1 : parameters?.script == null
|
||||
], config)
|
||||
|
||||
def jsonUtilsObject = new JsonUtils()
|
||||
|
||||
// make sure that all relevant descriptors, are available in workspace
|
||||
utils.unstashAll(config.stashContent)
|
||||
// make sure that for further execution whole workspace, e.g. also downloaded artifacts are considered
|
||||
config.stashContent = []
|
||||
|
||||
def customDescription = config.customDescription ? "${config.customDescription}" : "Git CommitId: ${script.commonPipelineEnvironment.getGitCommitId()}"
|
||||
def description = customDescription
|
||||
|
||||
def namedUser = jenkinsUtils.getJobStartedByUserId() ?: config.namedUser
|
||||
|
||||
def nodeName = config.nodeName
|
||||
def mtaPath = config.mtaPath
|
||||
|
||||
if (config.verbose) {
|
||||
echo "[TransportManagementService] CredentialsId: '${config.credentialsId}'"
|
||||
echo "[TransportManagementService] Node name: '${nodeName}'"
|
||||
echo "[TransportManagementService] MTA path: '${mtaPath}'"
|
||||
echo "[TransportManagementService] Named user: '${namedUser}'"
|
||||
}
|
||||
|
||||
def tms = parameters.transportManagementService ?: new TransportManagementService(script, config)
|
||||
|
||||
withCredentials([string(credentialsId: config.credentialsId, variable: 'tmsServiceKeyJSON')]) {
|
||||
|
||||
def tmsServiceKey = jsonUtilsObject.jsonStringToGroovyObject(tmsServiceKeyJSON)
|
||||
|
||||
def clientId = tmsServiceKey.uaa.clientid
|
||||
def clientSecret = tmsServiceKey.uaa.clientsecret
|
||||
def uaaUrl = tmsServiceKey.uaa.url
|
||||
def uri = tmsServiceKey.uri
|
||||
|
||||
if (config.verbose) {
|
||||
echo "[TransportManagementService] UAA URL: '${uaaUrl}'"
|
||||
echo "[TransportManagementService] TMS URL: '${uri}'"
|
||||
echo "[TransportManagementService] ClientId: '${clientId}'"
|
||||
}
|
||||
|
||||
def token = tms.authentication(uaaUrl, clientId, clientSecret)
|
||||
def fileUploadResponse = tms.uploadFile(uri, token, "${workspace}/${mtaPath}", namedUser)
|
||||
def uploadFileToNodeResponse = tms.uploadFileToNode(uri, token, nodeName, fileUploadResponse.fileId, description, namedUser)
|
||||
|
||||
echo "[TransportManagementService] File '${fileUploadResponse.fileName}' successfully uploaded to Node '${uploadFileToNodeResponse.queueEntries.nodeName}' (Id: '${uploadFileToNodeResponse.queueEntries.nodeId}')."
|
||||
echo "[TransportManagementService] Corresponding Transport Request: '${uploadFileToNodeResponse.transportRequestDescription}' (Id: '${uploadFileToNodeResponse.transportRequestId}')"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user