Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
Showing results for 
Search instead for 
Did you mean: 

With SAP Continuous Integration and Delivery, we like to keep things simple and easy to use. That’s why we’ve created preconfigured CI/CD pipelines for SAP-specific development scenarios. These pipelines consist of several building blocks, so-called stages. Each stage describes a task such as build this apprun these tests, and deploy this to pre-production. When running a pipeline job, each stage performs various smaller tasks - that is, steps - one after the other to meet its purpose.

Our goal was to cover standard scenarios to onboard you as quickly as possible. But sometimes, standard scenarios aren't sufficient. We’ve therefore already implemented the option to add additional credentials and variables to most stages within our CI/CD pipelines (see We Made Our CI/CD Pipelines More Flexible). As a second step in our journey to more flexibility, we’ve now added extension points that let you add your own commands before or after any other step within a stage.

You can extend our pipelines with any kind of additional JavaScript tasks, which will then be executed within a Node.js Docker image. Of course, you also can combine additional commands with additional credentials and variables.

For more information on why and how we want to make our CI/CD pipelines more flexible, see Extensible Pipelines for SAP Continuous Integration and Delivery.

When does it make sense to enhance our standard pipeline functionality? Let’s have a look at an example:

Creating a GitHub Release with an Additional Build Artifact

Add a command for a GitHub release with an attached .mtar file to the Release stage of your job.


In this example, you will add a GitHub release as last step to the Release stage of your SAP Continuous Integration and Delivery job. This GitHub release contains the .mtar file that results from the Build stage. To reuse files in later stages of a job, they must be placed into the so-called cloudcitransfer folder in your project sources. This folder is created automatically at the start of a pipeline run.


  1. In your project in your source code repository, create a file called create-release/create-release.js and paste the following content into it:

    const { Octokit } = require("@octokit/core");
    const fs = require("fs");
    const dateFormat = require('date-and-time')

    // 1.) Retrieve all parameters from the environment.
    // The corresponding environment variables are defined
    // in the job.

    // If the GITHUB_TOKEN is a basic auth credential, the
    // user and password are exposed with a trailing
    // '_user' and '_password'.
    var githubToken = process.env.GITHUB_TOKEN
    var releaseNamePrefix = process.env.RELEASE_NAME_PREFIX;
    var releaseTagPrefix = process.env.RELEASE_TAG_PREFIX;
    var additionalAssetLabel = process.env.ADDITIONAL_ASSET_LABEL

    // CLOUDCI_GIT_COMMIT is not defined as additional environment variable
    // for the stage. CLOUDCI_GIT_COMMIT is always injected into the environment
    // for run-first and run-last commands.
    var targetCommitish = process.env.CLOUDCI_GIT_COMMIT;

    // We expect the additional asset in the transfer folder one folder level above,
    // since the script is launched from a subfolder.
    var additionalAssetName = `../${process.env.ADDITIONAL_ASSET_PATH}`;

    // 2.) Use a suitable stategy for release suffixes
    // to ensure that the same release does not already exist. A simple and
    // straight-forward approach is to use a time stamp.
    var releaseSuffix = dateFormat.format(new Date(), 'YYYY-MM-DD-HH-mm-ss')

    // 1: protocol
    // 2: host
    // 3: owner
    // 4: repo
    var gitRepoUrlParts = process.env.GIT_URL.match(/(.*):\/\/(.*)\/(.*)\/(.*).git/)

    var githubApiUrl=`${gitRepoUrlParts[1]}://${gitRepoUrlParts[2]}/api/v3/`
    var owner=gitRepoUrlParts[3]
    var repo=gitRepoUrlParts[4]

    // 3.) Define the client for communicating with the GitHub-API.
    const octokit = new Octokit({
    auth: githubToken,
    baseUrl: githubApiUrl,

    // 4.) Create the GitHub release.
    .request("POST repos/{owner}/{repo}/releases", {
    owner: owner,
    repo: repo,
    target_commitish: targetCommitish,
    tag_name: `${releaseTagPrefix}-${releaseSuffix}`,
    name: `${releaseNamePrefix}-${releaseSuffix}`,
    draft: false,
    prerelease: false,
    generate_release_notes: false,
    .then((res) => {
    // response status code check not required. In case of an issue octokit throws an error
    console.log(`Release created: status: '${res.status}', url: '${}'`)

    // 5.) ... and we attach the additional asset
    octokit.request(`POST ${}`, {
    name: additionalAssetName,
    label: additionalAssetLabel,
    data: fs.readFileSync(additionalAssetName),

    console.log(`additional asset "${additionalAssetName}" uploaded`)

  2. Create another file called create-release/package.json with the following content:
    "dependencies": {
    "@octokit/core": "^4.2.0",
    "date-and-time": "^3.0.0",
    "fs": "^0.0.1-security"

    As a result, a GitHub release with an additional asset, namely an .mtar file that results from the build, is created.

  3. In SAP Continuous Integration and Delivery, create a new or edit an existing SAP Cloud Application Programming Model job.

  4. In the Build stage, choose + (Add command step) next to Additional Commands and then Run Last in Stage.

  5. As Command, enter: cp <PATH_TO_MTAR_FILE> cloudcitransfer

  6. In the Release stage, choose + (Add command step) next to Additional Commands and then Run Last in Stage.

  7. As Command, enter: cd create-release && npm install && node create-release.js

  8. Choose + (Add credentials variable) next to Additional Credentials.

  9. Enter a name for your credentials variable.

  10. From the Credentials Name drop-down list, choose Create Credentials.

  11. Enter the necessary information for your GitHub token and choose Create.

  12. Choose OK.

  13. Choose + (Add variable) next to Additional Variables.

  14. Add the following variables:

Name Value
RELEASE_NAME_PREFIX A prefix for the name of the release. A timestamp will be appended.
RELEASE_TAG_PREFIX A prefix for the tag used for the release. A timestamp will be appended.
ADDITIONAL_ASSET_LABEL The label for the additional asset
ADDITIONAL_ASSET_PATH The path to the file, in which the additional asset is located. Provide the file which was copied into the cloudcitransfer folder in run-last of the build stage.

  1. Create and run your job.


Configuration as Code

The configuration for this example looks as follows:

buildTool: "mta"
buildToolVersion: "MBTJ11N16"
command: "cp BAS_Sample_App.mtar cloudcitransfer"
- name: "GITHUB_TOKEN"
credentialId: "<YOUR_GITHUB_TOKEN>"
value: "experimental"
value: "v0.0.1"
value: "cloudcitransfer/BAS_Sample_App.mtar"
value: "BAS_Sample_App.mtar"
command: "cd create-release && npm install && node create-release.js"
npmExecuteLint: false
Additional Unit Tests:
npmExecuteScripts: false
Malware Scan:
malwareExecuteScan: true
cloudFoundryDeploy: false
npmExecuteEndToEndTests: fals
sonarExecuteScan: false
cloudFoundryDeploy: true
cfApiEndpoint: "<YOUR_CF_ENDPOINT>"
cfOrg: "<YOUR_CF_ORG>"
cfSpace: "<YOUR_CF_SPACE>"
cfCredentialsId: "<YOUR_CF_CREDENTIAL_ID>"
deployType: "standard"
tmsUpload: false
versioningType: "cloud_noTag"
mtaDeployParameters: "-f --version-rule ALL"


You have now extended our preconfigured pipeline for SAP Cloud Application Programming Model projects by a GitHub release with an additional asset.

How do you extend your SAP Continuous Integration and Delivery jobs? Try it out and let us know!