This post walks through setting up a simple CI/CD pipeline using GitHub Actions that automatically deploys a Node.js app to SAP BTP Cloud Foundry on every push to main.
What You’ll Need
An SAP BTP account with Cloud Foundry enabled and a space to deploy toA GitHub accountNode.js and the CF CLI installed locallyA non-SSO username and password for your BTP account (used by the pipeline
The App
We’ll deploy a minimal Node.js Express app with a simple Fiori-styled frontend. Nothing fancy — the point is the pipeline, not the app.
The project structure is:
btp-cicd-demo/
├── .github/
│ └── workflows/
│ └── deploy.yml
├── public/
│ └── index.html
├── server.js
├── package.json
├── manifest.yml
└── .gitignore
server.js
const express = require(“express”);
const path = require(“path”);
const app = express();
app.use(express.static(path.join(__dirname, “public”)));
app.get(“/”, (req, res) => {
res.sendFile(path.join(__dirname, “public”, “index.html”));
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
package.json
{
“name”: “btp-cicd-demo”,
“version”: “1.0.0”,
“description”: “BTP CI/CD Demo App”,
“main”: “server.js”,
“scripts”: {
“start”: “node server.js”
},
“dependencies”: {
“express”: “^5.2.1”
}
}
manifest.yml
applications:
– name: btp-cicd-demo
memory: 128M
buildpacks:
– nodejs_buildpack
public/index.html
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″ />
<title>BTP CI/CD Demo</title>
<script
id=”sap-ui-bootstrap”
src=”https://openui5.hana.ondemand.com/resources/sap-ui-core.js”
data-sap-ui-theme=”sap_fiori_3″
data-sap-ui-libs=”sap.m”
data-sap-ui-compatVersion=”edge”
data-sap-ui-preload=”async”
></script>
<script>
sap.ui.getCore().attachInit(function () {
sap.ui.require([“sap/m/App”, “sap/m/Page”, “sap/m/Text”], function (App, Page, Text) {
new App({
pages: [
new Page({
title: “BTP CI/CD Demo”,
content: [
new Text({ text: “Deployed via SAP CI/CD Service” })
]
})
]
}).placeAt(“content”);
});
});
</script>
</head>
<body class=”sapUiBody sapUiSizeCompact”>
<div id=”content”></div>
</body>
</html>
.gitignore
node_modules/
.env
Initialise the repo, commit everything, and push to GitHub.
The Pipeline
Create .github/workflows/deploy.yml:
name: Deploy to Cloud Foundry
on:
push:
branches:
– main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
– name: Checkout code
uses: actions/checkout@v3
– name: Install CF CLI
run: |
curl -L “https://packages.cloudfoundry.org/stable?release=linux64-binary&version=v8&source=github” | tar -zx
sudo mv cf8 /usr/local/bin/cf
– name: Deploy to Cloud Foundry
env:
CF_API: https://api.cf.ap10.hana.ondemand.com
CF_USERNAME: ${{ secrets.CF_USERNAME }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: <your-org>
CF_SPACE: <your-space>
run: |
cf login -a $CF_API -u $CF_USERNAME -p $CF_PASSWORD -o “$CF_ORG” -s “$CF_SPACE”
cf push btp-cicd-demo
Update CF_API with your region endpoint, and CF_ORG and CF_SPACE with your actual org and space names. These are visible when you run cf target.
GitHub Secrets
The pipeline uses two secrets to authenticate with Cloud Foundry without hardcoding credentials in the workflow file. In your GitHub repo go to Settings, then Secrets and variables, then Actions, and add two repository secrets:
CF_USERNAME — your BTP account email address CF_PASSWORD — your BTP account password
These are encrypted by GitHub and injected into the workflow at runtime. They never appear in logs or the codebase.
Note: this approach requires a non-SSO login. If your account authenticates via a corporate identity provider, you will need a technical user created by your BTP administrator for pipeline use.
Running the Pipeline
Push the workflow file to main:
git add .
git commit -m “Add CI/CD workflow”
git push
Go to the Actions tab in your GitHub repo. You should see the workflow trigger immediately. Click on it to watch the steps run — checkout, CF CLI install, login, and push.
If everything is configured correctly you’ll see a green tick and your app will be live at your CF route.
Once deployed, loading the app URL in your browser should give you something like this:
What This Gives You
Every push to main now triggers an automatic deployment to Cloud Foundry. No manual cf push, no forgetting to deploy, no environment drift between what’s in the repo and what’s running.
It’s a simple starting point. From here you can add a build step, run tests before deploying, deploy to multiple spaces (dev, test, prod) based on branch, or introduce the MTA build tool for more complex landscapes.
Full Repo: https://github.com/neilaspin/btp-cicd-demo
This post walks through setting up a simple CI/CD pipeline using GitHub Actions that automatically deploys a Node.js app to SAP BTP Cloud Foundry on every push to main.What You’ll NeedAn SAP BTP account with Cloud Foundry enabled and a space to deploy toA GitHub accountNode.js and the CF CLI installed locallyA non-SSO username and password for your BTP account (used by the pipelineThe AppWe’ll deploy a minimal Node.js Express app with a simple Fiori-styled frontend. Nothing fancy — the point is the pipeline, not the app.The project structure is:btp-cicd-demo/
├── .github/
│ └── workflows/
│ └── deploy.yml
├── public/
│ └── index.html
├── server.js
├── package.json
├── manifest.yml
└── .gitignoreserver.jsconst express = require(“express”);
const path = require(“path”);
const app = express();
app.use(express.static(path.join(__dirname, “public”)));
app.get(“/”, (req, res) => {
res.sendFile(path.join(__dirname, “public”, “index.html”));
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));package.json{
“name”: “btp-cicd-demo”,
“version”: “1.0.0”,
“description”: “BTP CI/CD Demo App”,
“main”: “server.js”,
“scripts”: {
“start”: “node server.js”
},
“dependencies”: {
“express”: “^5.2.1”
}
}manifest.ymlapplications:
– name: btp-cicd-demo
memory: 128M
buildpacks:
– nodejs_buildpackpublic/index.html<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″ />
<title>BTP CI/CD Demo</title>
<script
id=”sap-ui-bootstrap”
src=”https://openui5.hana.ondemand.com/resources/sap-ui-core.js”
data-sap-ui-theme=”sap_fiori_3″
data-sap-ui-libs=”sap.m”
data-sap-ui-compatVersion=”edge”
data-sap-ui-preload=”async”
></script>
<script>
sap.ui.getCore().attachInit(function () {
sap.ui.require([“sap/m/App”, “sap/m/Page”, “sap/m/Text”], function (App, Page, Text) {
new App({
pages: [
new Page({
title: “BTP CI/CD Demo”,
content: [
new Text({ text: “Deployed via SAP CI/CD Service” })
]
})
]
}).placeAt(“content”);
});
});
</script>
</head>
<body class=”sapUiBody sapUiSizeCompact”>
<div id=”content”></div>
</body>
</html>.gitignorenode_modules/
.envInitialise the repo, commit everything, and push to GitHub.The PipelineCreate .github/workflows/deploy.yml:name: Deploy to Cloud Foundry
on:
push:
branches:
– main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
– name: Checkout code
uses: actions/checkout@v3
– name: Install CF CLI
run: |
curl -L “https://packages.cloudfoundry.org/stable?release=linux64-binary&version=v8&source=github” | tar -zx
sudo mv cf8 /usr/local/bin/cf
– name: Deploy to Cloud Foundry
env:
CF_API: https://api.cf.ap10.hana.ondemand.com
CF_USERNAME: ${{ secrets.CF_USERNAME }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: <your-org>
CF_SPACE: <your-space>
run: |
cf login -a $CF_API -u $CF_USERNAME -p $CF_PASSWORD -o “$CF_ORG” -s “$CF_SPACE”
cf push btp-cicd-demoUpdate CF_API with your region endpoint, and CF_ORG and CF_SPACE with your actual org and space names. These are visible when you run cf target.GitHub SecretsThe pipeline uses two secrets to authenticate with Cloud Foundry without hardcoding credentials in the workflow file. In your GitHub repo go to Settings, then Secrets and variables, then Actions, and add two repository secrets:CF_USERNAME — your BTP account email address CF_PASSWORD — your BTP account passwordThese are encrypted by GitHub and injected into the workflow at runtime. They never appear in logs or the codebase.Note: this approach requires a non-SSO login. If your account authenticates via a corporate identity provider, you will need a technical user created by your BTP administrator for pipeline use.Running the PipelinePush the workflow file to main:git add .
git commit -m “Add CI/CD workflow”
git pushGo to the Actions tab in your GitHub repo. You should see the workflow trigger immediately. Click on it to watch the steps run — checkout, CF CLI install, login, and push.If everything is configured correctly you’ll see a green tick and your app will be live at your CF route.Once deployed, loading the app URL in your browser should give you something like this: What This Gives YouEvery push to main now triggers an automatic deployment to Cloud Foundry. No manual cf push, no forgetting to deploy, no environment drift between what’s in the repo and what’s running.It’s a simple starting point. From here you can add a build step, run tests before deploying, deploy to multiple spaces (dev, test, prod) based on branch, or introduce the MTA build tool for more complex landscapes.Full Repo: https://github.com/neilaspin/btp-cicd-demo Read More Technology Blog Posts by Members articles
#SAP
#SAPTechnologyblog