CI/CD

Why not use SAP CI/CD service

SAP's Continuous Integration & Delivery service on BTP is technically correct but painful in practice:

  • Limited customisation of pipeline steps
  • Slow feedback loops (5–10 min for a simple iFlow deploy)
  • No native GitHub PR integration
  • Additional BTP service cost

GitHub Actions gives you full control, integrates directly with your PR workflow, runs faster, and is free for public repos. If you're already using GitHub, use GitHub Actions.

Repository structure

my-integration-suite/
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       β”œβ”€β”€ deploy-dev.yml
β”‚       β”œβ”€β”€ deploy-qa.yml
β”‚       └── deploy-prod.yml
β”œβ”€β”€ iflows/
β”‚   β”œβ”€β”€ OrderProcessing/
β”‚   β”‚   β”œβ”€β”€ OrderProcessing.iflw     # exported iFlow ZIP extracted
β”‚   β”‚   β”œβ”€β”€ metainfo.prop
β”‚   β”‚   └── src/main/resources/
β”‚   β”‚       └── mapping/
β”‚   └── InvoiceSync/
β”‚       └── ...
β”œβ”€β”€ packages/
β”‚   └── MyIntegrationPackage/
β”‚       └── metainfo.prop
└── scripts/
    β”œβ”€β”€ deploy.sh
    └── validate.sh

Export iFlows from the CPI tenant as ZIP files and commit the extracted contents. This makes diffs readable β€” you can see what XSLT or Groovy changed in a PR review.

The pipeline workflow

# .github/workflows/deploy-dev.yml
name: Deploy to CPI Dev

on:
  push:
    branches: [develop]
    paths:
      - 'iflows/**'
      - 'packages/**'

env:
  CPI_HOST: ${{ secrets.CPI_DEV_HOST }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Get OAuth Token
        id: token
        run: |
          TOKEN=$(curl -s -X POST \
            "${{ secrets.XSUAA_URL }}/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -u "${{ secrets.CPI_CLIENT_ID }}:${{ secrets.CPI_CLIENT_SECRET }}" \
            -d "grant_type=client_credentials" \
            | jq -r '.access_token')
          echo "::add-mask::$TOKEN"
          echo "token=$TOKEN" >> $GITHUB_OUTPUT

      - name: Upload iFlow
        run: |
          ./scripts/deploy.sh \
            --host "$CPI_HOST" \
            --token "${{ steps.token.outputs.token }}" \
            --iflow "OrderProcessing" \
            --package "MyIntegrationPackage"

      - name: Verify Deployment
        run: |
          ./scripts/validate.sh \
            --host "$CPI_HOST" \
            --token "${{ steps.token.outputs.token }}" \
            --iflow "OrderProcessing"
Security

Use ::add-mask:: to redact the OAuth token from GitHub Actions logs. Without this, the token appears in plain text in the workflow run output β€” visible to anyone with read access to your repository.

Approval gates & environments

For production deployments, add a manual approval step using GitHub Environments:

  1. Go to Repository Settings β†’ Environments β†’ New environment
  2. Name it production
  3. Add Required reviewers (your tech lead or team lead)
  4. Set a Wait timer if you want a mandatory delay after approval
# .github/workflows/deploy-prod.yml
jobs:
  deploy-prod:
    runs-on: ubuntu-latest
    environment: production  # triggers approval gate
    needs: [deploy-qa]       # only runs after QA succeeded
    steps:
      # same deploy steps as dev, pointing to prod secrets

The pipeline stops at the production deploy job, sends a notification to the required reviewers, and only continues after manual approval in the GitHub UI. Zero extra tooling needed.

Best practice

Tag the Git commit after every successful production deployment: git tag -a v1.4.2 -m "Deploy: OrderProcessing hotfix". When a production incident happens at 2am, you want to immediately see what version is deployed and diff it against the previous version.

← All articles