Multi Tenancy Deploy & Integration Test LatestVersion🚀 #116
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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: | |
| pull-requests: read | |
| packages: read # Added permission to read packages | |
| jobs: | |
| deploy: | |
| #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: '18' # Ensure to use at least version 18 | |
| - name: Install MBT ⚙️ | |
| run: | | |
| echo "🔧 Installing MBT..." | |
| npm install -g mbt | |
| echo "✅ MBT installation complete!" | |
| - name: Clone the cloud-cap-samples-java repo 🌐 | |
| run: | | |
| echo "🔄 Cloning repository..." | |
| git clone --depth 1 --branch mtTests https://github.com/vibhutikumar07/cloud-cap-samples-java.git | |
| echo "✅ Repository cloned!" | |
| - 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>" . | 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 -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 -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: cloud-cap-samples-java | |
| run: | | |
| pwd | |
| echo "✔️ Directory changed!" | |
| - name: Run mbt build 🔨 | |
| working-directory: cloud-cap-samples-java | |
| run: | | |
| echo "🚀 Running MBT build..." | |
| echo "java version:" | |
| java --version | |
| mbt build | |
| echo "✅ MBT build completed!" | |
| - name: Deploy to Cloud Foundry ☁️ | |
| working-directory: cloud-cap-samples-java | |
| run: | | |
| echo "🚀 Deploying to ${{ secrets.CF_SPACE }}..." | |
| 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 cf-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 ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ secrets.CF_SPACE }} | |
| 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!" | |
| integration-test: | |
| 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 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 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: Determine Cloud Foundry Space 🌌 | |
| id: determine_space | |
| run: | | |
| if [ "${{ github.event.inputs.cf_space }}" == "developcap" ]; then | |
| space="${{ secrets.CF_SPACE }}" | |
| else | |
| space="${{ github.event.inputs.cf_space }}" | |
| fi | |
| echo "🌍 Space determined: $space" | |
| echo "space=$space" >> $GITHUB_OUTPUT | |
| - name: Login to Cloud Foundry 🔑 | |
| run: | | |
| echo "🔄 Logging in to Cloud Foundry using space: ${{ steps.determine_space.outputs.space }}" | |
| cf login -a ${{ secrets.CF_API }} \ | |
| -u ${{ secrets.CF_USER }} \ | |
| -p ${{ secrets.CF_PASSWORD }} \ | |
| -o ${{ secrets.CF_ORG }} \ | |
| -s ${{ secrets.CF_SPACE }} | |
| - 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: 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 }} | |
| run: | | |
| echo "🚀 Preparing credentials for ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..." | |
| set -e | |
| PROPERTIES_FILE="sdm/src/test/resources/credentials.properties" | |
| appUrl="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" | |
| appUrlMT="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com" | |
| authUrl="${{ secrets.CAPAUTH_URL }}" | |
| authUrlMT1="${{ secrets.AUTHURLMT1 }}" | |
| authUrlMT2="${{ secrets.AUTHURLMT2 }}" | |
| clientID="${{ env.CLIENT_ID }}" | |
| clientSecret="${{ env.CLIENT_SECRET }}" | |
| clientIDMT="${{ env.CLIENT_ID_MT }}" | |
| clientSecretMT="${{ env.CLIENT_SECRET_MT }}" | |
| username="${{ secrets.CF_USER }}" | |
| password="${{ secrets.CF_PASSWORD }}" | |
| noSDMRoleUsername="${{ secrets.NOSDMROLEUSERNAME }}" | |
| noSDMRoleUserPassword="${{ secrets.NOSDMROLEUSERPASSWORD }}" | |
| 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" | |
| 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 | |
| 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 | |
| EOL | |
| echo "✅ Credentials file prepared!" | |
| - 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 }}" | |
| mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" | |
| echo "✅ Integration tests completed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}!" | |
| - name: Upload test results 📊 | |
| if: always() | |
| 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 | |
| # Summary job to aggregate results | |
| test-summary: | |
| runs-on: ubuntu-latest | |
| needs: integration-test | |
| if: always() | |
| steps: | |
| - name: Check test results 📋 | |
| run: | | |
| if [ "${{ needs.integration-test.result }}" == "success" ]; then | |
| echo "✅ All integration tests passed!" | |
| else | |
| echo "❌ Some integration tests failed. Check individual job results for details." | |
| exit 1 | |
| fi |