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.

Context

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.

Procedure

  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
    //     as "additional variables" in your pipeline config.
    var githubApiUrl = process.env.GITHUB_API_URL;
    var githubToken = process.env.GITHUB_TOKEN;
    var owner = process.env.GITHUB_ORG;
    var repo =  process.env.GITHUB_REPO;
    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;
    
    // The additional asset path is relative to the project root folder.
    // The script is launched from the create-release subfolder. Hence we have to
    // add a leading '../' to that path.
    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')
    
    //
    // 3.) Prepare the client for communicating with the GitHub-API.
    const octokit = new Octokit({
      auth: githubToken,
      baseUrl: githubApiUrl,
    });
    
    
    //
    // 4.) Create the GitHub release.
    octokit
      .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) => {
        // A response status code check is not required. In case of an issue, octokit throws an error.
        console.log(`Release created: status: '${res.status}', url: '${res.data.html_url}'`)
    
        //
        // 5.) Attach the additional asset.
        octokit.request(`POST ${res.data.upload_url}`, {
          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
GITHUB_API_URL The API URL for the GitHub host
GITHUB_ORG The GitHub org, in which the sources are located
GITHUB_REPO The GitHub repository, in which the sources are located
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:

---
general:
  buildTool: "mta"
service:
  buildToolVersion: "MBTJ11N16"
  stages:
    Build:
      runLast:
        command: "cp BAS_Sample_App.mtar cloudcitransfer"
    Release:
      credentialVariables:
      - name: "GITHUB_TOKEN"
        credentialId: "<YOUR_GITHUB_TOKEN>"
      stringVariables:
      - name: "GITHUB_ORG"
        value: "<YOUR_GITHUB_ORG>"
      - name: "GITHUB_REPO"
        value: "<YOUR_GITHUB_REPO>"
      - name: "RELEASE_NAME_PREFIX"
        value: "experimental"
      - name: "RELEASE_TAG_PREFIX"
        value: "v0.0.1"
      - name: "ADDITIONAL_ASSET_PATH"
        value: "cloudcitransfer/BAS_Sample_App.mtar"
      - name: "ADDITIONAL_ASSET_LABEL"
        value: "BAS_Sample_App.mtar"
      - name: "GITHUB_API_URL"
        value: "<YOUR_GITHUB_API_URL>"
      runLast:
        command: "cd create-release && npm install && node create-release.js"
stages:
  Build:
    npmExecuteLint: false
  Additional Unit Tests:
    npmExecuteScripts: false
  Malware Scan:
    malwareExecuteScan: true
  Acceptance:
    cloudFoundryDeploy: false
    npmExecuteEndToEndTests: fals
  Compliance:
    sonarExecuteScan: false
  Release:
    cloudFoundryDeploy: true
    cfApiEndpoint: "<YOUR_CF_ENDPOINT>"
    cfOrg: "<YOUR_CF_ORG>"
    cfSpace: "<YOUR_CF_SPACE>"
    cfCredentialsId: "<YOUR_CF_CREDENTIAL_ID>"
    deployType: "standard"
    tmsUpload: false
steps:
  artifactPrepareVersion:
    versioningType: "cloud_noTag"
  cloudFoundryDeploy:
    mtaDeployParameters: "-f --version-rule ALL"

Result

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!

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x