From 79475732f959fddffff85dc48e23244b26b160ba Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Fri, 21 Feb 2020 16:16:15 +0100 Subject: [PATCH] Upload to transport request scenario (#855) Co-authored-by: Christoph Szymanski Co-authored-by: SarahNoack <44202907+SarahNoack@users.noreply.github.com> --- .../upload-to-transportrequest/Readme.md | 198 ++++++++++++++++++ .../upload-to-transportrequest/files/mta.yaml | 17 ++ .../images/pipeline.png | Bin 0 -> 22455 bytes documentation/mkdocs.yml | 1 + 4 files changed, 216 insertions(+) create mode 100644 documentation/docs/scenarios/upload-to-transportrequest/Readme.md create mode 100644 documentation/docs/scenarios/upload-to-transportrequest/files/mta.yaml create mode 100644 documentation/docs/scenarios/upload-to-transportrequest/images/pipeline.png diff --git a/documentation/docs/scenarios/upload-to-transportrequest/Readme.md b/documentation/docs/scenarios/upload-to-transportrequest/Readme.md new file mode 100644 index 000000000..75901e46b --- /dev/null +++ b/documentation/docs/scenarios/upload-to-transportrequest/Readme.md @@ -0,0 +1,198 @@ +# Build an SAP Fiori Application and Attach It to a Transport Request on an ABAP System with Jenkins + +Build an application based on SAPUI5 or SAP Fiori with Jenkins and attach the build result to a transport request in an SAP ABAP system. + +Generally, you can choose between two technical ways to attach a binary to an ABAP transport request: We support uploads through RFC and through OData. Which option to use depends on the version of your ABAP system. For AS ABAP 7.50 SP08, 7.51 SP07, or 7.52 SP03 and newer, use the OData-based upload, for older versions, use the RFC-based upload. + +## Prerequisites + +* You have set up your [Docker environment](https://docs.docker.com/get-started/). +* You have set up project “Piper”. See [guided tour](../../../guidedtour/). +* You have a transport request. In General it is possible to create a transport request on the fly. But the example here is based on an already existing transport request. +* Depending on the version of the ABAP system: Docker image for attaching binaries to transport requests via RFC available. Due to legal reasons there is no pre-build docker image. How to create the docker image is explained [here](https://github.com/SAP/devops-docker-images/tree/master/node-rfc) + +### Project Prerequisites + +This scenario requires additional files in your project and in the execution environment on your Jenkins instance. + +On the project level, provide and adjust the following template: + +| File Name | Description | Position | +|-----|-----|-----| +| [`mta.yaml`](https://github.com/SAP/jenkins-library/blob/master/documentation/docs/scenarios/rfc-upload/files/mta.yaml) | This file controls the behavior of the MTA toolset. | Place the `mta.yaml` file in your application root folder and adjust the values in brackets with your data. | + +Depending on the modules in your MTA, additional configuration files are required, e.g. `pom.xml` or `package.json`. + +## Context + +This scenario combines various different steps to create a complete pipeline. + +In this scenario, we want to show how to build an application based on SAPUI5 or SAP Fiori by using the multitarget application (MTA) concept and how to attach the build result to a transport request inside an ABAP system. This document comprises the [mtaBuild](../../../steps/mtaBuild/) and the [transportRequestUploadFile](../../../steps/transportRequestUploadFile/) steps. + +In case of an RFC based upload the binary is not streamed to the ABAP endpoint. Instead an URL pointing to the binary needs to be provided. Hence the binary must be published first so that it can be accessed via HTTP. This can happen by uploading the binary to a blob store or by archiving the artifact on Jenkins. The corresponding URL needs to be provided when the artifact is attached to the transport request. + +The transport request can be created on the fly (see [transportRequestCreate](../../../steps/transportRequestCreate/)) or we can use an already existing transport request. In case we use an already existing transport request Id the transport request Id needs to be provided in the git commit history (see example below) or the transport request Id needs to be provided inside the job (e.g. as a job parameter). + +The transport request can be closed by the pipeline job (see [transportRequestRelease](../../../steps/transportRequestRelease/)). + +This is an example of a Git commit message containing the transport request ID: + +``` +The headline + +The body. The blank line above is mandatory (Git standard). +TransportRequest: +``` + +By default, the Git commits between the merge base with the base branch (default: `master`) and the current branch head are traversed. + +![This pipeline in Jenkins Blue Ocean](images/pipeline.png) +###### Screenshot: Build and Deploy Process in Jenkins + +## Examples + +### Upload via RFC + +#### Jenkinsfile + +Following the convention for pipeline definitions, use a `Jenkinsfile`, which resides in the root directory of your development sources. + +```groovy +@Library('piper-lib-os') _ + + +pipeline { + + agent any + + stages { + stage("prepare") { + steps { + deleteDir() + checkout scm + setupCommonPipelineEnvironment script: this + } + } + + stage('build') { + steps { + // It depends on your project, what needs to be done here. Maybe it's sufficient to zip the sources + mtaBuild script: this + } + } + + stage('publish') { + steps { + // This uploads the binary into a blob store so that it can be attached to a transport request later + sh "curl --upload-file " + + // OR (in case there is no BLOB_STORE available) + + // This makes the artifact available on Nexus. The URL is the following: + // /job///artifact/. Nota bene: this format is not an Jenkins API. + // The build number can be retrieved during the build through ${currentBuild.number} + archiveArtifacts artifacts: + } + } + + // This attaches the deployable to a transport request + stage('attach') { + steps { + transportRequestUploadFile script: this, + transportRequestId: '', // This can be omitted if present inside a Git commit message + applicationUrl: '' + } + } + } +} +``` + +#### Configuration (`.pipeline/config.yml`) + +This is a basic configuration example, which is also located in the sources of the project. + +```yaml +general: + changeManagement: + type: 'RFC' + endpoint: 'the RFC endpoint' # e.g. example.com' + credentialsId: 'RFC' # The ID under which the credentials are provided on Jenkins defaults to 'CM' + rfc: + developmentInstance: '01' # needs to be adjusted + developmentClient: '001' # needs to be adjusted + docker: + image: '' # the image needs to be built on user side. The corresponding ID needs to be provided here. + options: [] + envVars: {} + pullImage: true|false # true if the image is provided by a company-specific Docker registry + +steps: + transportRequestUploadFile: + codePage: , # e.g. 'Cp1252' + acceptUnixStyleLineEndings: true|false + applicationName: '/your/application/name' + applicationDescription: 'Application description' + abapPackage: '/abap/package' +``` + +### Upload via ODATA + +#### Jenkinsfile + +Following the convention for pipeline definitions, use a `Jenkinsfile`, which resides in the root directory of your development sources. + +```groovy +@Library('piper-lib-os') _ + + +pipeline { + + agent any + + stages { + stage("prepare") { + steps { + deleteDir() + checkout scm + setupCommonPipelineEnvironment script: this + } + } + + stage('build') { + steps { + // It depends on your project, what needs to be done here. Maybe it's sufficient to zip the sources + mtaBuild script: this + } + } + + // This attaches the deployable to a transport request, + // if you have a prior call to mtaBuild, this step sets the deployable + stage('attach') { + steps { + transportRequestUploadFile script: this, + transportRequestId: '' // This can be omitted if present inside a Git commit message + } + } + } +} +``` + +#### Configuration (`.pipeline/config.yml`) + +This is a basic configuration example, which is also located in the sources of the project. + +```yaml +general: + changeManagement: + type: 'CTS' + endpoint: 'the ODATA endpoint' # e.g. 'http://example.org/sap/opu/odata/SAP/SCTS_CLOUD_API_ODATA_SRV/' + credentialsId: 'CTS' # The ID under which the credentials are provided on Jenkins defaults to 'CM' + clientOpts: '' # additional java options, e.g. '-Djavax.net.ssl.trustStore=/path/to/truststore.jks' +``` + +## Parameters + +For the detailed description of the relevant parameters, see: + +* [mtaBuild](https://sap.github.io/jenkins-library/steps/mtaBuild/) +* [transportRequestUploadFile](https://sap.github.io/jenkins-library/steps/transportRequestUploadFile/) diff --git a/documentation/docs/scenarios/upload-to-transportrequest/files/mta.yaml b/documentation/docs/scenarios/upload-to-transportrequest/files/mta.yaml new file mode 100644 index 000000000..d52a4c58b --- /dev/null +++ b/documentation/docs/scenarios/upload-to-transportrequest/files/mta.yaml @@ -0,0 +1,17 @@ +_schema-version: "3.1" +ID: "" +version: + +parameters: + ... + +modules: + - name: "" + type: + path: . + parameters: + version: -${timestamp} + name: "" + build-parameters: + builder: + ... diff --git a/documentation/docs/scenarios/upload-to-transportrequest/images/pipeline.png b/documentation/docs/scenarios/upload-to-transportrequest/images/pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..bf9f7411a3d7dde2ab1558a7babd0ce9e10ef76f GIT binary patch literal 22455 zcmeFYWmsKJvNj9^cM0xJaDux-aCe8`?ry<0PH-oL06~HT2<{sRE zLVaf|DXA(aDM_K~=4@r_UyIL097^UcQ04oJ}a=JEV3b^)CuYh0>TwjPr*5+y#fS^Y4tM1`pUH9;v!0>(du z#gr8nq7w}+!Il(UOS*+qxmxApl;!hnJHV=}lBV5cuQkjb$axI@u@S5glyA-#NlL=? zk(p6kkMm&h+fvq~ykc0BN-`laLahk+7z~pp3}(>!0+QEWEGh}$N4P>|r}V-(>G@2_ z6Tv5uj89xNX>Aov-GteT`vET&rCE+>l~%&n=W}G8HV-GI6M^+lK8JW`YL$|hih9xF zK_x5u8|UcoC9|hF+RtA!J;w+d-sNJW)bfB8eVxqf7vSsOV7Zz{Ilhm9wS3~iyhow^ zSZEjI;Fr!!C2qksoPjYH%Yqf%TuWqV#2_Ctb#n0MT=SM#e2FTxCMC)@{Ol)3Zv$eu z+4|l>EqWo1o(9`2EeopB#7#%)pFaBo*K&3?^|Hnf^P0w~Ur+nOkk>zGo^RAn_1w^S z=KENoJ4>_)khc+lq0kXuF@Fl7#u2dgu#!uny1#{rVgEx zQiXX6d55@39aLDZN6GNvPK8?kat7{wnN_SNS@RkP_?CibvwIaeE#p0nKJpEk9rzhE z7S;TxyD;~@Gy#p9gDBoSGozT(K@OEZ5~~P=B_+EAi_!Dygun+awD;9@-(zIm<8b~- z=7gM&RFm=!)lxpCG4p*n8D1u0i)lEb(rA{+Y}}%_Hk;6EjPQpfVrvLp7aTbPb?vDs z!6J$sfA&b)Oz`MqBT>grOMe1HM*K|?1LfullGpuxL>~#yCqfYEHUQL zT15!=U1u}uc7=KvDtvp-MmkOuBAEzn+IFj8{fI3>#stkb)vYra^Gm?cmlBF`B2*=n zgB@YE3wm|~x=kDk5qjMe2J}jf0!=Z>2(SB+`Bhz)VGUwxC~^&U<*OM}&Us|74+UK! z6R7B6IBTd)hyq=nF8EdXWGAQ>VZ5f8;+WVHvIHOw^U!&!F%SYI7M61T9cpsO7fQl+ zJXGSZ2Msrgzrg6lYf>8|`E6QnV!FZbCwfpdevEp@c7}Z$V$OiZEjFqu=)t@f`+d@e z3n?$sstC>oNk4{FwqioSgLff3UySYZ+$8G-p+E?yQ6u^yu}nH%LcB+&?yK61$8jWtZ3 zsk{r_4Ng<|&v1txW(mT=KMDEda(}TR}`{I(?7A#%-v{x@oyP! zk#CWFlRhid7T;(<7+{7RhLDGNtc+`WOu>(-*eNT6}({>Nf>fi0qO$U9oi+@0AUFM9`P&z8OMRSxuPIlM%I8~_tHRH_XGQo z!)yOkmtRwA@kLc}e)e1o4B&S*nojitJ1vt47U`}{u2rXu8&(_lbWPDIKWS3*=yDX5 zb1vd}2uRtpMOy+cIwrjp)img*VW;^^43yZi&@;1gq_gElc{203_BpMyqcXQMtGPw( zR_wcL5Wiy@R5tKgoeB;o^;vDzmg|=4KBkwXtED3kv!oxUhiPAF|J08CcBQ-ASfYQg zZ>?9|;8b_iSX+~2!#P*d{U?E?Z+1@mee23q<)ML~f2(He@j>=s{sQrD_d|sP;)7%U z3DOUw$Rv9tRs7hbfu!!FyaHZ)h04atRHa0v!((6T8tdkLi`=&fdI&l>k~usroLVLf z=UJs$(O5BzvZ^?$VvTZ)3KAO#b40vm=Ibm(TYa0injPI+_p6RYx&v$dEAACA=rKBE z;|I7^TCBsjVaD;s@i%e@kOmxyyoY1gxhMApt9hzbRzz0b9?KjXlM@%97U&n`bij9< zb_@rM-(o#TJmTGuUilv%ADZlRjz5n>WrQq+7(uHHEGFV7tnzdSPB13nH__HGfpAl? zE+kcTYAo5=npkhtK%O9q_x^)8Kd1$x+H)R-ez9oc`LSQH3>0uCx(lJA#G*1`*kjCL zsGwJ)2VYEV5jv-xdJXDPfcIu1-2 z-HN?R6G8XwT}#eEQsp}*g-N-rZ1sXO9&Tn&PrJFz+LUdjj!dg$I%Rt~`r^_r&MM@Y z*dmt8srhBb8p988(1$g>JL!+0%%;VG%PEp+;2jY+B#c$0pPR*oKQ zyWi~Jj>A%ZX!u}k_Q|E;L{8gucCWJZcj#~X@BY%=pXJpGGO4TZItQbNe&?R^@UnW# z9;q7Jt>g!|1<5>7Mt9KYxY?E5jzF^V)U9o^>MOcBO^w7mne~4dB@CASG(bjMi+oJ( z5kLI~F;i1jQ<`kmdsBCXzmKaB!#3)b-R^Ofk_<{F-(GXSabNhOKW4;ry)Jas#&Z7g zHtT#5PnV6sXrhkYZGBAomvnP%kkP>ppG(Nx>X)EteLL-zn)>_2L1*Hj`r-GMyqzdF zPUqMG(LQqb>f^=4=|QacsU}}tD!x|UG{tou^jsgU>I90`3)%bLBOl}DXk+WhYp>|y zw%Kjlwa?I2w9Y9SPS>Y5{0KPQ_vD<-t0vKD_7(PQHxJa&Qq&rT&p~724XDJ^GO0%T z_FKbVzqS7AP^P<|DMx~b+lgnnBU}qt#=3KK~CGe4T+K7p00$y73_^7N^FbMg+ta!56b(ri=eoVV*wfXU} zsP#jDg~>(7kH?OCVvKpRufl_Tx+~#aqfUFyc--C%Um85fvR%G@3m#n7+qSn4YJ=m(*rw~Dfe@8Pd68i%DtDg}Z#u75W5u6|np zZbm9{9Q-r^w~8`~-_FKkbk^c=qEl^x@x#B7*XXKwX=;6La)H0&d?#&{&WqJSCk`iJ71*8^LI@_qozSv|!M4*y1uqE( zlFK_icPJ=4+LsTsoI1@36clv6t){Mru9BjFg|j28*?VVmOI9C87oay3l#q`A@aSmi zVMgKO=-}io;3G`+R}TT;`Q>XiDvH0lc-RY5=_;vGNIJV&QgE|!v9eQ%AX89K2)Vtt z5>S_t`NweJKVd2x4-XdsHa2f>Z&q(kR%bVBHV%G%em3^EY;WJP06kdTeVshad{~^^ zssEnjzvhv$bhmJ`b@8xucA|Kh*Ua46(?ghw>V?pM|NPCTrH}1DDLJ|SV_Cog* z@_)4aW26w<%L@L-ivAYYU*7`q5Qxs01l_2p@97?Czc!n4~s2D$snyL2Kxn0 zD&}=@5d}}pNi>YQCgy9k&lD6|*%4HjnlWMyuW?_$W00eORfCa3Wem6{$=X^zrSB@wZ5+BALnN!_ePL|83U)8XO{#JN|!98v^S_@d-2I)q54n|C28Y z=m@@o|ImW8DJDkAiZGZj@gKNCb`^Q`?+g70OM{^y5{BqW!V&)>h5zOk_BA8`{y&H+ z=@oQD6A6Vs^8Y1AUPsD-?I3B9{bN&_Wz^D zT2gf0Kw{UU>GKhLBhgT(WfM?`Sz8^fP&(!R*255v&%^0J?~IN~oUtiVwaD>iBIM*SuY|0(S_0!5`2lKUko-@osSMwI@+4fa( zJj?dg?L8nY>hj;Cjx-Z#u&k{I-%oyNs6=qj>QXD_2{c&2uilP%_axIQ^vDo9zWy<9 z9t(K_=mhuVd9M&^>shANtoZHY1|JW@3}kUw$f(Z=?|m)0b3?rT_!8nzE~|ruZ42DW zqjBgX69YD>`EzG9HkC{#KTEHt=@^&Y)xSbOM;&HqG@MzStE03WZ|u1IwuzZ4m#U;6 z2n0Ul2jigIEtkWFIlAEB=lj)IDU;{BxhUSw+flP|;cL_sIwi)ZqYr-v^G_t9q7UmB z>rER83fdaJGMK}|Ul~Z<1}WEfOAF97Cu~MKPve~xm7jNt5+kV-h2H8tO=Wbv=2`LC z$WD%E8VH(ynYZR@!G5m3lUU(X4r0KbMgcO0@P+EUOD|e4pb_2k;^QBSPG+Z&KC=uX zFC+vqA5+(7=YS33^;rXFrH`Epy; z;SRxq=bTZB1qJMNaadUutjF4z5gSYc0=xa!R;MMP%)u4OaT@Ag`sf0IR+}b9J&`2DcRLtwi z#2_xLh2{`auX#!muX(e;4!npaks|j29-5P`R~R(L>wKmp!4Idx3m&_}-4zcP(<&H% zLOOe*0Lj-p-R+m^@LK9oR=t^b7cG-8JQ~dL>#4$rxYV|t_7kV%oIG83imIg%4uy$D z@eQ!&u0B6q|D5=I9C++699jN!meGmoBk0iic(o45#(5#$A9*;L~{l#&OVftAb|lc6Q6}p4 zuK4y08|r{>FYyXye?0M=1^1~aYs=2(5){{O$q8gG4^+Te;FAIpmjUS2{RcRd%aY`b5>qYt+2aB`Ay>|_HMs~4|e~n z19ta6BkZPKAv74SE9(81IAUbSQ)$}zZ+?gG(_mm_dh~=N^?f?qeXMA&x)5Pi_>=`Z zgybr8-1drqaY*pfk_${*!>JFYO0l)Dk_pZ+))2PC<&4fThdo|rT|QD2gXHHKDzF;- z>Dana7%$)PTY7sC&7%VX%w@Xguip?@W5p%hee+%WQq%xQG<|Y`wvp!ynQu!fW)y*# z2u-lsHcfDb04oABub!m9F(@qyN(*=Zwjih<_0 zTN&d=d)`P~@ldxQ>(myWx>V|_(_HLf$A%eg14bjTpQNtfdN@wZex?sY|6@rd_*L{B zr|)^DMS@)0(CQVjD$#OtsYigL) zXR=M{xR_Ez0xrn)G9EcvgT=Unx$GbW~Kel$UtC z_Vy|)gk>1?Ua&3wf)#MoyiHdC&R%;uZIjyQ>mP~fjlxJ2r7fs6e^|Nh;5{KZc^nXZ za&;B3w~~6#;K?N<7>$3v5$ZFh#U}2~fQkyVEH#3U{z0 z;6dM_dAvDk*AFt?7{NEaE^|iSv>bexJM47Aw-EeJ0$z*;V;xsne42^(FsFL-gkY>< zb;V{Z;sXxfMWkWv6_sW~bHhEW*Agm~pvUX?6_g;bQguES)UJ zf;`;}h|=9_%oaPIkMgRVF>q|NTPrC|yEfw@{W6%vij8j})*kbZlo{)|Kgw~CY;GLo zS)>_$h`r>qQhEf!Xzr#oM1vApN^;FgB2Ar>DFX+>2VYxNgTmHUBO67IMmr@Ru(5NC zGk$s1*eOin3dRy%!L9A+7L3u;DAU0{q7k+yCq?*`s4%0oQTv!GW(D!2z?DPv)UvE{mPa~s5c{?NNBdu^B zF^7>|5uH+xcdwBa@ZqD;V}x5Rd@4o_ z4CCu{ja+F$D}ooj{i*WTetr8>PlGz^PNY>IBnh<^@z{gHM)NvL&*`}RTKN~mO}8NU z>2}ld9UMYKW>jk~rYvoe%rCZ})7VWHYMHoqWC27*KG4$ZUs4y{M-;zAT@;t5ZNn-3 zkpP#`k#1G>trAO8Xg~1_urV^8`+Pl_>J^MIuGS6h5@W1bFK`<>70Ye;s8lH@y=`PV?a?E*zr#?cO+=J-!r{eaNJs465sDf6EH193`=n0{ z6RbXO8VG1ltyGL+Lr$d3w1u9aqcCU5f(WyG?&6!A$Sc;nC zU5XHiJNphBBr9vSy&kkrE%Nw5m0J9bO@ie1>`#uf@(Qnq)1=R5bU6$1ala0n7+U>G z=aZn%IEP2A$I3$6UxQUUX+~@7;smz8$fZE4g5)W@VNQJy55Wab7p1-0299YC+TSn- z&PRjV^VEWJSw9Hh%OU8Z&KKZ8zHaMaqxud|oY@}Aei9AmyFkt7 zSg`dNoZ^wXX@7pY$D!E412ygbpl7lXoU#SG%Qe>@wd~Vb!WVH7jE3$I?}s3}KAt;x zHee!1w7Dq@or1}@Y?)8b7Ttzf6k5&(;<0{WZZM)L_4OjKA(rHdCb)oAx6Q9{}&2|)duScSsqcH059`3r>-28y_@C7y9y zCaw_qr1|<7N-{nfn}p$pZ`PR`xF}BM-m!5RPg(f#*L%Wo<^1Y;tj?qlneb5CG2@Eu zyOJPD)c1IArbrWqn}Z+sO`>)~oTRevKa3UImFZ zOcF~$`cmMTeAbN-#J;;(Xdd>l+Lk@Vq{iV@BcTLI9^A{J60#oCq)b*?L_tJ~2!c}+ z(*(u7e{j%x*+w3LEg;G*2OizhgiDHbuK<1I#3G>UN62F>rXz+hiG90@4AV zUCcjAsYcrc!9fruna5QMM=0_94p(a6p~8&d6HuCf86q5)_ma~3g+3p}L%k&?aG0Dw8otgIRCqf2pTn! z|7nWKKnOuNk;7Qr%SKIr^YrtwbLS((Ng)t0hhnd@s7S1LI!}bj5*yqt>7^<|D9P*P zVB=fhG^`nipIJpfjl4mX8yNIemju`h<(v^%Z=%TjZ0;udEE%6TtwspK_Q2YctI*=9trlH`1nb z2oJIE8x{ulBLnC523h{0uc+oF(!Cm~ZcO^k>wgekcgIfEKYIzum`u6#qVdxBvXF%( z_~nXzkCe4*IZVQXfX=0bDM?}Ia-3lE9%z7xTP7;i<@h%xgTZ+1Q&I{U{p4-_FD zLrJC8&oG5xX`X%xLzhR79#V8@w&CF95CX{)*)mvPmJ}_yKDIl^$JEb^V^XepK+rZtu#srVMEo^t)^e@MyEnS@}GXgPL2CD3n>zvvYPQRpjr8y7valuhBwXcj3e*ZrUS

~V!az^m@c*gJLMbg&Z!>$QE8Hh65MBDEy`59 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