Skip to content

Multi Tenancy Deploy & Integration Test LatestVersion🚀 #206

Multi Tenancy Deploy & Integration Test LatestVersion🚀

Multi Tenancy Deploy & Integration Test LatestVersion🚀 #206

name: Multi Tenancy Deploy & Integration Test LatestVersion🚀
# This workflow now runs ONLY after the main "Multi Tenancy Deploy & Integration Test" workflow
# (multiTenant_deploy_and_Integration_test.yml) has completed successfully. It can still be
# triggered manually via workflow_dispatch if needed.
on:
workflow_run:
workflows: ["Multi Tenancy Deploy & Integration Test🚀"]
types: [completed]
workflow_dispatch:
permissions:
contents: read
pull-requests: read
packages: read # Added permission to read packages
jobs:
deploy:
environment: dev
#Run only if the triggering workflow concluded successfully
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
steps:
- name: Checkout this repository 📁
uses: actions/checkout@v6
- name: Set up JDK 21 ☕
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '21'
- name: Build and package 📦
run: |
echo "🔨 Building and packaging..."
mvn clean install -P unit-tests -DskipIntegrationTests
echo "✅ Build completed successfully!"
- name: Setup Node.js 🟢
uses: actions/setup-node@v3
with:
node-version: '20' # Ensure to use at least version 18
- name: Install MBT ⚙️
run: |
echo "🔧 Installing MBT..."
npm install -g mbt
echo "✅ MBT installation complete!"
- name: Override cds.services.version (runtime only)
env:
TARGET_CDS_SERVICES_VERSION: 4.3.1
run: |
set -e
echo "=== cds.services.version Override Step ==="
echo "Target version to apply: ${TARGET_CDS_SERVICES_VERSION}"
FILES=$(grep -Rl "<cds.services.version>" app/multi-tenant/central-space/cloud-cap-samples-java | grep pom.xml || true)
if [ -z "$FILES" ]; then
echo "No pom.xml files with <cds.services.version> found" >&2; exit 1;
fi
echo "POM files containing property:"; echo "$FILES" | sed 's/^/ - /'
echo "\nCurrent raw occurrences BEFORE override:"
for f in $FILES; do
# Show each occurrence with line number (first 3 if multiple)
MATCHES=$(grep -n "<cds.services.version>" "$f" | head -3 || true)
if [ -n "$MATCHES" ]; then
echo "--- $f"; echo "$MATCHES"
fi
done
echo "\nResolving effective value BEFORE override via mvn help:evaluate ..."
RESOLVED_BEFORE=$(mvn -q -DforceStdout help:evaluate -f app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml -Dexpression=cds.services.version || true)
echo "Effective cds.services.version before override: '${RESOLVED_BEFORE}'"
if [ "${RESOLVED_BEFORE}" = "${TARGET_CDS_SERVICES_VERSION}" ]; then
echo "NOTE: Effective value already equals target; files will still be normalized to target string."
fi
echo "\nApplying override ..."
# Perform in-place replacement for each file
for f in $FILES; do
sed -i "s|<cds.services.version>[^<]*</cds.services.version>|<cds.services.version>${TARGET_CDS_SERVICES_VERSION}</cds.services.version>|" "$f"
done
echo "\nRaw occurrences AFTER override:"
grep -R "<cds.services.version>" $FILES || true
echo "\nResolving effective value AFTER override via mvn help:evaluate ..."
RESOLVED_AFTER=$(mvn -q -DforceStdout help:evaluate -f app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml -Dexpression=cds.services.version || true)
echo "Effective cds.services.version after override: '${RESOLVED_AFTER}'"
if [ "${RESOLVED_AFTER}" != "${TARGET_CDS_SERVICES_VERSION}" ]; then
echo "WARNING: Resolved value does not match target (profiles or parent POM could be overriding it)." >&2
fi
echo "(Not committing these changes)"
echo "=== Override Step Complete ==="
shell: bash
- name: Change directory to cloud-cap-samples-java 📂
working-directory: app/multi-tenant/central-space/cloud-cap-samples-java
run: |
pwd
echo "✔️ Directory changed!"
- name: Set REPOSITORY_ID 🔍
id: set_repository_id
run: |
echo "repository_id=${{ secrets.MULTITENANT_REPOSITORY_ID }}" >> $GITHUB_OUTPUT
- name: Run mbt build 🔨
working-directory: app/multi-tenant/central-space/cloud-cap-samples-java
run: |
echo "🚀 Running MBT build..."
echo "java version:"
java --version
sed -i 's|__REPOSITORY_ID__|${{ steps.set_repository_id.outputs.repository_id }}|g' mta.yaml
mbt build
echo "✅ MBT build completed!"
- name: Deploy to Cloud Foundry ☁️
working-directory: app/multi-tenant/central-space/cloud-cap-samples-java
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🚀 Deploying..."
echo "🔧 Installing Cloud Foundry CLI and plugins..."
# Install cf CLI plugin
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo tee /etc/apt/trusted.gpg.d/cloudfoundry.asc
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt update
sudo apt install cf8-cli
cf install-plugin multiapps -f
echo "✅ Cloud Foundry CLI setup complete!"
# Login to Cloud Foundry again to ensure session is active
echo "🔑 Logging in to Cloud Foundry..."
cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s "$CF_SPACE" > /dev/null
echo "✅ Logged in successfully!"
# Deploy the application
echo "📂 Current directory.."
pwd
ls -lrth
echo "▶️ Running cf deploy..."
cf deploy mta_archives/bookshop-mt_1.0.0.mtar -f
echo "✅ Deployment complete!"
# Parallel integration tests using matrix strategy
integration-test:
environment: dev
needs: deploy
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
tokenFlow: [namedUser, technicalUser]
tenant: [TENANT1, TENANT2]
testClass:
- IntegrationTest_SingleFacet
- IntegrationTest_MultipleFacet
- IntegrationTest_Chapters_MultipleFacet
steps:
- name: Checkout repository ✅
uses: actions/checkout@v6
- name: Set up Java 21 ☕
uses: actions/setup-java@v3
with:
java-version: 21
distribution: 'temurin'
cache: 'maven'
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI and jq 📦
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
echo "🔧 Installing Cloud Foundry CLI..."
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Fetch and Escape Client Details for single tenant 🔍
id: fetch_credentials
run: |
echo "Fetching client details for single tenant..."
service_instance_guid=$(cf service demoappjava-public-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret" ] || [ "$clientSecret" == "null" ]; then
echo "❌ Error: clientSecret is not set or is null"; exit 1;
fi
escapedClientSecret=$(echo "$clientSecret" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret"
clientID=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID" ] || [ "$clientID" == "null" ]; then
echo "❌ Error: clientID is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID"
echo "CLIENT_SECRET=$escapedClientSecret" >> $GITHUB_OUTPUT
echo "CLIENT_ID=$clientID" >> $GITHUB_OUTPUT
echo "✅ Client details fetched successfully!"
- name: Fetch and Escape Client Details for multi tenant 🔍
id: fetch_credentials_mt
run: |
echo "Fetching client details for multi tenant..."
service_instance_guid=$(cf service bookshop-mt-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret_mt=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret_mt" ] || [ "$clientSecret_mt" == "null" ]; then
echo "❌ Error: clientSecret_mt is not set or is null"; exit 1;
fi
escapedClientSecret_mt=$(echo "$clientSecret_mt" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret_mt"
clientID_mt=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID_mt" ] || [ "$clientID_mt" == "null" ]; then
echo "❌ Error: clientID_mt is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID_mt"
echo "CLIENT_SECRET_MT=$escapedClientSecret_mt" >> $GITHUB_OUTPUT
echo "CLIENT_ID_MT=$clientID_mt" >> $GITHUB_OUTPUT
echo "✅ Multi-tenant client details fetched successfully!"
- name: Fetch and Escape SDM CMIS Credentials 🔍
id: fetch_credentials_cmis
run: |
echo "🔄 Fetching SDM CMIS credentials from CF service binding..."
service_instance_guid=$(cf service sdm --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve SDM service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
app_guid=$(cf app bookshop-mt-srv --guid)
binding_guid=$(echo "$bindings_response" | jq -r \
--arg app_guid "$app_guid" \
'.resources[] | select(.relationships.app.data.guid == $app_guid) | .guid' | head -1)
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve SDM binding GUID for bookshop-mt-srv"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
cmis_client_secret=$(echo "$binding_details" | jq -r '.credentials.uaa.clientsecret // .credentials.clientsecret // empty')
if [ -z "$cmis_client_secret" ] || [ "$cmis_client_secret" == "null" ]; then
echo "❌ Error: SDM clientsecret is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_secret"
cmis_client_id=$(echo "$binding_details" | jq -r '.credentials.uaa.clientid // .credentials.clientid // empty')
if [ -z "$cmis_client_id" ] || [ "$cmis_client_id" == "null" ]; then
echo "❌ Error: SDM clientid is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_id"
cmis_url=$(echo "$binding_details" | jq -r '.credentials.uri // .credentials.endpoints.ecm_service // .credentials.url // empty')
if [ -z "$cmis_url" ]; then
echo "❌ Error: SDM CMIS URL not found in binding details"; exit 1;
fi
echo "::add-mask::$cmis_url"
printf 'CMIS_CLIENT_SECRET=%s\n' "$cmis_client_secret" >> $GITHUB_OUTPUT
printf 'CMIS_CLIENT_ID=%s\n' "$cmis_client_id" >> $GITHUB_OUTPUT
printf 'CMIS_URL=%s\n' "$cmis_url" >> $GITHUB_OUTPUT
echo "✅ SDM CMIS credentials fetched successfully!"
- name: Prepare credentials file 📝
env:
CLIENT_SECRET: ${{ steps.fetch_credentials.outputs.CLIENT_SECRET }}
CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }}
CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }}
CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }}
CMIS_CLIENT_ID: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_ID }}
CMIS_CLIENT_SECRET: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_SECRET }}
CMIS_URL_FROM_CF: ${{ steps.fetch_credentials_cmis.outputs.CMIS_URL }}
CF_ORG: ${{ secrets.CF_ORG }}
CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }}
AUTHURLMT1: ${{ secrets.AUTHURLMT1 }}
AUTHURLMT2: ${{ secrets.AUTHURLMT2 }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }}
NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }}
DEFAULTREPOSITORYID: ${{ secrets.DEFAULTREPOSITORYID }}
DEFAULTREPOSITORYIDMT: ${{ secrets.DEFAULTREPOSITORYIDMT }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
echo "🚀 Preparing credentials for ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..."
set +x
set -e
PROPERTIES_FILE="sdm/src/test/resources/credentials.properties"
appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com"
appUrlMT="$CF_ORG-$CF_SPACE-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com"
authUrl="$CAPAUTH_URL"
authUrlMT1="$AUTHURLMT1"
authUrlMT2="$AUTHURLMT2"
clientID="$CLIENT_ID"
clientSecret="$CLIENT_SECRET"
clientIDMT="$CLIENT_ID_MT"
clientSecretMT="$CLIENT_SECRET_MT"
username="$CF_USER"
password="$CF_PASSWORD"
noSDMRoleUsername="$NOSDMROLEUSERNAME"
noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD"
CMIS_URL="${{ env.CMIS_URL_FROM_CF }}"
cmisClientID="$CMIS_CLIENT_ID"
cmisClientSecret="$CMIS_CLIENT_SECRET"
defaultRepositoryID="$DEFAULTREPOSITORYID"
defaultRepositoryIDMT="$DEFAULTREPOSITORYIDMT"
echo "::add-mask::$clientSecret"
echo "::add-mask::$clientID"
echo "::add-mask::$clientSecretMT"
echo "::add-mask::$clientIDMT"
echo "::add-mask::$username"
echo "::add-mask::$password"
echo "::add-mask::$noSDMRoleUsername"
echo "::add-mask::$noSDMRoleUserPassword"
echo "::add-mask::$CMIS_URL"
echo "::add-mask::$cmisClientID"
echo "::add-mask::$cmisClientSecret"
if [ -z "$appUrl" ]; then echo "❌ Error: appUrl is not set"; exit 1; fi
if [ -z "$appUrlMT" ]; then echo "❌ Error: appUrlMT is not set"; exit 1; fi
if [ -z "$authUrl" ]; then echo "❌ Error: authUrl is not set"; exit 1; fi
if [ -z "$authUrlMT1" ]; then echo "❌ Error: authUrlMT1 is not set"; exit 1; fi
if [ -z "$authUrlMT2" ]; then echo "❌ Error: authUrlMT2 is not set"; exit 1; fi
if [ -z "$clientID" ]; then echo "❌ Error: clientID is not set"; exit 1; fi
if [ -z "$clientSecret" ]; then echo "❌ Error: clientSecret is not set"; exit 1; fi
if [ -z "$clientIDMT" ]; then echo "❌ Error: clientIDMT is not set"; exit 1; fi
if [ -z "$clientSecretMT" ]; then echo "❌ Error: clientSecretMT is not set"; exit 1; fi
if [ -z "$username" ]; then echo "❌ Error: username is not set"; exit 1; fi
if [ -z "$password" ]; then echo "❌ Error: password is not set"; exit 1; fi
if [ -z "$noSDMRoleUsername" ]; then echo "❌ Error: noSDMRoleUsername is not set"; exit 1; fi
if [ -z "$noSDMRoleUserPassword" ]; then echo "❌ Error: noSDMRoleUserPassword is not set"; exit 1; fi
if [ -z "$CMIS_URL" ]; then echo "❌ Error: CMIS_URL is not set"; exit 1; fi
if [ -z "$cmisClientID" ]; then echo "❌ Error: cmisClientID is not set"; exit 1; fi
if [ -z "$cmisClientSecret" ]; then echo "❌ Error: cmisClientSecret is not set"; exit 1; fi
cat > "$PROPERTIES_FILE" <<EOL
appUrl=$appUrl
appUrlMT=$appUrlMT
authUrl=$authUrl
authUrlMT1=$authUrlMT1
authUrlMT2=$authUrlMT2
clientID=$clientID
clientSecret=$clientSecret
clientIDMT=$clientIDMT
clientSecretMT=$clientSecretMT
username=$username
password=$password
noSDMRoleUsername=$noSDMRoleUsername
noSDMRoleUserPassword=$noSDMRoleUserPassword
CMIS_URL=$CMIS_URL
cmisClientID=$cmisClientID
cmisClientSecret=$cmisClientSecret
defaultRepositoryID=$defaultRepositoryID
defaultRepositoryIDMT=$defaultRepositoryIDMT
EOL
echo "✅ Credentials file prepared!"
- name: Download virus test file 📥
run: |
curl -fSL "http://www.eicar.org/download/eicar.com.txt" -o "sdm/eicar.com.txt"
sleep 5
if [ -f "sdm/eicar.com.txt" ]; then
FILE_SIZE=$(stat -c '%s' "sdm/eicar.com.txt")
echo "File exists — Size: $FILE_SIZE bytes"
else
echo "❌ File NOT found at path: sdm/eicar.com.txt"
exit 1
fi
- name: Run integration tests (${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}) 🎯
run: |
echo "🎯 Running Maven integration tests: testClass=${{ matrix.testClass }}, tokenFlow=${{ matrix.tokenFlow }}, tenant=${{ matrix.tenant }}"
MAX_RETRIES=3
ATTEMPT=0
EXIT_CODE=1
while [ $ATTEMPT -lt $MAX_RETRIES ]; do
ATTEMPT=$((ATTEMPT + 1))
echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..."
if mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Deicar.file.path=eicar.com.txt -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then
echo "✅ Tests passed on attempt $ATTEMPT!"
EXIT_CODE=0
break
else
if [ $ATTEMPT -lt $MAX_RETRIES ]; then
echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..."
sleep 30
else
echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}."
fi
fi
done
exit $EXIT_CODE
- name: Upload test results 📊
if: "!cancelled()"
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.testClass }}-${{ matrix.tokenFlow }}-${{ matrix.tenant }}
path: |
sdm/target/surefire-reports/
sdm/target/failsafe-reports/
retention-days: 7
# Single-job setup: switch CF app to versioned repo BEFORE matrix tests run.
# Avoids race condition where parallel matrix entries try to restage the same app simultaneously.
versioned-setup:
environment: dev
runs-on: ubuntu-latest
needs: integration-test
steps:
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI 🔧
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Switch to versioned repository 🔄
env:
VERSIONEDREPOSITORYID: ${{ secrets.VERSIONEDREPOSITORYID }}
run: |
APP_GUID=$(cf app bookshop-mt-srv --guid)
CURRENT=$(cf curl "/v3/apps/${APP_GUID}/environment_variables" | jq -r '.var.REPOSITORY_ID // empty')
if [ "$CURRENT" != "$VERSIONEDREPOSITORYID" ]; then
echo "🔄 Switching REPOSITORY_ID to versioned repository..."
cf set-env bookshop-mt-srv REPOSITORY_ID "$VERSIONEDREPOSITORYID"
echo "🔄 Restaging application..."
cf restage bookshop-mt-srv > /dev/null 2>&1
echo "✅ Switched to versioned repository!"
else
echo "✅ Repository already set to versioned, skipping restage"
fi
# Versioned tests run in parallel against the already-switched repo
# Skipped if integration-test or versioned-setup fails
versioned-test:
environment: dev
runs-on: ubuntu-latest
needs: versioned-setup
strategy:
fail-fast: false
matrix:
tokenFlow: [namedUser, technicalUser]
tenant: [TENANT1, TENANT2]
testClass:
- IntegrationTest_SingleFacet_VersionedRepository
- IntegrationTest_MultipleFacet_VersionedRepository
- IntegrationTest_Chapters_MultipleFacet_VersionedRepository
steps:
- name: Checkout repository 📁
uses: actions/checkout@v6
- name: Set up Java 17 ☕
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'temurin'
cache: 'maven'
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI 🔧
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Fetch and Escape Client Details for single tenant 🔍
id: fetch_credentials
run: |
service_instance_guid=$(cf service demoappjava-public-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret" ] || [ "$clientSecret" == "null" ]; then
echo "❌ Error: clientSecret is not set or is null"; exit 1;
fi
escapedClientSecret=$(echo "$clientSecret" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret"
clientID=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID" ] || [ "$clientID" == "null" ]; then
echo "❌ Error: clientID is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID"
echo "CLIENT_SECRET=$escapedClientSecret" >> $GITHUB_OUTPUT
echo "CLIENT_ID=$clientID" >> $GITHUB_OUTPUT
- name: Fetch and Escape Client Details for multi tenant 🔍
id: fetch_credentials_mt
run: |
service_instance_guid=$(cf service bookshop-mt-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret_mt=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret_mt" ] || [ "$clientSecret_mt" == "null" ]; then
echo "❌ Error: clientSecret_mt is not set or is null"; exit 1;
fi
escapedClientSecret_mt=$(echo "$clientSecret_mt" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret_mt"
clientID_mt=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID_mt" ] || [ "$clientID_mt" == "null" ]; then
echo "❌ Error: clientID_mt is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID_mt"
echo "CLIENT_SECRET_MT=$escapedClientSecret_mt" >> $GITHUB_OUTPUT
echo "CLIENT_ID_MT=$clientID_mt" >> $GITHUB_OUTPUT
- name: Fetch and Escape SDM CMIS Credentials 🔍
id: fetch_credentials_cmis
run: |
echo "🔄 Fetching SDM CMIS credentials from CF service binding..."
service_instance_guid=$(cf service sdm --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve SDM service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
app_guid=$(cf app bookshop-mt-srv --guid)
binding_guid=$(echo "$bindings_response" | jq -r \
--arg app_guid "$app_guid" \
'.resources[] | select(.relationships.app.data.guid == $app_guid) | .guid' | head -1)
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve SDM binding GUID for bookshop-mt-srv"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
cmis_client_secret=$(echo "$binding_details" | jq -r '.credentials.uaa.clientsecret // .credentials.clientsecret // empty')
if [ -z "$cmis_client_secret" ] || [ "$cmis_client_secret" == "null" ]; then
echo "❌ Error: SDM clientsecret is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_secret"
cmis_client_id=$(echo "$binding_details" | jq -r '.credentials.uaa.clientid // .credentials.clientid // empty')
if [ -z "$cmis_client_id" ] || [ "$cmis_client_id" == "null" ]; then
echo "❌ Error: SDM clientid is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_id"
cmis_url=$(echo "$binding_details" | jq -r '.credentials.uri // .credentials.endpoints.ecm_service // .credentials.url // empty')
if [ -z "$cmis_url" ]; then
echo "❌ Error: SDM CMIS URL not found in binding details"; exit 1;
fi
echo "::add-mask::$cmis_url"
printf 'CMIS_CLIENT_SECRET=%s\n' "$cmis_client_secret" >> $GITHUB_OUTPUT
printf 'CMIS_CLIENT_ID=%s\n' "$cmis_client_id" >> $GITHUB_OUTPUT
printf 'CMIS_URL=%s\n' "$cmis_url" >> $GITHUB_OUTPUT
echo "✅ SDM CMIS credentials fetched successfully!"
- name: Run versioned integration tests 🎯 (${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }})
env:
CLIENT_SECRET: ${{ steps.fetch_credentials.outputs.CLIENT_SECRET }}
CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }}
CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }}
CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }}
CMIS_CLIENT_ID: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_ID }}
CMIS_CLIENT_SECRET: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_SECRET }}
CMIS_URL_FROM_CF: ${{ steps.fetch_credentials_cmis.outputs.CMIS_URL }}
CF_ORG: ${{ secrets.CF_ORG }}
CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }}
AUTHURLMT1: ${{ secrets.AUTHURLMT1 }}
AUTHURLMT2: ${{ secrets.AUTHURLMT2 }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }}
NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }}
VERSIONEDREPOSITORYID: ${{ secrets.VERSIONEDREPOSITORYID }}
VIRUSSCANREPOSITORYID: ${{ secrets.VIRUSSCANREPOSITORYID }}
DEFAULTREPOSITORYID: ${{ secrets.DEFAULTREPOSITORYID }}
DEFAULTREPOSITORYIDMT: ${{ secrets.DEFAULTREPOSITORYIDMT }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set -e
PROPERTIES_FILE="sdm/src/test/resources/credentials.properties"
appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com"
appUrlMT="$CF_ORG-$CF_SPACE-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com"
authUrl="$CAPAUTH_URL"
authUrlMT1="$AUTHURLMT1"
authUrlMT2="$AUTHURLMT2"
clientID="$CLIENT_ID"
clientSecret="$CLIENT_SECRET"
clientIDMT="$CLIENT_ID_MT"
clientSecretMT="$CLIENT_SECRET_MT"
username="$CF_USER"
password="$CF_PASSWORD"
noSDMRoleUsername="$NOSDMROLEUSERNAME"
noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD"
versionedRepositoryID="$VERSIONEDREPOSITORYID"
virusScanRepositoryID="$VIRUSSCANREPOSITORYID"
defaultRepositoryID="$DEFAULTREPOSITORYID"
defaultRepositoryIDMT="$DEFAULTREPOSITORYIDMT"
CMIS_URL="$CMIS_URL_FROM_CF"
cmisClientID="$CMIS_CLIENT_ID"
cmisClientSecret="$CMIS_CLIENT_SECRET"
cat > "$PROPERTIES_FILE" <<EOL
appUrl=$appUrl
appUrlMT=$appUrlMT
authUrl=$authUrl
authUrlMT1=$authUrlMT1
authUrlMT2=$authUrlMT2
clientID=$clientID
clientSecret=$clientSecret
clientIDMT=$clientIDMT
clientSecretMT=$clientSecretMT
username=$username
password=$password
noSDMRoleUsername=$noSDMRoleUsername
noSDMRoleUserPassword=$noSDMRoleUserPassword
versionedRepositoryID=$versionedRepositoryID
virusScanRepositoryID=$virusScanRepositoryID
defaultRepositoryID=$defaultRepositoryID
defaultRepositoryIDMT=$defaultRepositoryIDMT
CMIS_URL=$CMIS_URL
cmisClientID=$cmisClientID
cmisClientSecret=$cmisClientSecret
EOL
echo "🎯 Running versioned integration tests for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..."
MAX_RETRIES=3
ATTEMPT=0
EXIT_CODE=1
while [ $ATTEMPT -lt $MAX_RETRIES ]; do
ATTEMPT=$((ATTEMPT + 1))
echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..."
if mvn clean verify -P integration-tests \
-DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} \
-DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then
echo "✅ Tests passed on attempt $ATTEMPT!"
EXIT_CODE=0
break
else
if [ $ATTEMPT -lt $MAX_RETRIES ]; then
echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..."
sleep 30
else
echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}."
fi
fi
done
exit $EXIT_CODE
# Single-job setup: switch CF app to virus scan repo BEFORE matrix tests run.
# Avoids race condition where parallel matrix entries try to restage the same app simultaneously.
virusscan-setup:
environment: dev
runs-on: ubuntu-latest
needs: versioned-test
steps:
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI 🔧
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Switch to virus scan repository 🔄
env:
VIRUSSCANREPOSITORYID: ${{ secrets.VIRUSSCANREPOSITORYID }}
run: |
APP_GUID=$(cf app bookshop-mt-srv --guid)
CURRENT=$(cf curl "/v3/apps/${APP_GUID}/environment_variables" | jq -r '.var.REPOSITORY_ID // empty')
if [ "$CURRENT" != "$VIRUSSCANREPOSITORYID" ]; then
echo "🔄 Switching REPOSITORY_ID to virus scan repository..."
cf set-env bookshop-mt-srv REPOSITORY_ID "$VIRUSSCANREPOSITORYID"
echo "🔄 Restaging application..."
cf restage bookshop-mt-srv > /dev/null 2>&1
echo "✅ Switched to virus scan repository!"
else
echo "✅ Repository already set to virus scan, skipping restage"
fi
# Virus scan tests run in parallel against the already-switched repo
# Skipped if versioned-test or virusscan-setup fails
virusscan-test:
environment: dev
runs-on: ubuntu-latest
needs: virusscan-setup
strategy:
fail-fast: false
matrix:
tokenFlow: [namedUser, technicalUser]
tenant: [TENANT1, TENANT2]
testClass:
- IntegrationTest_SingleFacet_Virus
- IntegrationTest_MultipleFacet_Virus
- IntegrationTest_Chapters_MultipleFacet_Virus
steps:
- name: Checkout repository 📁
uses: actions/checkout@v6
- name: Set up Java 17 ☕
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'temurin'
cache: 'maven'
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI 🔧
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Fetch and Escape Client Details for single tenant 🔍
id: fetch_credentials
run: |
service_instance_guid=$(cf service demoappjava-public-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret" ] || [ "$clientSecret" == "null" ]; then
echo "❌ Error: clientSecret is not set or is null"; exit 1;
fi
escapedClientSecret=$(echo "$clientSecret" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret"
clientID=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID" ] || [ "$clientID" == "null" ]; then
echo "❌ Error: clientID is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID"
echo "CLIENT_SECRET=$escapedClientSecret" >> $GITHUB_OUTPUT
echo "CLIENT_ID=$clientID" >> $GITHUB_OUTPUT
- name: Fetch and Escape Client Details for multi tenant 🔍
id: fetch_credentials_mt
run: |
service_instance_guid=$(cf service bookshop-mt-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret_mt=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret_mt" ] || [ "$clientSecret_mt" == "null" ]; then
echo "❌ Error: clientSecret_mt is not set or is null"; exit 1;
fi
escapedClientSecret_mt=$(echo "$clientSecret_mt" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret_mt"
clientID_mt=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID_mt" ] || [ "$clientID_mt" == "null" ]; then
echo "❌ Error: clientID_mt is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID_mt"
echo "CLIENT_SECRET_MT=$escapedClientSecret_mt" >> $GITHUB_OUTPUT
echo "CLIENT_ID_MT=$clientID_mt" >> $GITHUB_OUTPUT
- name: Fetch and Escape SDM CMIS Credentials 🔍
id: fetch_credentials_cmis
run: |
echo "🔄 Fetching SDM CMIS credentials from CF service binding..."
service_instance_guid=$(cf service sdm --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve SDM service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
app_guid=$(cf app bookshop-mt-srv --guid)
binding_guid=$(echo "$bindings_response" | jq -r \
--arg app_guid "$app_guid" \
'.resources[] | select(.relationships.app.data.guid == $app_guid) | .guid' | head -1)
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve SDM binding GUID for bookshop-mt-srv"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
cmis_client_secret=$(echo "$binding_details" | jq -r '.credentials.uaa.clientsecret // .credentials.clientsecret // empty')
if [ -z "$cmis_client_secret" ] || [ "$cmis_client_secret" == "null" ]; then
echo "❌ Error: SDM clientsecret is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_secret"
cmis_client_id=$(echo "$binding_details" | jq -r '.credentials.uaa.clientid // .credentials.clientid // empty')
if [ -z "$cmis_client_id" ] || [ "$cmis_client_id" == "null" ]; then
echo "❌ Error: SDM clientid is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_id"
cmis_url=$(echo "$binding_details" | jq -r '.credentials.uri // .credentials.endpoints.ecm_service // .credentials.url // empty')
if [ -z "$cmis_url" ]; then
echo "❌ Error: SDM CMIS URL not found in binding details"; exit 1;
fi
echo "::add-mask::$cmis_url"
printf 'CMIS_CLIENT_SECRET=%s\n' "$cmis_client_secret" >> $GITHUB_OUTPUT
printf 'CMIS_CLIENT_ID=%s\n' "$cmis_client_id" >> $GITHUB_OUTPUT
printf 'CMIS_URL=%s\n' "$cmis_url" >> $GITHUB_OUTPUT
echo "✅ SDM CMIS credentials fetched successfully!"
- name: Download virus test file 📥
run: |
curl -fSL "http://www.eicar.org/download/eicar.com.txt" -o "sdm/eicar.com.txt"
sleep 5
if [ -f "sdm/eicar.com.txt" ]; then
FILE_SIZE=$(stat -c '%s' "sdm/eicar.com.txt")
echo "File exists — Size: $FILE_SIZE bytes"
else
echo "❌ File NOT found at path: sdm/eicar.com.txt"
exit 1
fi
- name: Run virus scan integration tests 🎯 (${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }})
env:
CLIENT_SECRET: ${{ steps.fetch_credentials.outputs.CLIENT_SECRET }}
CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }}
CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }}
CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }}
CMIS_CLIENT_ID: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_ID }}
CMIS_CLIENT_SECRET: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_SECRET }}
CMIS_URL_FROM_CF: ${{ steps.fetch_credentials_cmis.outputs.CMIS_URL }}
CF_ORG: ${{ secrets.CF_ORG }}
CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }}
AUTHURLMT1: ${{ secrets.AUTHURLMT1 }}
AUTHURLMT2: ${{ secrets.AUTHURLMT2 }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }}
NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }}
VERSIONEDREPOSITORYID: ${{ secrets.VERSIONEDREPOSITORYID }}
VIRUSSCANREPOSITORYID: ${{ secrets.VIRUSSCANREPOSITORYID }}
DEFAULTREPOSITORYID: ${{ secrets.DEFAULTREPOSITORYID }}
DEFAULTREPOSITORYIDMT: ${{ secrets.DEFAULTREPOSITORYIDMT }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set -e
PROPERTIES_FILE="sdm/src/test/resources/credentials.properties"
appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com"
appUrlMT="$CF_ORG-$CF_SPACE-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com"
authUrl="$CAPAUTH_URL"
authUrlMT1="$AUTHURLMT1"
authUrlMT2="$AUTHURLMT2"
clientID="$CLIENT_ID"
clientSecret="$CLIENT_SECRET"
clientIDMT="$CLIENT_ID_MT"
clientSecretMT="$CLIENT_SECRET_MT"
username="$CF_USER"
password="$CF_PASSWORD"
noSDMRoleUsername="$NOSDMROLEUSERNAME"
noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD"
versionedRepositoryID="$VERSIONEDREPOSITORYID"
virusScanRepositoryID="$VIRUSSCANREPOSITORYID"
defaultRepositoryID="$DEFAULTREPOSITORYID"
defaultRepositoryIDMT="$DEFAULTREPOSITORYIDMT"
CMIS_URL="$CMIS_URL_FROM_CF"
cmisClientID="$CMIS_CLIENT_ID"
cmisClientSecret="$CMIS_CLIENT_SECRET"
cat > "$PROPERTIES_FILE" <<EOL
appUrl=$appUrl
appUrlMT=$appUrlMT
authUrl=$authUrl
authUrlMT1=$authUrlMT1
authUrlMT2=$authUrlMT2
clientID=$clientID
clientSecret=$clientSecret
clientIDMT=$clientIDMT
clientSecretMT=$clientSecretMT
username=$username
password=$password
noSDMRoleUsername=$noSDMRoleUsername
noSDMRoleUserPassword=$noSDMRoleUserPassword
versionedRepositoryID=$versionedRepositoryID
virusScanRepositoryID=$virusScanRepositoryID
defaultRepositoryID=$defaultRepositoryID
defaultRepositoryIDMT=$defaultRepositoryIDMT
CMIS_URL=$CMIS_URL
cmisClientID=$cmisClientID
cmisClientSecret=$cmisClientSecret
EOL
echo "🎯 Running virus scan integration tests for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..."
MAX_RETRIES=3
ATTEMPT=0
EXIT_CODE=1
while [ $ATTEMPT -lt $MAX_RETRIES ]; do
ATTEMPT=$((ATTEMPT + 1))
echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..."
if mvn clean verify -P integration-tests \
-DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} \
-DskipUnitTests -Deicar.file.path=eicar.com.txt \
-Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then
echo "✅ Tests passed on attempt $ATTEMPT!"
EXIT_CODE=0
break
else
if [ $ATTEMPT -lt $MAX_RETRIES ]; then
echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..."
sleep 30
else
echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}."
fi
fi
done
exit $EXIT_CODE
# Revert repository to default after virus scan tests
# Runs if either setup job actually switched the repo (i.e. didn't get skipped)
virusscan-cleanup:
environment: dev
runs-on: ubuntu-latest
needs: [versioned-setup, versioned-test, virusscan-setup, virusscan-test]
if: always() && (needs.versioned-setup.result != 'skipped' || needs.virusscan-setup.result != 'skipped')
steps:
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI 🔧
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Revert to Default Repository 🔄
env:
DEFAULTREPOSITORYIDMT: ${{ secrets.DEFAULTREPOSITORYIDMT }}
run: |
echo "🔄 Reverting REPOSITORY_ID to default repository..."
cf set-env bookshop-mt-srv REPOSITORY_ID "$DEFAULTREPOSITORYIDMT"
echo "🔄 Restaging application..."
cf restage bookshop-mt-srv > /dev/null 2>&1
echo "✅ Reverted to default repository!"
# Repo-specific tests run one at a time (max-parallel: 1) so each shows individually in UI
# DISABLED: set if to true to re-enable
repospecific-test:
environment: dev
runs-on: ubuntu-latest
needs: [virusscan-test, virusscan-cleanup]
if: false
strategy:
fail-fast: false
max-parallel: 1
matrix:
tokenFlow: [namedUser, technicalUser]
tenant: [TENANT1, TENANT2]
testClass:
- IntegrationTest_SingleFacet_RepoSpecific
- IntegrationTest_MultipleFacet_RepoSpecific
- IntegrationTest_Chapters_MultipleFacet_RepoSpecific
steps:
- name: Checkout repository 📁
uses: actions/checkout@v6
- name: Set up Java 17 ☕
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'temurin'
cache: 'maven'
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI 🔧
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Fetch and Escape Client Details for single tenant 🔍
id: fetch_credentials
run: |
service_instance_guid=$(cf service demoappjava-public-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret" ] || [ "$clientSecret" == "null" ]; then
echo "❌ Error: clientSecret is not set or is null"; exit 1;
fi
escapedClientSecret=$(echo "$clientSecret" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret"
clientID=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID" ] || [ "$clientID" == "null" ]; then
echo "❌ Error: clientID is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID"
echo "CLIENT_SECRET=$escapedClientSecret" >> $GITHUB_OUTPUT
echo "CLIENT_ID=$clientID" >> $GITHUB_OUTPUT
- name: Fetch and Escape Client Details for multi tenant 🔍
id: fetch_credentials_mt
run: |
service_instance_guid=$(cf service bookshop-mt-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret_mt=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret_mt" ] || [ "$clientSecret_mt" == "null" ]; then
echo "❌ Error: clientSecret_mt is not set or is null"; exit 1;
fi
escapedClientSecret_mt=$(echo "$clientSecret_mt" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret_mt"
clientID_mt=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID_mt" ] || [ "$clientID_mt" == "null" ]; then
echo "❌ Error: clientID_mt is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID_mt"
echo "CLIENT_SECRET_MT=$escapedClientSecret_mt" >> $GITHUB_OUTPUT
echo "CLIENT_ID_MT=$clientID_mt" >> $GITHUB_OUTPUT
- name: Fetch and Escape SDM CMIS Credentials 🔍
id: fetch_credentials_cmis
run: |
echo "🔄 Fetching SDM CMIS credentials from CF service binding..."
service_instance_guid=$(cf service sdm --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve SDM service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
app_guid=$(cf app bookshop-mt-srv --guid)
binding_guid=$(echo "$bindings_response" | jq -r \
--arg app_guid "$app_guid" \
'.resources[] | select(.relationships.app.data.guid == $app_guid) | .guid' | head -1)
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve SDM binding GUID for bookshop-mt-srv"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
cmis_client_secret=$(echo "$binding_details" | jq -r '.credentials.uaa.clientsecret // .credentials.clientsecret // empty')
if [ -z "$cmis_client_secret" ] || [ "$cmis_client_secret" == "null" ]; then
echo "❌ Error: SDM clientsecret is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_secret"
cmis_client_id=$(echo "$binding_details" | jq -r '.credentials.uaa.clientid // .credentials.clientid // empty')
if [ -z "$cmis_client_id" ] || [ "$cmis_client_id" == "null" ]; then
echo "❌ Error: SDM clientid is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_id"
cmis_url=$(echo "$binding_details" | jq -r '.credentials.uri // .credentials.endpoints.ecm_service // .credentials.url // empty')
if [ -z "$cmis_url" ]; then
echo "❌ Error: SDM CMIS URL not found in binding details"; exit 1;
fi
echo "::add-mask::$cmis_url"
printf 'CMIS_CLIENT_SECRET=%s\n' "$cmis_client_secret" >> $GITHUB_OUTPUT
printf 'CMIS_CLIENT_ID=%s\n' "$cmis_client_id" >> $GITHUB_OUTPUT
printf 'CMIS_URL=%s\n' "$cmis_url" >> $GITHUB_OUTPUT
echo "✅ SDM CMIS credentials fetched successfully!"
- name: Run repo-specific integration tests 🎯 (${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }})
env:
CLIENT_SECRET: ${{ steps.fetch_credentials.outputs.CLIENT_SECRET }}
CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }}
CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }}
CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }}
CMIS_CLIENT_ID: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_ID }}
CMIS_CLIENT_SECRET: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_SECRET }}
CMIS_URL_FROM_CF: ${{ steps.fetch_credentials_cmis.outputs.CMIS_URL }}
CF_ORG: ${{ secrets.CF_ORG }}
CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }}
AUTHURLMT1: ${{ secrets.AUTHURLMT1 }}
AUTHURLMT2: ${{ secrets.AUTHURLMT2 }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }}
NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }}
VERSIONEDREPOSITORYID: ${{ secrets.VERSIONEDREPOSITORYID }}
VIRUSSCANREPOSITORYID: ${{ secrets.VIRUSSCANREPOSITORYID }}
DEFAULTREPOSITORYID: ${{ secrets.DEFAULTREPOSITORYID }}
DEFAULTREPOSITORYIDMT: ${{ secrets.DEFAULTREPOSITORYIDMT }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set -e
PROPERTIES_FILE="sdm/src/test/resources/credentials.properties"
appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com"
appUrlMT="$CF_ORG-$CF_SPACE-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com"
authUrl="$CAPAUTH_URL"
authUrlMT1="$AUTHURLMT1"
authUrlMT2="$AUTHURLMT2"
clientID="$CLIENT_ID"
clientSecret="$CLIENT_SECRET"
clientIDMT="$CLIENT_ID_MT"
clientSecretMT="$CLIENT_SECRET_MT"
username="$CF_USER"
password="$CF_PASSWORD"
noSDMRoleUsername="$NOSDMROLEUSERNAME"
noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD"
versionedRepositoryID="$VERSIONEDREPOSITORYID"
virusScanRepositoryID="$VIRUSSCANREPOSITORYID"
defaultRepositoryID="$DEFAULTREPOSITORYID"
defaultRepositoryIDMT="$DEFAULTREPOSITORYIDMT"
CMIS_URL="$CMIS_URL_FROM_CF"
cmisClientID="$CMIS_CLIENT_ID"
cmisClientSecret="$CMIS_CLIENT_SECRET"
cat > "$PROPERTIES_FILE" <<EOL
appUrl=$appUrl
appUrlMT=$appUrlMT
authUrl=$authUrl
authUrlMT1=$authUrlMT1
authUrlMT2=$authUrlMT2
clientID=$clientID
clientSecret=$clientSecret
clientIDMT=$clientIDMT
clientSecretMT=$clientSecretMT
username=$username
password=$password
noSDMRoleUsername=$noSDMRoleUsername
noSDMRoleUserPassword=$noSDMRoleUserPassword
versionedRepositoryID=$versionedRepositoryID
virusScanRepositoryID=$virusScanRepositoryID
defaultRepositoryID=$defaultRepositoryID
defaultRepositoryIDMT=$defaultRepositoryIDMT
CMIS_URL=$CMIS_URL
cmisClientID=$cmisClientID
cmisClientSecret=$cmisClientSecret
EOL
echo "🎯 Running repo-specific integration tests for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..."
MAX_RETRIES=3
ATTEMPT=0
EXIT_CODE=1
while [ $ATTEMPT -lt $MAX_RETRIES ]; do
ATTEMPT=$((ATTEMPT + 1))
echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..."
if mvn clean verify -P integration-tests \
-DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} \
-DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then
echo "✅ Tests passed on attempt $ATTEMPT!"
EXIT_CODE=0
break
else
if [ $ATTEMPT -lt $MAX_RETRIES ]; then
echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..."
sleep 30
else
echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}."
fi
fi
done
exit $EXIT_CODE
# Subscription tests run one at a time (max-parallel: 1) so each shows individually in UI
# Skipped if virusscan-test or virusscan-cleanup fails
subscription-test:
environment: dev
runs-on: ubuntu-latest
needs: [virusscan-test, virusscan-cleanup]
strategy:
fail-fast: false
max-parallel: 1
matrix:
tenant: [TENANT1, TENANT2]
steps:
- name: Checkout repository 📁
uses: actions/checkout@v6
- name: Set up Java 17 ☕
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'temurin'
cache: 'maven'
- name: Cache CF CLI 📦
id: cache-cf-cli
uses: actions/cache@v4
with:
path: /usr/bin/cf8
key: cf-cli-v8-${{ runner.os }}
- name: Install Cloud Foundry CLI 🔧
if: steps.cache-cf-cli.outputs.cache-hit != 'true'
run: |
wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
sudo apt-get update
sudo apt-get install cf8-cli
- name: Install jq 📦
run: |
if ! command -v jq &> /dev/null; then
sudo apt-get update && sudo apt-get install -y jq
fi
- name: Install BTP CLI 🔧
run: |
echo "🔄 Installing SAP BTP CLI..."
curl -fsSL https://cli.btp.cloud.sap/btpcli-install.sh | bash
BTP_BIN=$(find "$HOME/bin" /usr/local/bin -maxdepth 1 -name 'btp' -type f 2>/dev/null | head -1)
if [ -z "$BTP_BIN" ]; then
echo "❌ btp binary not found after install script."
exit 1
fi
if [ "$BTP_BIN" != "/usr/local/bin/btp" ]; then
sudo install -m 755 "$BTP_BIN" /usr/local/bin/btp
fi
btp --version
echo "✅ BTP CLI installed successfully!"
- name: Login to Cloud Foundry 🔑
env:
CF_API: ${{ secrets.CF_API }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
CF_ORG: ${{ secrets.CF_ORG }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set +x
echo "::add-mask::$CF_API"
echo "::add-mask::$CF_USER"
echo "::add-mask::$CF_PASSWORD"
echo "::add-mask::$CF_ORG"
echo "::add-mask::$CF_SPACE"
echo "🔄 Logging in to Cloud Foundry using space: $CF_SPACE"
cf login -a "$CF_API" \
-u "$CF_USER" \
-p "$CF_PASSWORD" \
-o "$CF_ORG" \
-s $CF_SPACE > /dev/null
- name: Fetch and Escape Client Details for single tenant 🔍
id: fetch_credentials
run: |
service_instance_guid=$(cf service demoappjava-public-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret" ] || [ "$clientSecret" == "null" ]; then
echo "❌ Error: clientSecret is not set or is null"; exit 1;
fi
escapedClientSecret=$(echo "$clientSecret" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret"
clientID=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID" ] || [ "$clientID" == "null" ]; then
echo "❌ Error: clientID is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID"
echo "CLIENT_SECRET=$escapedClientSecret" >> $GITHUB_OUTPUT
echo "CLIENT_ID=$clientID" >> $GITHUB_OUTPUT
- name: Fetch and Escape Client Details for multi tenant 🔍
id: fetch_credentials_mt
run: |
service_instance_guid=$(cf service bookshop-mt-uaa --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
binding_guid=$(echo "$bindings_response" | jq -r '.resources[0].guid')
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve binding GUID"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
clientSecret_mt=$(echo "$binding_details" | jq -r '.credentials.clientsecret')
if [ -z "$clientSecret_mt" ] || [ "$clientSecret_mt" == "null" ]; then
echo "❌ Error: clientSecret_mt is not set or is null"; exit 1;
fi
escapedClientSecret_mt=$(echo "$clientSecret_mt" | sed 's/\$/\\$/g')
echo "::add-mask::$escapedClientSecret_mt"
clientID_mt=$(echo "$binding_details" | jq -r '.credentials.clientid')
if [ -z "$clientID_mt" ] || [ "$clientID_mt" == "null" ]; then
echo "❌ Error: clientID_mt is not set or is null"; exit 1;
fi
echo "::add-mask::$clientID_mt"
echo "CLIENT_SECRET_MT=$escapedClientSecret_mt" >> $GITHUB_OUTPUT
echo "CLIENT_ID_MT=$clientID_mt" >> $GITHUB_OUTPUT
- name: Fetch and Escape SDM CMIS Credentials 🔍
id: fetch_credentials_cmis
run: |
echo "🔄 Fetching SDM CMIS credentials from CF service binding..."
service_instance_guid=$(cf service sdm --guid)
if [ -z "$service_instance_guid" ]; then
echo "❌ Error: Unable to retrieve SDM service instance GUID"; exit 1;
fi
bindings_response=$(cf curl "/v3/service_credential_bindings?service_instance_guids=${service_instance_guid}")
app_guid=$(cf app bookshop-mt-srv --guid)
binding_guid=$(echo "$bindings_response" | jq -r \
--arg app_guid "$app_guid" \
'.resources[] | select(.relationships.app.data.guid == $app_guid) | .guid' | head -1)
if [ -z "$binding_guid" ]; then
echo "❌ Error: Unable to retrieve SDM binding GUID for bookshop-mt-srv"; exit 1;
fi
binding_details=$(cf curl "/v3/service_credential_bindings/${binding_guid}/details")
cmis_client_secret=$(echo "$binding_details" | jq -r '.credentials.uaa.clientsecret // .credentials.clientsecret // empty')
if [ -z "$cmis_client_secret" ] || [ "$cmis_client_secret" == "null" ]; then
echo "❌ Error: SDM clientsecret is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_secret"
cmis_client_id=$(echo "$binding_details" | jq -r '.credentials.uaa.clientid // .credentials.clientid // empty')
if [ -z "$cmis_client_id" ] || [ "$cmis_client_id" == "null" ]; then
echo "❌ Error: SDM clientid is not set or is null"; exit 1;
fi
echo "::add-mask::$cmis_client_id"
cmis_url=$(echo "$binding_details" | jq -r '.credentials.uri // .credentials.endpoints.ecm_service // .credentials.url // empty')
if [ -z "$cmis_url" ]; then
echo "❌ Error: SDM CMIS URL not found in binding details"; exit 1;
fi
echo "::add-mask::$cmis_url"
printf 'CMIS_CLIENT_SECRET=%s\n' "$cmis_client_secret" >> $GITHUB_OUTPUT
printf 'CMIS_CLIENT_ID=%s\n' "$cmis_client_id" >> $GITHUB_OUTPUT
printf 'CMIS_URL=%s\n' "$cmis_url" >> $GITHUB_OUTPUT
echo "✅ SDM CMIS credentials fetched successfully!"
- name: Run subscription integration test 🎯 (${{ matrix.tenant }})
id: run_tests
env:
CLIENT_SECRET: ${{ steps.fetch_credentials.outputs.CLIENT_SECRET }}
CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }}
CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }}
CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }}
CMIS_CLIENT_ID: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_ID }}
CMIS_CLIENT_SECRET: ${{ steps.fetch_credentials_cmis.outputs.CMIS_CLIENT_SECRET }}
CMIS_URL_FROM_CF: ${{ steps.fetch_credentials_cmis.outputs.CMIS_URL }}
CF_ORG: ${{ secrets.CF_ORG }}
CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }}
AUTHURLMT1: ${{ secrets.AUTHURLMT1 }}
AUTHURLMT2: ${{ secrets.AUTHURLMT2 }}
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }}
NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }}
VERSIONEDREPOSITORYID: ${{ secrets.VERSIONEDREPOSITORYID }}
VIRUSSCANREPOSITORYID: ${{ secrets.VIRUSSCANREPOSITORYID }}
DEFAULTREPOSITORYID: ${{ secrets.DEFAULTREPOSITORYID }}
DEFAULTREPOSITORYIDMT: ${{ secrets.DEFAULTREPOSITORYIDMT }}
CONSUMERSUBACCOUNTIDMT1: ${{ secrets.CONSUMERSUBACCOUNTIDMT1 }}
CONSUMERSUBDOMAINMT1: ${{ secrets.CONSUMERSUBDOMAINMT1 }}
CONSUMERSUBACCOUNTIDMT2: ${{ secrets.CONSUMERSUBACCOUNTIDMT2 }}
CONSUMERSUBDOMAINMT2: ${{ secrets.CONSUMERSUBDOMAINMT2 }}
CONSUMERSUBDOMAINMT: ${{ secrets.CONSUMERSUBDOMAINMT }}
BTP_CLI_URL: ${{ secrets.BTP_CLI_URL }}
BTP_GLOBAL_ACCOUNT_SUBDOMAIN: ${{ secrets.BTP_GLOBAL_ACCOUNT_SUBDOMAIN }}
CF_SPACE: ${{ secrets.CF_SPACE }}
run: |
set -e
PROPERTIES_FILE="sdm/src/test/resources/credentials.properties"
appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com"
appUrlMT="$CF_ORG-$CF_SPACE-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com"
authUrl="$CAPAUTH_URL"
authUrlMT1="$AUTHURLMT1"
authUrlMT2="$AUTHURLMT2"
clientID="$CLIENT_ID"
clientSecret="$CLIENT_SECRET"
clientIDMT="$CLIENT_ID_MT"
clientSecretMT="$CLIENT_SECRET_MT"
username="$CF_USER"
password="$CF_PASSWORD"
noSDMRoleUsername="$NOSDMROLEUSERNAME"
noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD"
versionedRepositoryID="$VERSIONEDREPOSITORYID"
virusScanRepositoryID="$VIRUSSCANREPOSITORYID"
defaultRepositoryID="$DEFAULTREPOSITORYID"
defaultRepositoryIDMT="$DEFAULTREPOSITORYIDMT"
consumerSubaccountIdMT1="$CONSUMERSUBACCOUNTIDMT1"
consumerSubdomainMT1="$CONSUMERSUBDOMAINMT1"
consumerSubaccountIdMT2="$CONSUMERSUBACCOUNTIDMT2"
consumerSubdomainMT2="$CONSUMERSUBDOMAINMT2"
consumerSubdomainMT="$CONSUMERSUBDOMAINMT"
CMIS_URL="$CMIS_URL_FROM_CF"
cmisClientID="$CMIS_CLIENT_ID"
cmisClientSecret="$CMIS_CLIENT_SECRET"
SAAS_APP_NAME="bookshop-mt-sdmgoogleworkspacedev-$CF_SPACE"
ROLE_COLLECTION_NAME="test-cases-role"
APP_ROLE_FILTER="bookshop-mt-sdmgoogleworkspacedev-$CF_SPACE"
cat > "$PROPERTIES_FILE" <<EOL
appUrl=$appUrl
appUrlMT=$appUrlMT
authUrl=$authUrl
authUrlMT1=$authUrlMT1
authUrlMT2=$authUrlMT2
clientID=$clientID
clientSecret=$clientSecret
clientIDMT=$clientIDMT
clientSecretMT=$clientSecretMT
username=$username
password=$password
noSDMRoleUsername=$noSDMRoleUsername
noSDMRoleUserPassword=$noSDMRoleUserPassword
versionedRepositoryID=$versionedRepositoryID
virusScanRepositoryID=$virusScanRepositoryID
defaultRepositoryID=$defaultRepositoryID
defaultRepositoryIDMT=$defaultRepositoryIDMT
consumerSubaccountIdMT1=$consumerSubaccountIdMT1
consumerSubdomainMT1=$consumerSubdomainMT1
consumerSubaccountIdMT2=$consumerSubaccountIdMT2
consumerSubdomainMT2=$consumerSubdomainMT2
CMIS_URL=$CMIS_URL
cmisClientID=$cmisClientID
cmisClientSecret=$cmisClientSecret
SAAS_APP_NAME=$SAAS_APP_NAME
ROLE_COLLECTION_NAME=$ROLE_COLLECTION_NAME
APP_ROLE_FILTER=$APP_ROLE_FILTER
BTP_CLI_URL=$BTP_CLI_URL
BTP_GLOBAL_ACCOUNT_SUBDOMAIN=$BTP_GLOBAL_ACCOUNT_SUBDOMAIN
EOL
echo "🎯 Running subscription test for ${{ matrix.tenant }}"
MAX_RETRIES=3
ATTEMPT=0
EXIT_CODE=1
while [ $ATTEMPT -lt $MAX_RETRIES ]; do
ATTEMPT=$((ATTEMPT + 1))
echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..."
if mvn clean verify -P integration-tests \
-DtokenFlow=technicalUser -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} \
-DskipUnitTests -Dfailsafe.includes="**/IntegrationTest_Subscription.java"; then
echo "✅ Tests passed on attempt $ATTEMPT!"
EXIT_CODE=0
break
else
if [ $ATTEMPT -lt $MAX_RETRIES ]; then
echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..."
sleep 30
else
echo "❌ All $MAX_RETRIES attempts failed for subscription test ${{ matrix.tenant }}."
fi
fi
done
exit $EXIT_CODE
# Summary job to aggregate results
test-summary:
environment: dev
runs-on: ubuntu-latest
needs: [integration-test, versioned-test, virusscan-test, virusscan-cleanup, repospecific-test, subscription-test]
if: "!cancelled()"
steps:
- name: Check test results 📋
run: |
echo "Integration test: ${{ needs.integration-test.result }}"
echo "Versioned test: ${{ needs.versioned-test.result }}"
echo "Virus scan test: ${{ needs.virusscan-test.result }}"
echo "Repo-specific test: ${{ needs.repospecific-test.result }} (disabled is OK)"
echo "Subscription test: ${{ needs.subscription-test.result }}"
if [ "${{ needs.integration-test.result }}" == "success" ] && \
[ "${{ needs.versioned-test.result }}" == "success" ] && \
[ "${{ needs.virusscan-test.result }}" == "success" ] && \
[ "${{ needs.subscription-test.result }}" == "success" ]; then
echo "✅ All enabled integration tests passed!"
else
echo "❌ Some integration tests failed. Check individual job results for details."
exit 1
fi