diff --git a/.controlplane/controlplane.yml b/.controlplane/controlplane.yml index 53f68730..f394fe1c 100644 --- a/.controlplane/controlplane.yml +++ b/.controlplane/controlplane.yml @@ -38,7 +38,7 @@ aliases: release_script: release_script.sh apps: - react-webpack-rails-tutorial: + react-webpack-rails-tutorial-production: # Simulate Production Version <<: *common # Don't allow overriding the org and app by ENV vars b/c production is sensitive! diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index b8f9b733..b5282ce8 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -44,205 +44,59 @@ runs: - name: Setup Environment uses: ./.github/actions/setup-environment - - name: Set shared functions - id: shared-functions - uses: actions/github-script@v7 - with: - script: | - core.exportVariable('GET_CONSOLE_LINK', ` - function getConsoleLink(prNumber) { - return ' [Control Plane Console for Review App with PR #' + prNumber + '](' + - 'https://console.cpln.io/org/' + process.env.CPLN_ORG + '/workloads/' + process.env.APP_NAME + ')'; - } - `); - - - name: Initialize Deployment - id: init-deployment - uses: actions/github-script@v7 - with: - script: | - eval(process.env.GET_CONSOLE_LINK); - - async function getWorkflowUrl(runId) { - // Get the current job ID - const jobs = await github.rest.actions.listJobsForWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: runId - }); - - const currentJob = jobs.data.jobs.find(job => job.status === 'in_progress'); - const jobId = currentJob?.id; - - if (!jobId) { - console.log('Warning: Could not find current job ID'); - return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; - } - - return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}`; - } - - // Create initial deployment comment - const comment = await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: process.env.PR_NUMBER, - body: ' Initializing deployment...' - }); - - // Create GitHub deployment - const deployment = await github.rest.repos.createDeployment({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: context.sha, - environment: 'review', - auto_merge: false, - required_contexts: [] - }); - - const workflowUrl = await getWorkflowUrl(context.runId); - - core.exportVariable('WORKFLOW_URL', workflowUrl); - core.exportVariable('COMMENT_ID', comment.data.id); - core.exportVariable('DEPLOYMENT_ID', deployment.data.id); - - - name: Set commit hash - shell: bash - run: | - FULL_COMMIT=$(git rev-parse HEAD) - echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV - - - name: Update Status - Setting Up - uses: actions/github-script@v7 - with: - script: | - eval(process.env.GET_CONSOLE_LINK); - - const setupMessage = [ - '🔧 Setting up Control Plane app...', - '', - ' [View Setup Logs](' + process.env.WORKFLOW_URL + ')', - '', - getConsoleLink(process.env.PR_NUMBER) - ].join('\n'); - - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: setupMessage - }); - - - name: Setup Control Plane App + - name: Get Commit SHA + id: get_sha shell: bash - run: | - echo "🔧 Checking if app exists..." - if ! cpflow exists -a ${{ inputs.app_name }} ; then - echo "📦 Setting up new Control Plane app..." - cpflow setup-app -a ${{ inputs.app_name }} - fi - - - name: Update Status - Building - uses: actions/github-script@v7 - with: - script: | - eval(process.env.GET_CONSOLE_LINK); - - const buildingMessage = [ - '🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + process.env.COMMIT_HASH, - '', - ' [View Build Logs](' + process.env.WORKFLOW_URL + ')', - '', - getConsoleLink(process.env.PR_NUMBER) - ].join('\n'); - - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: buildingMessage - }); - - - name: Update Status - Deploying - uses: actions/github-script@v7 - with: - script: | - eval(process.env.GET_CONSOLE_LINK); - - const deployingMessage = [ - '🚀 Deploying to Control Plane...', - '', - '⏳ Waiting for deployment to be ready...', - '', - ' [View Deploy Logs](' + process.env.WORKFLOW_URL + ')', - '', - getConsoleLink(process.env.PR_NUMBER) - ].join('\n'); - - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: deployingMessage - }); + run: ${{ github.action_path }}/scripts/get-commit-sha.sh + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + PR_NUMBER: ${{ env.PR_NUMBER }} - name: Deploy to Control Plane id: deploy shell: bash - run: ${{ github.action_path }}/scripts/deploy.sh - env: - APP_NAME: ${{ inputs.app_name }} - CPLN_ORG: ${{ inputs.org }} - WAIT_TIMEOUT: ${{ inputs.wait_timeout }} - - - name: Update Status - Deployment Complete - if: always() - uses: actions/github-script@v7 - with: - script: | - eval(process.env.GET_CONSOLE_LINK); - - const prNumber = process.env.PR_NUMBER; - const appUrl = process.env.REVIEW_APP_URL; - const workflowUrl = process.env.WORKFLOW_URL; - const isSuccess = '${{ job.status }}' === 'success'; - - // Create GitHub deployment status - const deploymentStatus = { - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: process.env.DEPLOYMENT_ID, - state: isSuccess ? 'success' : 'failure', - environment_url: isSuccess ? appUrl : undefined, - log_url: workflowUrl, - environment: 'review' - }; - - await github.rest.repos.createDeploymentStatus(deploymentStatus); - - // Define messages based on deployment status - const successMessage = [ - '✅ Deployment complete for PR #' + prNumber + ', commit ' + process.env.COMMIT_HASH, - '', - '🌐 [Review App for PR #' + prNumber + '](' + appUrl + ')', - '', - ' [View Completed Action Build and Deploy Logs](' + workflowUrl + ')', - '', - getConsoleLink(prNumber) - ].join('\n'); - - const failureMessage = [ - '❌ Deployment failed for PR #' + prNumber + ', commit ' + process.env.COMMIT_HASH, - '', - ' [View Deployment Logs with Errors](' + workflowUrl + ')', - '', - getConsoleLink(prNumber) - ].join('\n'); - - // Update the existing comment - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: isSuccess ? successMessage : failureMessage - }); + run: | + echo "🚀 Deploying app for PR #${PR_NUMBER}..." + + # Create temp file for output + TEMP_OUTPUT=$(mktemp) + trap 'rm -f "${TEMP_OUTPUT}"' EXIT + + # Deploy the application and show output in real-time while capturing it + if ! cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1 | tee "${TEMP_OUTPUT}"; then + echo "❌ Deployment failed for PR #${PR_NUMBER}" + echo "Error output:" + cat "${TEMP_OUTPUT}" + exit 1 + fi + + # Extract app URL from captured output + REVIEW_APP_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "${TEMP_OUTPUT}" | head -n1) + if [ -z "${REVIEW_APP_URL}" ]; then + echo "❌ Failed to get app URL from deployment output" + echo "Deployment output:" + cat "${TEMP_OUTPUT}" + exit 1 + fi + + # Wait for all workloads to be ready + WAIT_TIMEOUT=${WAIT_TIMEOUT:-${{ inputs.wait_timeout }}} + echo "⏳ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)..." + + # Use timeout command with ps:wait and show output in real-time + if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1 | tee -a "${TEMP_OUTPUT}"; then + TIMEOUT_EXIT=$? + if [ ${TIMEOUT_EXIT} -eq 124 ]; then + echo "❌ Timed out waiting for workloads after ${WAIT_TIMEOUT} seconds" + else + echo "❌ Workloads did not become ready for PR #${PR_NUMBER} (exit code: ${TIMEOUT_EXIT})" + fi + echo "Full output:" + cat "${TEMP_OUTPUT}" + exit 1 + fi + + echo "✅ Deployment successful for PR #${PR_NUMBER}" + echo "🌐 App URL: ${REVIEW_APP_URL}" + echo "review_app_url=${REVIEW_APP_URL}" >> $GITHUB_OUTPUT + echo "REVIEW_APP_URL=${REVIEW_APP_URL}" >> $GITHUB_ENV diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml index 829a9498..1a086ee3 100644 --- a/.github/actions/setup-environment/action.yml +++ b/.github/actions/setup-environment/action.yml @@ -3,6 +3,14 @@ name: 'Setup Environment' description: 'Sets up Ruby, installs Control Plane CLI, cpflow gem, and sets up the default profile' +inputs: + token: + description: 'Control Plane token' + required: true + org: + description: 'Control Plane organization' + required: true + runs: using: 'composite' steps: @@ -22,19 +30,22 @@ runs: - name: Setup Control Plane Profile shell: bash run: | - if [ -z "$CPLN_TOKEN" ]; then - echo " Error: CPLN_TOKEN environment variable is not set" + TOKEN="${{ inputs.token }}" + ORG="${{ inputs.org }}" + + if [ -z "$TOKEN" ]; then + echo " Error: Control Plane token not provided" exit 1 fi - if [ -z "$CPLN_ORG" ]; then - echo " Error: CPLN_ORG environment variable is not set" + if [ -z "$ORG" ]; then + echo " Error: Control Plane organization not provided" exit 1 fi echo "Setting up Control Plane profile..." - echo "Organization: $CPLN_ORG" - cpln profile update default --org "$CPLN_ORG" --token "$CPLN_TOKEN" + echo "Organization: $ORG" + cpln profile update default --org "$ORG" --token "$TOKEN" echo "Setting up Docker login for Control Plane registry..." - cpln image docker-login --org "$CPLN_ORG" + cpln image docker-login --org "$ORG" diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index fa24902c..3f547579 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -13,8 +13,8 @@ permissions: issues: write env: - CPLN_ORG: ${{ secrets.CPLN_ORG }} - CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} + CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} @@ -29,6 +29,18 @@ jobs: runs-on: ubuntu-latest steps: + - name: Get PR number + id: pr + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.issue.number; + core.setOutput('pr_number', prNumber); + core.exportVariable('PR_NUMBER', prNumber); + + - name: Set App Name + run: echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" >> $GITHUB_ENV + - uses: actions/checkout@v4 - name: Validate Required Secrets @@ -46,7 +58,10 @@ jobs: fi - name: Setup Environment - uses: ./.github/actions/setup-environment + uses: ./.github/actions/setup-environment@justin808-working-for-deploys + with: + org: ${{ env.CPLN_ORG }} + token: ${{ env.CPLN_TOKEN }} - name: Set shared functions id: shared-functions @@ -105,10 +120,11 @@ jobs: issue_number: process.env.PR_NUMBER, owner: context.repo.owner, repo: context.repo.repo, + body: '🗑️ Starting app deletion...' body: [ message, '', - ' [View Delete Logs](' + process.env.WORKFLOW_URL + ')', + ' 🗑️ [View Delete Logs](' + process.env.WORKFLOW_URL + ')', '', getConsoleLink(process.env.PR_NUMBER) ].join('\n') @@ -116,12 +132,14 @@ jobs: return { commentId: comment.data.id }; - name: Delete Review App - uses: ./.github/actions/delete-control-plane-app + uses: ./.github/actions/delete-control-plane-app@justin808-working-for-deploys with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} env: + APP_NAME: ${{ env.APP_NAME }} + CPLN_ORG: ${{ secrets.CPLN_ORG }} CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} - name: Update Delete Status @@ -133,6 +151,7 @@ jobs: const success = '${{ job.status }}' === 'success'; const prNumber = process.env.PR_NUMBER; + const cpConsoleUrl = `https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME}`; const successMessage = [ '✅ Review app for PR #' + prNumber + ' was successfully deleted', diff --git a/.github/workflows/deploy-to-control-plane-staging.yml b/.github/workflows/deploy-to-control-plane-staging.yml index 095c635a..b56511b1 100644 --- a/.github/workflows/deploy-to-control-plane-staging.yml +++ b/.github/workflows/deploy-to-control-plane-staging.yml @@ -13,8 +13,8 @@ on: # Convert the GitHub secret variables to environment variables for use by the Control Plane CLI env: - CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}} - CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}} + CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} jobs: deploy-to-control-plane-staging: @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 # Fetch all history for proper SHA handling ref: master # Explicitly checkout master branch - - uses: ./.github/actions/deploy-to-control-plane + - uses: ./.github/actions/deploy-to-control-plane@justin808-working-for-deploys with: - app_name: ${{ secrets.APP_NAME_STAGING }} - org: ${{ secrets.CPLN_ORG_STAGING }} + app_name: ${{ vars.STAGING_APP_NAME }} + org: ${{ vars.CPLN_ORG_STAGING }} diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 9cdc4599..35e26082 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -3,31 +3,29 @@ name: Deploy Review App to Control Plane run-name: ${{ github.event_name == 'issue_comment' && 'Deploying Review App' || format('Updating Review App for {0}', github.ref_name) }} on: + pull_request: + types: [opened, synchronize, reopened] issue_comment: types: [created] - push: - branches-ignore: - - main # Don't run on main branch pushes - - master # Don't run on master branch pushes # Use concurrency to cancel in-progress runs concurrency: - group: deploy-pr-${{ github.event.issue.number }} + group: deploy-pr-${{ github.event.pull_request.number || github.event.issue.number }} cancel-in-progress: true env: - CPLN_ORG: ${{ secrets.CPLN_ORG }} - CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} + APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} + CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }} + PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: Process-Deployment-Command: - # For issue comments, only run on /deploy-review-app command - # For push events, only run if PR exists and has a review app if: | + (github.event_name == 'pull_request') || (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '/deploy-review-app') || - github.event_name == 'push' + github.event.comment.body == '/deploy-review-app') runs-on: ubuntu-latest permissions: contents: read @@ -39,36 +37,29 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || steps.getRef.outputs.PR_REF || github.ref }} - name: Setup Environment - uses: ./.github/actions/setup-environment - - - name: Get PR Number for Push Event - if: github.event_name == 'push' - id: get-pr - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Get PR number from branch - PR_NUMBER=$(gh pr list --head ${{ github.ref_name }} --json number --jq '.[0].number') - if [ -n "$PR_NUMBER" ]; then - echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV - echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-$PR_NUMBER" >> $GITHUB_ENV - echo "has_pr=true" >> $GITHUB_OUTPUT - else - echo "No PR found for this branch" - exit 0 - fi + uses: ./.github/actions/setup-environment@justin808-working-for-deploys + with: + token: ${{ env.CPLN_TOKEN }} + org: ${{ env.CPLN_ORG }} - - name: Set PR Number for Comment Event + - name: Get PR HEAD Ref if: github.event_name == 'issue_comment' run: | echo "PR_NUMBER=${{ github.event.issue.number }}" >> $GITHUB_ENV echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ github.event.issue.number }}" >> $GITHUB_ENV + # For PR comments, get the actual PR head commit + PR_DATA=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName,headRefOid) + echo "PR_REF=$(echo "$PR_DATA" | jq -r '.headRefName')" >> $GITHUB_OUTPUT + echo "PR_SHA=$(echo "$PR_DATA" | jq -r '.headRefOid')" >> $GITHUB_OUTPUT + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check if Review App Exists id: check-app - if: github.event_name == 'push' && steps.get-pr.outputs.has_pr == 'true' + if: github.event_name == 'push' env: CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} run: | @@ -78,26 +69,44 @@ jobs: fi echo "app_exists=true" >> $GITHUB_OUTPUT - - name: Get PR HEAD Ref - id: getRef - if: | - (github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') - run: | - PR_DATA=$(gh pr view ${{ env.PR_NUMBER }} --repo ${{ github.repository }} --json headRefName,headRefOid) - echo "PR_REF=$(echo "$PR_DATA" | jq -r '.headRefName')" >> $GITHUB_OUTPUT - echo "PR_SHA=$(echo "$PR_DATA" | jq -r '.headRefOid')" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Set Workflow URL + id: workflow-url + uses: actions/github-script@v7 + with: + script: | + async function getWorkflowUrl(runId) { + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: runId + }); + + const currentJob = jobs.data.jobs.find(job => job.status === 'in_progress'); + const jobId = currentJob?.id; + + if (!jobId) { + return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; + } + + return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}`; + } + + const workflowUrl = await getWorkflowUrl(context.runId); + core.exportVariable('WORKFLOW_URL', workflowUrl); + core.exportVariable('GET_CONSOLE_LINK', ` + function getConsoleLink(prNumber) { + return '🎮 [Control Plane Console](' + + 'https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)'; + } + `); - name: Create Initial Comment if: | (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') + ( steps.check-app.outputs.app_exists == 'true') id: create-comment uses: actions/github-script@v7 with: @@ -116,16 +125,11 @@ jobs: (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') + (steps.check-app.outputs.app_exists == 'true') run: echo "COMMENT_ID=${{ fromJSON(steps.create-comment.outputs.result).commentId }}" >> $GITHUB_ENV - - name: Set Workflow URL - if: | - (github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') - id: workflow-url + - name: Initialize Deployment + id: init-deployment uses: actions/github-script@v7 with: script: | @@ -140,33 +144,62 @@ jobs: const jobId = currentJob?.id; if (!jobId) { + console.log('Warning: Could not find current job ID'); return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; } return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}`; } + // Create initial deployment comment + const comment = await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: process.env.PR_NUMBER, + body: '⏳ Initializing deployment...' + }); + + // Create GitHub deployment + const deployment = await github.rest.repos.createDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: context.sha, + environment: 'review', + auto_merge: false, + required_contexts: [] + }); + const workflowUrl = await getWorkflowUrl(context.runId); - core.exportVariable('WORKFLOW_URL', workflowUrl); - core.exportVariable('GET_CONSOLE_LINK', ` - function getConsoleLink(prNumber) { - return '🎮 [Control Plane Console](' + - 'https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)'; - } - `); + + return { + deploymentId: deployment.data.id, + commentId: comment.data.id, + workflowUrl + }; + + - name: Set comment ID and workflow URL + run: | + echo "COMMENT_ID=${{ fromJSON(steps.init-deployment.outputs.result).commentId }}" >> $GITHUB_ENV + echo "WORKFLOW_URL=${{ fromJSON(steps.init-deployment.outputs.result).workflowUrl }}" >> $GITHUB_ENV + + - name: Set commit hash + run: | + FULL_COMMIT="${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }}" + echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV - name: Update Status - Building if: | (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') + (steps.check-app.outputs.app_exists == 'true') uses: actions/github-script@v7 with: script: | eval(process.env.GET_CONSOLE_LINK); const buildingMessage = [ + '🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}', '🏗️ Building Docker image...', '', '📝 [View Build Logs](' + process.env.WORKFLOW_URL + ')', @@ -186,7 +219,7 @@ jobs: (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') + (steps.check-app.outputs.app_exists == 'true') run: git checkout ${{ steps.getRef.outputs.PR_REF }} - name: Build Docker Image @@ -194,12 +227,12 @@ jobs: (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') - uses: ./.github/actions/build-docker-image + (steps.check-app.outputs.app_exists == 'true') + uses: ./.github/actions/build-docker-image@justin808-working-for-deploys with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} - commit: ${{ steps.getRef.outputs.PR_SHA }} + commit: ${{ env.COMMIT_HASH }} PR_NUMBER: ${{ env.PR_NUMBER }} - name: Update Status - Deploying @@ -207,7 +240,7 @@ jobs: (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') + (steps.check-app.outputs.app_exists == 'true') uses: actions/github-script@v7 with: script: | @@ -235,8 +268,8 @@ jobs: (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') - uses: ./.github/actions/deploy-to-control-plane + (steps.check-app.outputs.app_exists == 'true') + uses: ./.github/actions/deploy-to-control-plane@justin808-working-for-deploys with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} @@ -246,26 +279,53 @@ jobs: CPLN_TOKEN: ${{ env.CPLN_TOKEN }} PR_NUMBER: ${{ env.PR_NUMBER }} - - name: Update Status - Success - if: success() + - name: Update Status - Deployment Complete uses: actions/github-script@v7 with: script: | - eval(process.env.GET_CONSOLE_LINK); - + const prNumber = process.env.PR_NUMBER; + const appUrl = process.env.REVIEW_APP_URL; + const workflowUrl = process.env.WORKFLOW_URL; + const isSuccess = '${{ job.status }}' === 'success'; + + const consoleLink = '🎮 [Control Plane Console](https://console.cpln.io/console/org/' + + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)'; + + // Create GitHub deployment status + const deploymentStatus = { + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }}, + state: isSuccess ? 'success' : 'failure', + environment_url: isSuccess ? appUrl : undefined, + log_url: workflowUrl, + environment: 'review' + }; + + await github.rest.repos.createDeploymentStatus(deploymentStatus); + + // Define messages based on deployment status const successMessage = [ - '✅ Deployment successful!', + '✅ Deployment complete for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', '', - '🌐 Review app is ready at: ${{ env.REVIEW_APP_URL }}', + '🚀 [Review App for PR #' + prNumber + '](' + appUrl + ')', + consoleLink, '', - '📝 [View App Logs](' + process.env.WORKFLOW_URL + ')', + '📋 [View Completed Action Build and Deploy Logs](' + workflowUrl + ')' + ].join('\n'); + + const failureMessage = [ + '❌ Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', '', - getConsoleLink(process.env.PR_NUMBER) + consoleLink, + '', + '📋 [View Deployment Logs with Errors](' + workflowUrl + ')' ].join('\n'); + // Update the existing comment await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: process.env.COMMENT_ID, - body: successMessage + body: isSuccess ? successMessage : failureMessage }); diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 8894d034..90f19a2c 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -1,13 +1,12 @@ -name: Show Detailed Help +name: Show Help for Commands on: + push: + branches: + - "**" # Trigger on all branches, including feature branches issue_comment: types: [created] - -# Use concurrency to prevent duplicate runs -concurrency: - group: help-${{ github.event.issue.number }} - cancel-in-progress: true + workflow_dispatch: permissions: issues: write @@ -16,12 +15,17 @@ permissions: jobs: show-help: if: | - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/help' + github.event_name == 'workflow_dispatch' || + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.body == '/help') runs-on: ubuntu-latest steps: + - name: Identify Workflow Branch + run: | + echo "Workflow branch ref: ${{ github.ref }}" + - name: Show Available Commands uses: actions/github-script@v7 with: @@ -42,9 +46,18 @@ jobs: '- Provides a unique URL to preview your changes', '- Shows build and deployment progress in real-time', '', - '**Required Environment Variables:**', - '- `CPLN_TOKEN`: Control Plane authentication token', - '- `CPLN_ORG`: Control Plane organization name', + '**Required Environment Secrets:**', + '- `CPLN_TOKEN_STAGING`: Control Plane authentication token', + '- `CPLN_TOKEN_PRODUCTION`: Control Plane authentication token', + '', + '**Required GitHub Actions Variables:**', + '- `CPLN_ORG_STAGING`: Control Plane authentication token', + '- `CPLN_ORG_PRODUCTION`: Control Plane authentication token', + '', + '**Required GitHub Actions Variables (these need to match your control_plane.yml file:**', + '- `PRODUCTION_APP_NAME`: Control Plane production app name', + '- `STAGING_APP_NAME`: Control Plane staging app name', + '- `REVIEW_APP_PREFIX`: Control Plane review app prefix', '', '**Optional Configuration:**', '- `WAIT_TIMEOUT`: Deployment timeout in seconds (default: 900)', @@ -89,14 +102,10 @@ jobs: 'For more information, see the [React on Rails Tutorial documentation](https://github.com/shakacode/react-on-rails/tree/master/react-webpack-rails-tutorial)' ].join('\n'); - console.log('Issue number:', github.context.payload.issue.number); - console.log('Owner:', context.repo.owner); - console.log('Repo:', context.repo.repo); - await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: github.context.payload.issue.number, + issue_number: context.issue.number, body: helpMessage }); diff --git a/.github/workflows/nightly-remove-stale-review-apps.yml b/.github/workflows/nightly-remove-stale-review-apps.yml index c5f0376a..0e8630f3 100644 --- a/.github/workflows/nightly-remove-stale-review-apps.yml +++ b/.github/workflows/nightly-remove-stale-review-apps.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Environment - uses: ./.github/actions/setup-environment + uses: ./.github/actions/setup-environment@justin808-working-for-deploys - name: Get Stale PRs id: stale_prs diff --git a/.github/workflows/promote-staging-to-production.yml b/.github/workflows/promote-staging-to-production.yml index 04148067..06cea9cd 100644 --- a/.github/workflows/promote-staging-to-production.yml +++ b/.github/workflows/promote-staging-to-production.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Environment - uses: ./.github/actions/setup-environment + uses: ./.github/actions/setup-environment@justin808-working-for-deploys env: CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}