chore: add healthcheck commands to Dockerfiles for improved container⦠#107
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: DMZ Branch Validation | |
| permissions: | |
| contents: read | |
| on: | |
| push: | |
| branches: [dmz] | |
| env: | |
| NODE_VERSION: "22.11.0" | |
| jobs: | |
| validate-dmz: | |
| name: Validate DMZ Branch | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Validate XM Cloud credentials | |
| id: credential-check | |
| run: | | |
| echo "==========================================" | |
| echo "π Validating XM Cloud Credentials" | |
| echo "==========================================" | |
| echo "" | |
| echo "Repository: ${{ github.repository }}" | |
| echo "Event: ${{ github.event_name }}" | |
| echo "Ref: ${{ github.ref }}" | |
| echo "" | |
| MISSING_CREDENTIALS="" | |
| CREDENTIALS_OK=true | |
| # Check required secrets | |
| if [ -z "${{ secrets.SITECORE_EDGE_URL }}" ]; then | |
| echo "β SITECORE_EDGE_URL is missing" | |
| MISSING_CREDENTIALS="$MISSING_CREDENTIALS SITECORE_EDGE_URL" | |
| CREDENTIALS_OK=false | |
| else | |
| echo "β SITECORE_EDGE_URL is set" | |
| fi | |
| if [ -z "${{ secrets.SITECORE_EDGE_CONTEXT_ID }}" ]; then | |
| echo "β SITECORE_EDGE_CONTEXT_ID is missing" | |
| MISSING_CREDENTIALS="$MISSING_CREDENTIALS SITECORE_EDGE_CONTEXT_ID" | |
| CREDENTIALS_OK=false | |
| else | |
| echo "β SITECORE_EDGE_CONTEXT_ID is set" | |
| fi | |
| if [ -z "${{ secrets.NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID }}" ]; then | |
| echo "β NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID is missing" | |
| MISSING_CREDENTIALS="$MISSING_CREDENTIALS NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID" | |
| CREDENTIALS_OK=false | |
| else | |
| echo "β NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID is set" | |
| fi | |
| if [ -z "${{ secrets.SITECORE_EDITING_SECRET }}" ]; then | |
| echo "β SITECORE_EDITING_SECRET is missing" | |
| MISSING_CREDENTIALS="$MISSING_CREDENTIALS SITECORE_EDITING_SECRET" | |
| CREDENTIALS_OK=false | |
| else | |
| echo "β SITECORE_EDITING_SECRET is set" | |
| fi | |
| # Check optional but recommended secrets | |
| if [ -z "${{ secrets.NEXT_PUBLIC_SITECORE_API_KEY }}" ]; then | |
| echo "β οΈ NEXT_PUBLIC_SITECORE_API_KEY is not set (optional)" | |
| else | |
| echo "β NEXT_PUBLIC_SITECORE_API_KEY is set" | |
| fi | |
| if [ -z "${{ secrets.NEXT_PUBLIC_SITECORE_API_HOST }}" ]; then | |
| echo "β οΈ NEXT_PUBLIC_SITECORE_API_HOST is not set (optional)" | |
| else | |
| echo "β NEXT_PUBLIC_SITECORE_API_HOST is set" | |
| fi | |
| echo "" | |
| echo "==========================================" | |
| if [ "$CREDENTIALS_OK" = false ]; then | |
| echo "β CREDENTIAL VALIDATION FAILED" | |
| echo "" | |
| echo "Missing required credentials:$MISSING_CREDENTIALS" | |
| echo "" | |
| echo "β οΈ IMPORTANT: This workflow runs in the upstream repository context." | |
| echo " Fork secrets are NOT accessible - only upstream repository secrets are used." | |
| echo "" | |
| echo "This is an UPSTREAM REPOSITORY configuration issue." | |
| echo "The upstream repository administrator needs to configure these secrets:" | |
| echo "" | |
| echo " Settings > Secrets and variables > Actions > Secrets" | |
| echo "" | |
| echo "Required secrets:" | |
| echo " - SITECORE_EDGE_URL" | |
| echo " - SITECORE_EDGE_CONTEXT_ID" | |
| echo " - NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID" | |
| echo " - SITECORE_EDITING_SECRET" | |
| echo "" | |
| echo "Once these secrets are configured in the upstream repository," | |
| echo "this workflow will be able to access them when PRs are merged." | |
| echo "" | |
| echo "::error::Missing required XM Cloud credentials in upstream repository:$MISSING_CREDENTIALS" | |
| echo "credentials-valid=false" >> $GITHUB_OUTPUT | |
| exit 1 | |
| else | |
| echo "β All required credentials are present" | |
| echo "credentials-valid=true" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Install dependencies for all starters | |
| run: | | |
| echo "Installing dependencies for all enabled starters..." | |
| # Install dependencies for each enabled starter | |
| if [ -d "examples/kit-nextjs-skate-park" ]; then | |
| echo "Installing dependencies for kit-nextjs-skate-park..." | |
| cd examples/kit-nextjs-skate-park | |
| npm ci | |
| cd ../.. | |
| fi | |
| if [ -d "examples/kit-nextjs-article-starter" ]; then | |
| echo "Installing dependencies for kit-nextjs-article-starter..." | |
| cd examples/kit-nextjs-article-starter | |
| npm ci | |
| cd ../.. | |
| fi | |
| if [ -d "examples/kit-nextjs-location-finder" ]; then | |
| echo "Installing dependencies for kit-nextjs-location-finder..." | |
| cd examples/kit-nextjs-location-finder | |
| npm ci | |
| cd ../.. | |
| fi | |
| if [ -d "examples/kit-nextjs-product-listing" ]; then | |
| echo "Installing dependencies for kit-nextjs-product-listing..." | |
| cd examples/kit-nextjs-product-listing | |
| npm ci | |
| cd ../.. | |
| fi | |
| - name: Generate Sitecore files for all starters | |
| run: | | |
| echo "Generating Sitecore configuration files..." | |
| # Generate files for each enabled starter | |
| for starter in examples/kit-nextjs-skate-park examples/kit-nextjs-article-starter examples/kit-nextjs-location-finder examples/kit-nextjs-product-listing; do | |
| if [ -d "$starter" ]; then | |
| echo "Generating files for $starter..." | |
| cd "$starter" | |
| # Try to generate files with Sitecore tools, fallback to minimal files if credentials are missing | |
| if npm run sitecore-tools:generate-map 2>/dev/null; then | |
| echo "β Sitecore files generated successfully for $starter" | |
| else | |
| echo "β οΈ Sitecore tools failed (likely missing credentials), creating minimal files for $starter" | |
| # Create minimal .sitecore directory and files | |
| mkdir -p .sitecore | |
| # Create minimal sites.json | |
| echo '[{"name":"basic","hostName":"*","language":"en"}]' > .sitecore/sites.json | |
| # Create minimal metadata.json | |
| echo '{"packages":{"@sitecore-content-sdk/core":"1.1.0","@sitecore-content-sdk/nextjs":"1.1.0"}}' > .sitecore/metadata.json | |
| # Create minimal component-map.ts | |
| echo 'export default new Map();' > .sitecore/component-map.ts | |
| # Create minimal import-map.ts | |
| echo 'export default [];' > .sitecore/import-map.ts | |
| echo "β Minimal Sitecore files created for $starter" | |
| fi | |
| cd ../.. | |
| fi | |
| done | |
| - name: Lint and format check | |
| run: | | |
| echo "Running linting and formatting checks..." | |
| # Check each enabled starter | |
| for starter in examples/kit-nextjs-skate-park examples/kit-nextjs-article-starter examples/kit-nextjs-location-finder examples/kit-nextjs-product-listing; do | |
| if [ -d "$starter" ]; then | |
| echo "==================================" | |
| echo "Checking $starter" | |
| echo "==================================" | |
| cd "$starter" | |
| # Run linting - WARNING ONLY (does not fail the workflow) | |
| echo "Running lint for $starter..." | |
| if ! npm run lint; then | |
| echo "β οΈ WARNING: Linting issues found in $starter" | |
| echo "::warning::Linting found issues in $starter (non-blocking)" | |
| # Continue without failing - lint check is a warning only for now | |
| else | |
| echo "β Linting passed for $starter" | |
| fi | |
| # Check formatting - WARNING ONLY (does not fail the workflow) | |
| echo "Running format check for $starter..." | |
| if ! npm run format:check; then | |
| echo "β οΈ WARNING: Formatting issues found in $starter" | |
| echo "Run 'npm run prettier' to fix formatting issues" | |
| echo "::warning::Formatting check found issues in $starter (non-blocking)" | |
| # Continue without failing - format check is a warning only for now | |
| else | |
| echo "β Formatting check passed for $starter" | |
| fi | |
| cd ../.. | |
| fi | |
| done | |
| - name: Type checking | |
| run: | | |
| echo "Running TypeScript type checking..." | |
| # Check each enabled starter - WARNING ONLY (does not fail the workflow) | |
| for starter in examples/kit-nextjs-skate-park examples/kit-nextjs-article-starter examples/kit-nextjs-location-finder examples/kit-nextjs-product-listing; do | |
| if [ -d "$starter" ]; then | |
| echo "Type checking $starter..." | |
| cd "$starter" | |
| if npm run type-check 2>/dev/null; then | |
| echo "β Type checking passed for $starter" | |
| else | |
| echo "β οΈ WARNING: Type checking issues found in $starter" | |
| echo "::warning::Type checking found issues in $starter (non-blocking)" | |
| # Continue without failing - type check is a warning only for now | |
| fi | |
| cd ../.. | |
| fi | |
| done | |
| - name: Check configured site names and extract default | |
| id: site-check | |
| run: | | |
| echo "==========================================" | |
| echo "π Checking Configured Site Names" | |
| echo "==========================================" | |
| echo "" | |
| CONFIGURED_SITE_NAME="" | |
| FIRST_SITE_FOUND="" | |
| for starter in examples/kit-nextjs-skate-park examples/kit-nextjs-article-starter examples/kit-nextjs-location-finder examples/kit-nextjs-product-listing; do | |
| if [ -d "$starter" ]; then | |
| echo "Checking $starter..." | |
| cd "$starter" | |
| if [ -f ".sitecore/sites.json" ]; then | |
| echo " Sites configured in .sitecore/sites.json:" | |
| echo " Full contents of sites.json:" | |
| cat .sitecore/sites.json | head -20 | |
| echo "" | |
| # Extract site names from sites.json (handles JSON format) | |
| if command -v jq &> /dev/null; then | |
| FIRST_SITE=$(jq -r '.[0].name' .sitecore/sites.json 2>/dev/null) | |
| if [ -n "$FIRST_SITE" ] && [ "$FIRST_SITE" != "null" ]; then | |
| if [ -z "$FIRST_SITE_FOUND" ]; then | |
| FIRST_SITE_FOUND="$FIRST_SITE" | |
| fi | |
| echo " - $FIRST_SITE (first site)" | |
| jq -r '.[].name' .sitecore/sites.json 2>/dev/null | while read -r site_name; do | |
| if [ "$site_name" != "$FIRST_SITE" ]; then | |
| echo " - $site_name" | |
| fi | |
| done || true | |
| else | |
| echo " (Could not parse sites.json - first site is null or empty)" | |
| fi | |
| else | |
| # Fallback: try to extract site names with grep/sed | |
| FIRST_SITE=$(grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' .sitecore/sites.json 2>/dev/null | head -1 | sed 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') | |
| if [ -n "$FIRST_SITE" ]; then | |
| if [ -z "$FIRST_SITE_FOUND" ]; then | |
| FIRST_SITE_FOUND="$FIRST_SITE" | |
| fi | |
| echo " - $FIRST_SITE (first site)" | |
| grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' .sitecore/sites.json 2>/dev/null | sed 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' | while read -r site_name; do | |
| if [ "$site_name" != "$FIRST_SITE" ]; then | |
| echo " - $site_name" | |
| fi | |
| done || true | |
| else | |
| echo " (Could not parse sites.json - install jq for better parsing)" | |
| fi | |
| fi | |
| else | |
| echo " β οΈ .sitecore/sites.json not found" | |
| fi | |
| cd ../.. | |
| fi | |
| done | |
| echo "" | |
| CONFIGURED_VAR="${{ vars.NEXT_PUBLIC_DEFAULT_SITE_NAME || 'basic' }}" | |
| echo "Current NEXT_PUBLIC_DEFAULT_SITE_NAME variable: $CONFIGURED_VAR" | |
| if [ -n "$FIRST_SITE_FOUND" ]; then | |
| echo "First site found in sites.json: $FIRST_SITE_FOUND" | |
| echo "site-name-from-config=$FIRST_SITE_FOUND" >> $GITHUB_OUTPUT | |
| if [ "$CONFIGURED_VAR" != "$FIRST_SITE_FOUND" ]; then | |
| echo "" | |
| echo "β οΈ WARNING: Site name mismatch detected!" | |
| echo " Variable value: '$CONFIGURED_VAR'" | |
| echo " Actual site in config: '$FIRST_SITE_FOUND'" | |
| echo "" | |
| echo "The build will use the site name from sites.json: '$FIRST_SITE_FOUND'" | |
| echo "To fix permanently, update NEXT_PUBLIC_DEFAULT_SITE_NAME variable to: $FIRST_SITE_FOUND" | |
| else | |
| echo "β Site name matches!" | |
| fi | |
| else | |
| echo "β οΈ Could not extract site name from sites.json" | |
| echo "site-name-from-config=" >> $GITHUB_OUTPUT | |
| fi | |
| echo "" | |
| echo "βΉοΈ If the build fails with 'Site does not exist', verify that" | |
| echo " NEXT_PUBLIC_DEFAULT_SITE_NAME matches one of the sites listed above." | |
| echo "" | |
| - name: Build all starters | |
| if: steps.credential-check.outputs.credentials-valid == 'true' | |
| env: | |
| # Sitecore Edge API Configuration | |
| SITECORE_EDGE_URL: ${{ secrets.SITECORE_EDGE_URL }} | |
| SITECORE_EDGE_CONTEXT_ID: ${{ secrets.SITECORE_EDGE_CONTEXT_ID }} | |
| NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID: ${{ secrets.NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID }} | |
| # Sitecore Configuration | |
| NEXT_PUBLIC_DEFAULT_SITE_NAME: ${{ vars.NEXT_PUBLIC_DEFAULT_SITE_NAME || 'basic' }} | |
| SITECORE_EDITING_SECRET: ${{ secrets.SITECORE_EDITING_SECRET }} | |
| # Additional Sitecore Environment Variables | |
| NEXT_PUBLIC_SITECORE_EDGE_URL: ${{ secrets.SITECORE_EDGE_URL }} | |
| NEXT_PUBLIC_SITECORE_API_KEY: ${{ secrets.NEXT_PUBLIC_SITECORE_API_KEY }} | |
| NEXT_PUBLIC_SITECORE_API_HOST: ${{ secrets.NEXT_PUBLIC_SITECORE_API_HOST }} | |
| NEXT_PUBLIC_DEFAULT_LANGUAGE: ${{ vars.NEXT_PUBLIC_DEFAULT_LANGUAGE || 'en' }} | |
| NEXT_PUBLIC_PERSONALIZE_SCOPE: ${{ vars.NEXT_PUBLIC_PERSONALIZE_SCOPE }} | |
| PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT: ${{ vars.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT || '1000' }} | |
| run: | | |
| set -e # Exit immediately if any command fails | |
| echo "==========================================" | |
| echo "ποΈ Building all enabled starters" | |
| echo "==========================================" | |
| echo "" | |
| echo "Sitecore Environment Variables Status:" | |
| echo " SITECORE_EDGE_URL: ${SITECORE_EDGE_URL:+β [SET]}${SITECORE_EDGE_URL:-β [NOT SET]}" | |
| echo " SITECORE_EDGE_CONTEXT_ID: ${SITECORE_EDGE_CONTEXT_ID:+β [SET]}${SITECORE_EDGE_CONTEXT_ID:-β [NOT SET]}" | |
| echo " NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID: ${NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID:+β [SET]}${NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID:-β [NOT SET]}" | |
| echo " NEXT_PUBLIC_DEFAULT_SITE_NAME: ${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| echo " SITECORE_EDITING_SECRET: ${SITECORE_EDITING_SECRET:+β [SET]}${SITECORE_EDITING_SECRET:-β [NOT SET]}" | |
| echo "" | |
| # Build each enabled starter | |
| for starter in examples/kit-nextjs-skate-park examples/kit-nextjs-article-starter examples/kit-nextjs-location-finder examples/kit-nextjs-product-listing; do | |
| if [ -d "$starter" ]; then | |
| echo "==========================================" | |
| echo "Building $starter..." | |
| echo "==========================================" | |
| cd "$starter" | |
| # Try to read site name from sites.json as fallback | |
| ACTUAL_SITE_NAME="${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| DETECTED_SITE="" | |
| echo "Checking for site name in .sitecore/sites.json..." | |
| if [ -f ".sitecore/sites.json" ]; then | |
| echo " Found .sitecore/sites.json" | |
| if command -v jq &> /dev/null; then | |
| DETECTED_SITE=$(jq -r '.[0].name' .sitecore/sites.json 2>/dev/null) | |
| else | |
| DETECTED_SITE=$(grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' .sitecore/sites.json 2>/dev/null | head -1 | sed 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') | |
| fi | |
| echo " Detected site name from sites.json: '${DETECTED_SITE:-<empty or null>}'" | |
| echo " Variable site name: '${NEXT_PUBLIC_DEFAULT_SITE_NAME}'" | |
| if [ -n "$DETECTED_SITE" ] && [ "$DETECTED_SITE" != "null" ] && [ "$DETECTED_SITE" != "$NEXT_PUBLIC_DEFAULT_SITE_NAME" ]; then | |
| echo "β οΈ Site name mismatch detected for $starter:" | |
| echo " Variable: ${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| echo " sites.json: $DETECTED_SITE" | |
| echo " Using site name from sites.json: $DETECTED_SITE" | |
| ACTUAL_SITE_NAME="$DETECTED_SITE" | |
| # Set environment variable for npm command | |
| export NEXT_PUBLIC_DEFAULT_SITE_NAME="$DETECTED_SITE" | |
| elif [ -n "$DETECTED_SITE" ] && [ "$DETECTED_SITE" != "null" ]; then | |
| echo "β Site names match: ${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| ACTUAL_SITE_NAME="${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| else | |
| echo "β οΈ Could not extract valid site name from sites.json, using variable: ${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| ACTUAL_SITE_NAME="${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| fi | |
| else | |
| echo " β οΈ .sitecore/sites.json not found, using variable: ${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| ACTUAL_SITE_NAME="${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| fi | |
| echo "" | |
| echo "Final site name to be used: ${ACTUAL_SITE_NAME}" | |
| echo "Environment variable NEXT_PUBLIC_DEFAULT_SITE_NAME: ${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| echo "" | |
| echo "Running build for $starter..." | |
| # Ensure the environment variable is set for the npm command | |
| NEXT_PUBLIC_DEFAULT_SITE_NAME="${ACTUAL_SITE_NAME}" npm run build 2>&1 | tee build_output.log || BUILD_EXIT_CODE=$? | |
| BUILD_OUTPUT=$(cat build_output.log) | |
| rm -f build_output.log | |
| if [ -n "$BUILD_EXIT_CODE" ]; then | |
| echo "β Build failed for $starter" | |
| echo "" | |
| echo "Build output:" | |
| echo "$BUILD_OUTPUT" | |
| echo "" | |
| # Detect site configuration errors | |
| if echo "$BUILD_OUTPUT" | grep -qi "Site.*does not exist\|site.*missing\|site item tree is missing"; then | |
| echo "π΄ SITE CONFIGURATION ERROR DETECTED" | |
| echo "" | |
| echo "The build failed because the site '${ACTUAL_SITE_NAME}' does not exist in XM Cloud." | |
| echo "" | |
| echo "Site name used in build: ${ACTUAL_SITE_NAME}" | |
| echo "Variable value: ${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| echo "" | |
| echo "β οΈ IMPORTANT: This means the site '${ACTUAL_SITE_NAME}' needs to exist in your XM Cloud instance." | |
| echo "" | |
| echo "Possible solutions:" | |
| echo "" | |
| echo "Option 1: Create the site in XM Cloud (if you have access)" | |
| echo " 1. Log into XM Cloud" | |
| echo " 2. Create a new site with the name: '${ACTUAL_SITE_NAME}'" | |
| echo " 3. Publish the site" | |
| echo "" | |
| echo "Option 2: Use an existing site name (recommended)" | |
| echo " 1. Check what site names actually exist in your XM Cloud instance" | |
| echo " 2. Check the 'Check configured site names' step above to see what's in sites.json" | |
| echo " 3. A repository administrator needs to update the 'NEXT_PUBLIC_DEFAULT_SITE_NAME'" | |
| echo " variable in: Settings > Secrets and variables > Actions > Variables" | |
| echo " 4. The variable should match an EXISTING site name in XM Cloud" | |
| echo "" | |
| echo "Option 3: Update sites.json (if you have access to modify it)" | |
| echo " 1. Update .sitecore/sites.json to use a site name that exists in XM Cloud" | |
| echo " 2. The site name in sites.json should match what's actually in XM Cloud" | |
| echo "" | |
| echo "π Note: The site name MUST exist in XM Cloud for the build to succeed." | |
| echo " The build process tries to fetch routes from XM Cloud, and if the site" | |
| echo " doesn't exist, it will fail with this error." | |
| echo "" | |
| echo "::error::Build failed for $starter - Site '${ACTUAL_SITE_NAME}' does not exist in XM Cloud. Either create the site in XM Cloud or update NEXT_PUBLIC_DEFAULT_SITE_NAME to match an existing site." | |
| # Detect credential-related errors | |
| elif echo "$BUILD_OUTPUT" | grep -qi "edge.*context\|sitecore.*edge\|credential\|authentication\|unauthorized\|403\|401"; then | |
| echo "π CREDENTIAL ISSUE DETECTED" | |
| echo "" | |
| echo "The build failure appears to be related to XM Cloud credentials." | |
| echo "This could indicate:" | |
| echo " - Invalid or expired credentials" | |
| echo " - Missing environment variables" | |
| echo " - Network/connectivity issues with XM Cloud Edge" | |
| echo "" | |
| echo "::error::Build failed for $starter due to credential/authentication issues" | |
| else | |
| echo "::error::Build failed for $starter (check logs above for details)" | |
| fi | |
| exit 1 | |
| fi | |
| echo "β Build successful for $starter" | |
| cd ../.. | |
| fi | |
| done | |
| echo "" | |
| echo "==========================================" | |
| echo "β All builds completed successfully" | |
| echo "==========================================" | |
| - name: Credential validation failed - skip build | |
| if: steps.credential-check.outputs.credentials-valid != 'true' | |
| run: | | |
| echo "==========================================" | |
| echo "β BUILD SKIPPED - CREDENTIALS MISSING" | |
| echo "==========================================" | |
| echo "" | |
| echo "The build step was skipped because required XM Cloud credentials" | |
| echo "are not configured in the UPSTREAM repository." | |
| echo "" | |
| echo "β οΈ IMPORTANT INFORMATION:" | |
| echo "" | |
| echo "This workflow runs in the upstream repository context after a PR merge." | |
| echo "Fork secrets are NOT accessible - only upstream repository secrets are used." | |
| echo "" | |
| echo "π§ SOLUTION:" | |
| echo "" | |
| echo "An upstream repository administrator needs to configure these secrets:" | |
| echo "" | |
| echo " 1. Go to: Settings > Secrets and variables > Actions > Secrets" | |
| echo " 2. Add the following required secrets:" | |
| echo " - SITECORE_EDGE_URL" | |
| echo " - SITECORE_EDGE_CONTEXT_ID" | |
| echo " - NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID" | |
| echo " - SITECORE_EDITING_SECRET" | |
| echo "" | |
| echo " 3. Once configured, future PR merges will be able to use these secrets" | |
| echo "" | |
| echo "π NOTE:" | |
| echo " - This is NOT a code issue - it's a repository configuration issue" | |
| echo " - Contributors cannot fix this - only repository admins can" | |
| echo " - The PR validation workflow (for forks) runs without credentials" | |
| echo " - The dmz-validation workflow (after merge) requires upstream secrets" | |
| echo "" | |
| echo "::error::Build skipped - Missing required XM Cloud credentials in upstream repository" | |
| exit 1 | |
| - name: Run tests with coverage | |
| if: steps.credential-check.outputs.credentials-valid == 'true' | |
| run: | | |
| set -e # Exit immediately if any command fails | |
| echo "Running tests with coverage for all starters..." | |
| # Test each enabled starter | |
| for starter in examples/kit-nextjs-skate-park examples/kit-nextjs-article-starter examples/kit-nextjs-location-finder examples/kit-nextjs-product-listing; do | |
| if [ -d "$starter" ]; then | |
| echo "Testing $starter..." | |
| cd "$starter" | |
| # Check if test:coverage script exists, if not fail the workflow | |
| if grep -q '"test:coverage:unit"' package.json; then | |
| echo "Running tests with coverage for $starter..." | |
| if ! npm run test:coverage:unit; then | |
| echo "β Tests failed for $starter" | |
| echo "::error::Tests failed for $starter" | |
| exit 1 | |
| fi | |
| echo "β Tests passed for $starter" | |
| else | |
| echo "β No test:coverage:unit script found for $starter - tests are mandatory" | |
| echo "::error::No test:coverage:unit script found for $starter" | |
| exit 1 | |
| fi | |
| cd ../.. | |
| fi | |
| done | |
| - name: Run GEO endpoint tests (with server) | |
| id: run-geo-tests | |
| env: | |
| SITECORE_EDGE_URL: ${{ secrets.SITECORE_EDGE_URL }} | |
| SITECORE_EDGE_CONTEXT_ID: ${{ secrets.SITECORE_EDGE_CONTEXT_ID }} | |
| NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID: ${{ secrets.NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID }} | |
| NEXT_PUBLIC_DEFAULT_SITE_NAME: ${{ vars.NEXT_PUBLIC_DEFAULT_SITE_NAME || 'basic' }} | |
| SITECORE_EDITING_SECRET: ${{ secrets.SITECORE_EDITING_SECRET }} | |
| NEXT_PUBLIC_SITECORE_EDGE_URL: ${{ secrets.SITECORE_EDGE_URL }} | |
| NEXT_PUBLIC_SITECORE_API_KEY: ${{ secrets.NEXT_PUBLIC_SITECORE_API_KEY }} | |
| NEXT_PUBLIC_SITECORE_API_HOST: ${{ secrets.NEXT_PUBLIC_SITECORE_API_HOST }} | |
| NEXT_PUBLIC_DEFAULT_LANGUAGE: ${{ vars.NEXT_PUBLIC_DEFAULT_LANGUAGE || 'en' }} | |
| NEXT_PUBLIC_PERSONALIZE_SCOPE: ${{ vars.NEXT_PUBLIC_PERSONALIZE_SCOPE }} | |
| PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT: ${{ vars.PERSONALIZE_MIDDLEWARE_EDGE_TIMEOUT || '1000' }} | |
| run: | | |
| echo "Running GEO endpoint tests (site must be running)..." | |
| echo "Per-starter site names: skate-park | solterra | alaris | sync (must match build and exist in XM Cloud)" | |
| # Why site names are hardcoded below: Each starter maps to the canonical Sitecore site name used by that | |
| # kit in the All Things JSS / xmcloud-starter-js repo. | |
| # GitHub Actions repository variables/secrets usually expose only ONE default NEXT_PUBLIC_DEFAULT_SITE_NAME; | |
| # applying that single value to every starter would inline the wrong site into builds and break GEO tests. | |
| # Whenever a site name changes in XM Cloud or in this repository, update the case arms to match β do not | |
| # rely on the lone repo variable for per-kit site selection. | |
| # Fully stop the previous Next.js server and free :3000 before starting the next starter | |
| # (npm spawns child processes; killing only $! can leave node listening on the port) | |
| stop_geo_server() { | |
| local pid="${1:-}" | |
| echo "Stopping GEO server (pid=${pid:-none})..." | |
| if [ -n "$pid" ]; then | |
| kill "$pid" 2>/dev/null || true | |
| pkill -P "$pid" 2>/dev/null || true | |
| fi | |
| pkill -f "next start" 2>/dev/null || true | |
| sleep 2 | |
| for i in $(seq 1 20); do | |
| if ! curl -sf -o /dev/null --connect-timeout 1 --max-time 3 http://127.0.0.1:3000/ 2>/dev/null; then | |
| echo "Port 3000 is free." | |
| return 0 | |
| fi | |
| echo "Waiting for port 3000 to be released ($i/20)..." | |
| fuser -k 3000/tcp 2>/dev/null || true | |
| sleep 2 | |
| done | |
| echo "β οΈ Port 3000 may still be in use; attempting to continue." | |
| } | |
| SERVER_PID="" | |
| for starter in examples/kit-nextjs-skate-park examples/kit-nextjs-article-starter examples/kit-nextjs-location-finder examples/kit-nextjs-product-listing; do | |
| if [ -d "$starter" ]; then | |
| echo "GEO tests for $starter..." | |
| cd "$starter" | |
| if grep -q '"test:geo"' package.json 2>/dev/null; then | |
| stop_geo_server "$SERVER_PID" | |
| SERVER_PID="" | |
| # sync | solterra | alaris | skate-park β must match XM Cloud + All Things JSS kit (see comment above). | |
| case "$starter" in | |
| examples/kit-nextjs-product-listing) | |
| export NEXT_PUBLIC_DEFAULT_SITE_NAME="sync" | |
| ;; | |
| examples/kit-nextjs-article-starter) | |
| export NEXT_PUBLIC_DEFAULT_SITE_NAME="solterra" | |
| ;; | |
| examples/kit-nextjs-location-finder) | |
| export NEXT_PUBLIC_DEFAULT_SITE_NAME="alaris" | |
| ;; | |
| examples/kit-nextjs-skate-park) | |
| export NEXT_PUBLIC_DEFAULT_SITE_NAME="skate-park" | |
| ;; | |
| *) | |
| export NEXT_PUBLIC_DEFAULT_SITE_NAME="${NEXT_PUBLIC_DEFAULT_SITE_NAME:-basic}" | |
| ;; | |
| esac | |
| echo "NEXT_PUBLIC_DEFAULT_SITE_NAME=${NEXT_PUBLIC_DEFAULT_SITE_NAME}" | |
| # npm run start runs build then next:start (kit package.json). Allow time below for build before :3000 is up. | |
| echo "Starting $starter for GEO (npm run start)..." | |
| npm run start & | |
| SERVER_PID=$! | |
| # Wait for server (npm run start runs build first; large starters may need several minutes) | |
| echo "Waiting for server on http://localhost:3000..." | |
| for i in $(seq 1 120); do | |
| if curl -sf -o /dev/null http://localhost:3000 2>/dev/null; then | |
| echo "Server ready." | |
| break | |
| fi | |
| if [ "$i" -eq 120 ]; then | |
| echo "β Server did not become ready in time" | |
| stop_geo_server "$SERVER_PID" | |
| exit 1 | |
| fi | |
| sleep 5 | |
| done | |
| if GEO_BASE_URL=http://localhost:3000 npm run test:geo; then | |
| echo "β GEO tests passed for $starter" | |
| else | |
| echo "β GEO tests failed for $starter" | |
| stop_geo_server "$SERVER_PID" | |
| SERVER_PID="" | |
| cd ../.. | |
| exit 1 | |
| fi | |
| stop_geo_server "$SERVER_PID" | |
| SERVER_PID="" | |
| else | |
| echo "βοΈ No test:geo script for $starter, skipping" | |
| fi | |
| cd ../.. | |
| fi | |
| done | |
| stop_geo_server "$SERVER_PID" | |
| - name: Create success notification | |
| if: success() | |
| run: | | |
| echo "## β DMZ Validation Successful" >> $GITHUB_STEP_SUMMARY | |
| echo "The dmz branch has passed all validation checks." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Validation Results:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- β All builds passed" >> $GITHUB_STEP_SUMMARY | |
| echo "- β Unit tests with coverage (npm run test:coverage:unit)" >> $GITHUB_STEP_SUMMARY | |
| echo "- β Linting and formatting checks passed" >> $GITHUB_STEP_SUMMARY | |
| echo "- β Type checking passed" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Next Steps:**" >> $GITHUB_STEP_SUMMARY | |
| echo "You can now merge dmz into main via GitHub web interface:" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Create a Pull Request from \`dmz\` to \`main\`" >> $GITHUB_STEP_SUMMARY | |
| echo "2. Select **\"Create a merge commit\"** option (not Squash or Rebase)" >> $GITHUB_STEP_SUMMARY | |
| echo "3. Confirm the merge" >> $GITHUB_STEP_SUMMARY | |
| notify-failure: | |
| name: Notify Build Failure | |
| runs-on: ubuntu-latest | |
| needs: validate-dmz | |
| if: failure() | |
| steps: | |
| - name: Create failure notification | |
| run: | | |
| echo "## β DMZ Validation Failed" >> $GITHUB_STEP_SUMMARY | |
| echo "The dmz branch failed validation and should not be merged to main." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Possible Issues:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- π **Missing XM Cloud credentials in upstream repository** (check 'Validate XM Cloud credentials' step)" >> $GITHUB_STEP_SUMMARY | |
| echo "- Site configuration error: Site name mismatch (check 'Check configured site names' step)" >> $GITHUB_STEP_SUMMARY | |
| echo "- Build failures (check 'Build all starters' step)" >> $GITHUB_STEP_SUMMARY | |
| echo "- Unit tests with coverage (check 'Run tests with coverage:unit for all starters' step)" >> $GITHUB_STEP_SUMMARY | |
| echo "- Code quality issues (linting, formatting, type checking)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**β οΈ IMPORTANT - Credential Issue:**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "If the failure is due to missing credentials:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "This workflow runs in the **upstream repository context** after a PR merge." >> $GITHUB_STEP_SUMMARY | |
| echo "Fork secrets are NOT accessible - only upstream repository secrets are used." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Solution:** An upstream repository administrator must configure secrets:" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Go to: Settings > Secrets and variables > Actions > Secrets" >> $GITHUB_STEP_SUMMARY | |
| echo "2. Add required secrets: SITECORE_EDGE_URL, SITECORE_EDGE_CONTEXT_ID, NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID, SITECORE_EDITING_SECRET" >> $GITHUB_STEP_SUMMARY | |
| echo "3. This is NOT a code issue - it's a repository configuration issue" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Next Steps:**" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Review the failed checks above" >> $GITHUB_STEP_SUMMARY | |
| echo "2. If credentials missing: Contact upstream repository admin to configure secrets" >> $GITHUB_STEP_SUMMARY | |
| echo "3. If site configuration error: Repository admin needs to update 'NEXT_PUBLIC_DEFAULT_SITE_NAME' variable" >> $GITHUB_STEP_SUMMARY | |
| echo "4. Fix code issues in the dmz branch and push" >> $GITHUB_STEP_SUMMARY | |
| echo "5. The validation will run automatically" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Note:** Contributors cannot fix credential/variable issues - only repository admins can." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Alternative:** Use the 'Rebase DMZ Branch' workflow to remove problematic commits." >> $GITHUB_STEP_SUMMARY |