From 9bc9a6a3fcdb25334d0e12b2d4cd75c9046acd24 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 23:43:38 -1000 Subject: [PATCH 01/14] wip --- .github/workflows/delete-review-app.yml | 4 +++- .github/workflows/help-command.yml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index caf90b18..5153626f 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -151,7 +151,9 @@ jobs: const successMessage = [ '✅ Review app for PR #' + prNumber + ' was successfully deleted', '', - ' [View Completed Delete Logs](' + process.env.WORKFLOW_URL + ')' + ' [View Completed Delete Logs](' + process.env.WORKFLOW_URL + ')', + '', + ' [Control Plane Organization](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/-info)' ].join('\n'); const failureMessage = [ diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index ff59b65f..57fafff6 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -31,7 +31,7 @@ jobs: const helpMessage = [ '## 📚 Available Commands', '', - '### `/deploy`', + '### `/deploy-review-app`', 'Deploys your PR branch to a review environment on Control Plane.', '- Creates a new review app if one doesn\'t exist', '- Updates the existing review app if it already exists', @@ -52,7 +52,7 @@ jobs: 'Deletes the review app associated with this PR.', '- Removes all resources from Control Plane', '- Helpful for cleaning up when you\'re done testing', - '- Can be re-deployed later using `/deploy`', + '- Can be re-deployed later using `/deploy-review-app`', '', '**Required Environment Variables:**', '- `CPLN_TOKEN`: Control Plane authentication token', From 8aca18e64965a9ea7ecd6b1b09ec07ec75421305 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 23:52:02 -1000 Subject: [PATCH 02/14] wip --- .github/workflows/delete-review-app.yml | 40 ++++++------------ .github/workflows/deploy-to-control-plane.yml | 42 ------------------- 2 files changed, 13 insertions(+), 69 deletions(-) diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index 5153626f..cf721ab4 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -60,13 +60,11 @@ jobs: } `); - - name: Initialize Delete - id: init-delete + - name: Initialize and Set Workflow URL + id: init-workflow 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({ @@ -87,34 +85,16 @@ jobs: } const workflowUrl = await getWorkflowUrl(context.runId); - - const comment = await github.rest.issues.createComment({ - issue_number: process.env.PR_NUMBER, - owner: context.repo.owner, - repo: context.repo.repo, - body: [ - ' Starting app deletion...', - '', - ' [View Delete Logs](' + workflowUrl + ')', - '', - getConsoleLink(process.env.PR_NUMBER) - ].join('\n') - }); - - return { - commentId: comment.data.id, - workflowUrl - }; - - - name: Set workflow URL - run: | - echo "WORKFLOW_URL=${{ fromJSON(steps.init-delete.outputs.result).workflowUrl }}" >> $GITHUB_ENV + core.exportVariable('WORKFLOW_URL', workflowUrl); + return { workflowUrl }; - name: Create Initial Delete Comment id: init-delete uses: actions/github-script@v7 with: script: | + eval(process.env.GET_CONSOLE_LINK); + let message = '🗑️ Starting app deletion'; if ('${{ github.event_name }}' === 'pull_request') { const merged = '${{ github.event.pull_request.merged }}' === 'true'; @@ -125,7 +105,13 @@ jobs: issue_number: process.env.PR_NUMBER, owner: context.repo.owner, repo: context.repo.repo, - body: message + body: [ + message, + '', + ' [View Delete Logs](' + process.env.WORKFLOW_URL + ')', + '', + getConsoleLink(process.env.PR_NUMBER) + ].join('\n') }); return { commentId: comment.data.id }; diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 2adad3d7..d2d90ab2 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -251,45 +251,3 @@ jobs: comment_id: process.env.COMMENT_ID, body: isSuccess ? successMessage : failureMessage }); - - show-help: - if: | - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/help' - runs-on: ubuntu-latest - - steps: - - name: Show Available Commands - uses: actions/github-script@v7 - with: - script: | - const helpMessage = [ - '## Available Commands', - '', - '### `/deploy-review-app`', - 'Deploys your PR branch to a review environment on Control Plane.', - '- Creates a new review app if one doesn\'t exist', - '- Updates the existing review app if it already exists', - '- Provides a unique URL to preview your changes', - '- Shows build and deployment progress in real-time', - '', - '### `/delete-review-app`', - 'Deletes the review app associated with this PR.', - '- Removes all resources from Control Plane', - '- Helpful for cleaning up when you\'re done testing', - '- Can be re-deployed later using `/deploy-review-app`', - '', - '### `/help`', - 'Shows this help message explaining available commands.', - '', - '---', - '_Note: These commands only work in pull request comments._' - ].join('\n'); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.issue.number, - body: helpMessage - }); \ No newline at end of file From c90b70b564c0925a93d4046f907e8778592bc520 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 23:55:58 -1000 Subject: [PATCH 03/14] wip --- .../workflows/add-comment-on-pr-creation.yml | 36 +++++++++---------- .github/workflows/deploy-to-control-plane.yml | 15 ++++---- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/.github/workflows/add-comment-on-pr-creation.yml b/.github/workflows/add-comment-on-pr-creation.yml index eef586a6..fa686305 100644 --- a/.github/workflows/add-comment-on-pr-creation.yml +++ b/.github/workflows/add-comment-on-pr-creation.yml @@ -10,21 +10,21 @@ jobs: permissions: pull-requests: write steps: - name: Add GitHub Comment for review app instructions - uses: actions/github-script@v7 - with: - script: | - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: [ - "Hi 👋 Here are the commands available for this PR:", - "", - "- `/deploy-review-app`: Deploy your changes to a review environment", - "- `/delete-review-app`: Clean up the review environment when you're done", - "- `/help`: Show detailed information about all commands", - "", - "Use `/help` to see full documentation, including configuration options." - ].join("\n") - }); + - uses: actions/github-script@v7 + name: Add GitHub Comment for review app instructions + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body: [ + "Hi 👋 Here are the commands available for this PR:", + "", + "- `/deploy-review-app`: Deploy your changes to a review environment", + "- `/delete-review-app`: Clean up the review environment when you're done", + "- `/help`: Show detailed information about all commands", + "", + "Use `/help` to see full documentation, including configuration options." + ].join("\n") + }); diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index d2d90ab2..8aba1194 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -3,29 +3,26 @@ name: Deploy Review App to Control Plane run-name: ${{ (github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && github.event.issue.pull_request)) && 'Deploying Review App' || format('Deploying {0} to Staging App', github.ref_name) }} on: - pull_request: - types: [opened, synchronize, reopened] issue_comment: types: [created] # Use concurrency to cancel in-progress runs concurrency: - group: deploy-${{ github.event.pull_request.number || github.event.issue.number }} + group: deploy-${{ github.event.issue.number }} cancel-in-progress: true env: - APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number }} + APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.issue.number }} CPLN_ORG: ${{ secrets.CPLN_ORG }} CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} + PR_NUMBER: ${{ github.event.issue.number }} jobs: Process-Deployment-Command: 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 == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.body == '/deploy-review-app' runs-on: ubuntu-latest permissions: contents: read From 34603d81278dca3294bcbf0c35843c92862261a2 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 00:11:50 -1000 Subject: [PATCH 04/14] wip --- .../deploy-to-control-plane/action.yml | 8 ++++ .../deploy-to-control-plane/scripts/deploy.sh | 48 ++++++++++++------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 1e5c9fa7..8d34d7e8 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -37,6 +37,14 @@ runs: GITHUB_TOKEN: ${{ inputs.github_token }} PR_NUMBER: ${{ env.PR_NUMBER }} + - name: Setup Control Plane App If It Doesn't Exist + shell: bash + run: | + if ! cpflow exists -a ${{ inputs.app_name }} ; then + echo " Setting up new Control Plane app for app ${{ inputs.app_name }}..." + cpflow setup-app -a ${{ inputs.app_name }} + fi + - name: Deploy to Control Plane id: deploy shell: bash diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index 9d070b64..d9460822 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -1,7 +1,7 @@ #!/bin/bash # This script handles the deployment to Control Plane and extracts the Rails URL -# +# # Required environment variables: # - APP_NAME: Name of the application to deploy # - CPLN_ORG: Control Plane organization @@ -31,21 +31,33 @@ trap 'rm -f "$TEMP_OUTPUT"' EXIT # Deploy the application echo "🚀 Deploying to Control Plane (timeout: ${WAIT_TIMEOUT}s)" -if timeout "$WAIT_TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then - # Extract Rails URL from deployment output - RAILS_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "$TEMP_OUTPUT" | head -n1) - if [ -n "$RAILS_URL" ]; then - echo "rails_url=$RAILS_URL" >> "$GITHUB_OUTPUT" - echo "✅ Deployment successful" - echo "🚀 Rails URL: $RAILS_URL" - else - echo "❌ Failed to extract Rails URL from deployment output" - exit 1 - fi -elif [ $? -eq 124 ]; then - echo "❌ Deployment timed out after $WAIT_TIMEOUT seconds" - exit 1 -else - echo "❌ Deployment to Control Plane failed" - exit 1 +if ! timeout "$WAIT_TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then + echo "❌ Deployment failed" + echo "Error output:" + exit 1 +fi + +# Extract app URL from deployment output +RAILS_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "$TEMP_OUTPUT" | head -n1) +if [ -z "$RAILS_URL" ]; then + echo "❌ Failed to get app URL from deployment output" + exit 1 fi + +# Wait for all workloads to be ready +echo "⏳ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)" +if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"$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" + fi + echo "Full output:" + cat "$TEMP_OUTPUT" + exit 1 +fi + +echo "✅ Deployment successful" +echo "🌐 Rails URL: $RAILS_URL" +echo "rails_url=$RAILS_URL" >> "$GITHUB_OUTPUT" From 5b451faef526647d2a98916facabb6b8bf424a1a Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 00:28:03 -1000 Subject: [PATCH 05/14] big-refactor-might-not-work --- .../deploy-to-control-plane/action.yml | 280 ++++++++++++++---- .../deploy-to-control-plane/scripts/deploy.sh | 3 + .github/workflows/delete-review-app.yml | 4 +- .github/workflows/deploy-to-control-plane.yml | 211 +------------ 4 files changed, 238 insertions(+), 260 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 8d34d7e8..8aef8752 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -26,74 +26,240 @@ outputs: runs: using: "composite" steps: + - name: Validate Required Secrets + shell: bash + run: | + missing_secrets=() + for secret in "CPLN_TOKEN" "CPLN_ORG"; do + if [ -z "${!secret}" ]; then + missing_secrets+=("$secret") + fi + done + + if [ ${#missing_secrets[@]} -ne 0 ]; then + echo "Required secrets are not set: ${missing_secrets[*]}" + exit 1 + fi + - name: Setup Environment uses: ./.github/actions/setup-environment - - name: Get Commit SHA - id: get_sha + - 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: ${{ github.action_path }}/scripts/get-commit-sha.sh - env: - GITHUB_TOKEN: ${{ inputs.github_token }} - PR_NUMBER: ${{ env.PR_NUMBER }} + run: | + FULL_COMMIT=$(git rev-parse HEAD) + echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV - - name: Setup Control Plane App If It Doesn't Exist + - 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 shell: bash run: | + echo "🔧 Checking if app exists..." if ! cpflow exists -a ${{ inputs.app_name }} ; then - echo " Setting up new Control Plane app for app ${{ inputs.app_name }}..." + echo "📦 Setting up new Control Plane app..." cpflow setup-app -a ${{ inputs.app_name }} fi + echo "🔧 Ensuring rails template is applied..." + if ! cpflow list-workloads -a ${{ inputs.app_name }} --org ${{ inputs.org }} | grep -q "rails"; then + echo "📦 Applying rails template..." + if ! cpflow apply-template rails -a ${{ inputs.app_name }} --org ${{ inputs.org }}; then + echo "❌ Failed to apply rails template" + exit 1 + fi + 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: Build Docker Image + uses: ./.github/actions/build-docker-image + with: + app_name: ${{ inputs.app_name }} + org: ${{ inputs.org }} + commit: ${{ env.COMMIT_HASH }} + PR_NUMBER: ${{ env.PR_NUMBER }} + + - 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 + }); + - name: Deploy to Control Plane id: deploy shell: bash - 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 }}} - if ! [[ "${WAIT_TIMEOUT}" =~ ^[0-9]+$ ]]; then - echo "❌ Invalid timeout value: ${WAIT_TIMEOUT}" - exit 1 - fi - 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 + 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 + }); diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index d9460822..bc5e9d67 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -34,6 +34,7 @@ echo "🚀 Deploying to Control Plane (timeout: ${WAIT_TIMEOUT}s)" if ! timeout "$WAIT_TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then echo "❌ Deployment failed" echo "Error output:" + cat "$TEMP_OUTPUT" exit 1 fi @@ -41,6 +42,8 @@ fi RAILS_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "$TEMP_OUTPUT" | head -n1) if [ -z "$RAILS_URL" ]; then echo "❌ Failed to get app URL from deployment output" + echo "Deployment output:" + cat "$TEMP_OUTPUT" exit 1 fi diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index cf721ab4..06416363 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -89,7 +89,7 @@ jobs: return { workflowUrl }; - name: Create Initial Delete Comment - id: init-delete + id: create-delete-comment uses: actions/github-script@v7 with: script: | @@ -153,6 +153,6 @@ jobs: await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, - comment_id: ${{ fromJSON(steps.init-delete.outputs.result).commentId }}, + comment_id: ${{ fromJSON(steps.create-delete-comment.outputs.result).commentId }}, body: success ? successMessage : failureMessage }); diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 8aba1194..a55ed7bd 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,6 +1,6 @@ name: Deploy Review App to Control Plane -run-name: ${{ (github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && github.event.issue.pull_request)) && 'Deploying Review App' || format('Deploying {0} to Staging App', github.ref_name) }} +run-name: ${{ github.event_name == 'issue_comment' && 'Deploying Review App' || format('Deploying {0} to Staging App', github.ref_name) }} on: issue_comment: @@ -31,164 +31,21 @@ jobs: issues: write steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Get PR HEAD Ref - if: github.event_name == 'issue_comment' id: getRef run: | - # 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 }} - - 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: Validate Required Secrets - run: | - missing_secrets=() - for secret in "CPLN_TOKEN" "CPLN_ORG"; do - if [ -z "${!secret}" ]; then - missing_secrets+=("$secret") - fi - done - - if [ ${#missing_secrets[@]} -ne 0 ]; then - echo "Required secrets are not set: ${missing_secrets[*]}" - exit 1 - fi - - - 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); - - 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 - 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 }}', - '', - ' [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: Build Docker Image - uses: ./.github/actions/build-docker-image - with: - app_name: ${{ env.APP_NAME }} - org: ${{ env.CPLN_ORG }} - commit: ${{ env.COMMIT_HASH }} - PR_NUMBER: ${{ env.PR_NUMBER }} - - - 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 - }); + - name: Checkout PR Branch + run: git checkout ${{ steps.getRef.outputs.PR_REF }} - name: Deploy to Control Plane uses: ./.github/actions/deploy-to-control-plane @@ -197,54 +54,6 @@ jobs: org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} wait_timeout: ${{ vars.WAIT_TIMEOUT || 900 }} - - - 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'; - - // 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 complete for PR #' + prNumber + ', commit ' + '${{ 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 ' + '${{ 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 - }); + env: + CPLN_TOKEN: ${{ env.CPLN_TOKEN }} + PR_NUMBER: ${{ env.PR_NUMBER }} From 160c7852cc2333c9ff4026acc21c0ce36201a30f Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 00:36:44 -1000 Subject: [PATCH 06/14] big-refactor-might-not-work --- .github/workflows/deploy-to-control-plane.yml | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index a55ed7bd..675eb7ab 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -5,24 +5,30 @@ run-name: ${{ github.event_name == 'issue_comment' && 'Deploying Review App' || on: 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-${{ github.event.issue.number }} + group: deploy-pr-${{ github.event.issue.number }} cancel-in-progress: true env: - APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.issue.number }} CPLN_ORG: ${{ secrets.CPLN_ORG }} CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} - PR_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 == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/deploy-review-app' + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.body == '/deploy-review-app') || + (github.event_name == 'push' && + github.event.pull_request) runs-on: ubuntu-latest permissions: contents: read @@ -35,10 +41,47 @@ jobs: with: fetch-depth: 0 + - 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 + else + echo "No PR found for this branch" + exit 0 + fi + + - name: Set PR Number for Comment Event + 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 + + - name: Check if Review App Exists + id: check-app + if: github.event_name == 'push' + env: + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} + run: | + if ! cpflow exists -a ${{ env.APP_NAME }}; then + echo "No review app exists for this PR" + exit 0 + fi + echo "app_exists=true" >> $GITHUB_OUTPUT + - name: Get PR HEAD Ref id: getRef run: | - PR_DATA=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName,headRefOid) + 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: @@ -48,6 +91,7 @@ jobs: run: git checkout ${{ steps.getRef.outputs.PR_REF }} - name: Deploy to Control Plane + if: github.event_name == 'issue_comment' || steps.check-app.outputs.app_exists == 'true' uses: ./.github/actions/deploy-to-control-plane with: app_name: ${{ env.APP_NAME }} From c8500cd90ba188cec300ac0b1bc0cf2b30a7f453 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 00:40:11 -1000 Subject: [PATCH 07/14] big-refactor-might-not-work --- .github/workflows/delete-review-app.yml | 2 +- .github/workflows/deploy-to-control-plane.yml | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index 06416363..a031d434 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -60,7 +60,7 @@ jobs: } `); - - name: Initialize and Set Workflow URL + - name: Initialize Workflow id: init-workflow uses: actions/github-script@v7 with: diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 675eb7ab..0d5ef737 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,6 +1,6 @@ name: Deploy Review App to Control Plane -run-name: ${{ github.event_name == 'issue_comment' && 'Deploying Review App' || format('Deploying {0} to Staging App', github.ref_name) }} +run-name: ${{ github.event_name == 'issue_comment' && 'Deploying Review App' || format('Updating Review App for {0}', github.ref_name) }} on: issue_comment: @@ -27,8 +27,7 @@ jobs: (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/deploy-review-app') || - (github.event_name == 'push' && - github.event.pull_request) + github.event_name == 'push' runs-on: ubuntu-latest permissions: contents: read @@ -55,6 +54,7 @@ jobs: 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 @@ -68,7 +68,7 @@ jobs: - name: Check if Review App Exists id: check-app - if: github.event_name == 'push' + if: github.event_name == 'push' && steps.get-pr.outputs.has_pr == 'true' env: CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} run: | @@ -80,6 +80,9 @@ jobs: - name: Get PR HEAD Ref id: getRef + if: | + github.event_name == 'issue_comment' || + (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 @@ -88,10 +91,15 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Checkout PR Branch + if: | + github.event_name == 'issue_comment' || + (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') run: git checkout ${{ steps.getRef.outputs.PR_REF }} - name: Deploy to Control Plane - if: github.event_name == 'issue_comment' || steps.check-app.outputs.app_exists == 'true' + if: | + github.event_name == 'issue_comment' || + (steps.get-pr.outputs.has_pr == 'true' && steps.check-app.outputs.app_exists == 'true') uses: ./.github/actions/deploy-to-control-plane with: app_name: ${{ env.APP_NAME }} From d256c0cdaf4310109ca04588935df6379ab63fa1 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 00:47:50 -1000 Subject: [PATCH 08/14] big-refactor-might-not-work --- .github/actions/deploy-to-control-plane/scripts/deploy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index bc5e9d67..d973ebc8 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -31,9 +31,9 @@ trap 'rm -f "$TEMP_OUTPUT"' EXIT # Deploy the application echo "🚀 Deploying to Control Plane (timeout: ${WAIT_TIMEOUT}s)" -if ! timeout "$WAIT_TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then +if ! timeout "${WAIT_TIMEOUT}" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose 2>&1 | tee "$TEMP_OUTPUT"; then echo "❌ Deployment failed" - echo "Error output:" + echo "Full output:" cat "$TEMP_OUTPUT" exit 1 fi From ef8801643602bb88b220d9d86cf048493049ab07 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 00:52:52 -1000 Subject: [PATCH 09/14] big-refactor-might-not-work --- .../deploy-to-control-plane/action.yml | 8 ------- .../deploy-to-control-plane/scripts/deploy.sh | 11 +++++++++- .github/workflows/deploy-to-control-plane.yml | 21 +++++++++++++++++-- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 8aef8752..2d2a8073 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -172,14 +172,6 @@ runs: body: buildingMessage }); - - name: Build Docker Image - uses: ./.github/actions/build-docker-image - with: - app_name: ${{ inputs.app_name }} - org: ${{ inputs.org }} - commit: ${{ env.COMMIT_HASH }} - PR_NUMBER: ${{ env.PR_NUMBER }} - - name: Update Status - Deploying uses: actions/github-script@v7 with: diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index d973ebc8..fcb7c138 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -29,6 +29,15 @@ fi TEMP_OUTPUT=$(mktemp) trap 'rm -f "$TEMP_OUTPUT"' EXIT +# Build the Docker image +echo "🏗️ Building Docker image" +if ! cpflow build-image -a "$APP_NAME" --org "$CPLN_ORG" --verbose 2>&1 | tee "$TEMP_OUTPUT"; then + echo "❌ Image build failed" + echo "Full output:" + cat "$TEMP_OUTPUT" + exit 1 +fi + # Deploy the application echo "🚀 Deploying to Control Plane (timeout: ${WAIT_TIMEOUT}s)" if ! timeout "${WAIT_TIMEOUT}" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose 2>&1 | tee "$TEMP_OUTPUT"; then @@ -42,7 +51,7 @@ fi RAILS_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "$TEMP_OUTPUT" | head -n1) if [ -z "$RAILS_URL" ]; then echo "❌ Failed to get app URL from deployment output" - echo "Deployment output:" + echo "Full output:" cat "$TEMP_OUTPUT" exit 1 fi diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 0d5ef737..b2cb76b0 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -92,13 +92,30 @@ jobs: - name: Checkout PR Branch if: | - github.event_name == 'issue_comment' || + (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: git checkout ${{ steps.getRef.outputs.PR_REF }} + - name: Build Docker Image + 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') + uses: ./.github/actions/build-docker-image + with: + app_name: ${{ env.APP_NAME }} + org: ${{ env.CPLN_ORG }} + commit: ${{ steps.getRef.outputs.PR_SHA }} + PR_NUMBER: ${{ env.PR_NUMBER }} + - name: Deploy to Control Plane if: | - github.event_name == 'issue_comment' || + (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 with: From 1917948c89ed3d4e9bd68c2bea39e72b707ad074 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 01:05:01 -1000 Subject: [PATCH 10/14] big-refactor-might-not-work --- .github/workflows/deploy-to-control-plane.yml | 145 +++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index b2cb76b0..9cdc4599 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -81,7 +81,9 @@ jobs: - name: Get PR HEAD Ref id: getRef if: | - github.event_name == 'issue_comment' || + (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) @@ -90,6 +92,95 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - 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') + id: create-comment + uses: actions/github-script@v7 + with: + script: | + const result = await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: process.env.PR_NUMBER, + body: '🚀 Starting deployment process...' + }); + console.log('Created comment:', result.data.id); + return { commentId: result.data.id }; + + - name: Set Comment ID + 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: 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 + 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: 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') + uses: actions/github-script@v7 + with: + script: | + eval(process.env.GET_CONSOLE_LINK); + + const buildingMessage = [ + '🏗️ Building Docker image...', + '', + '📝 [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: Checkout PR Branch if: | (github.event_name == 'issue_comment' && @@ -111,6 +202,34 @@ jobs: commit: ${{ steps.getRef.outputs.PR_SHA }} PR_NUMBER: ${{ env.PR_NUMBER }} + - name: Update Status - Deploying + 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') + 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 + }); + - name: Deploy to Control Plane if: | (github.event_name == 'issue_comment' && @@ -126,3 +245,27 @@ jobs: env: CPLN_TOKEN: ${{ env.CPLN_TOKEN }} PR_NUMBER: ${{ env.PR_NUMBER }} + + - name: Update Status - Success + if: success() + uses: actions/github-script@v7 + with: + script: | + eval(process.env.GET_CONSOLE_LINK); + + const successMessage = [ + '✅ Deployment successful!', + '', + '🌐 Review app is ready at: ${{ env.REVIEW_APP_URL }}', + '', + '📝 [View App 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: successMessage + }); From d688a87c2cf6a06922e6bca5d8d5b1891b9d06bb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 01:11:00 -1000 Subject: [PATCH 11/14] big-refactor-might-not-work --- .github/workflows/delete-review-app.yml | 8 ++--- .github/workflows/review-app-help.yml | 42 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/review-app-help.yml diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index a031d434..fa24902c 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -55,13 +55,13 @@ jobs: 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 + ')'; + return '🎮 [Control Plane Console](' + + 'https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)'; } `); - - name: Initialize Workflow - id: init-workflow + - name: Setup Workflow URL + id: setup-workflow-url uses: actions/github-script@v7 with: script: | diff --git a/.github/workflows/review-app-help.yml b/.github/workflows/review-app-help.yml new file mode 100644 index 00000000..4d74bc57 --- /dev/null +++ b/.github/workflows/review-app-help.yml @@ -0,0 +1,42 @@ +name: Review App Help + +on: + pull_request: + types: [opened] + issue_comment: + types: [created] + +permissions: + pull-requests: write + issues: write + +jobs: + Post-Help-Message: + if: | + (github.event_name == 'pull_request') || + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.body == '/show-help') + runs-on: ubuntu-latest + + steps: + - name: Post Help Message + uses: actions/github-script@v7 + with: + script: | + const helpMessage = [ + '## Review App Commands', + '', + '- `/deploy-review-app` - Deploy a review app for this PR', + '- `/delete-review-app` - Delete the review app for this PR', + '- `/show-help` - Show this help message', + '', + 'The review app will be automatically deleted when the PR is closed or merged.' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number || context.payload.pull_request.number, + body: helpMessage + }); From a84e3e806aba9de622c6c7bb8f612de6ad9d48e2 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 01:19:56 -1000 Subject: [PATCH 12/14] help-commands --- .github/workflows/help-command.yml | 32 +++++++++++--- .github/workflows/review-app-help.yml | 64 ++++++++++++++++----------- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 57fafff6..8894d034 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -1,4 +1,4 @@ -name: Show Help for Commands +name: Show Detailed Help on: issue_comment: @@ -27,9 +27,13 @@ jobs: with: script: | try { - console.log('Creating help message...'); + console.log('Creating detailed help message...'); const helpMessage = [ - '## 📚 Available Commands', + '# 📚 Detailed Review App Commands Guide', + '', + 'This is a detailed guide to using review app commands. For a quick reference, see the message posted when your PR was created.', + '', + '## Available Commands', '', '### `/deploy-review-app`', 'Deploys your PR branch to a review environment on Control Plane.', @@ -59,16 +63,30 @@ jobs: '- `CPLN_ORG`: Control Plane organization name', '', '### `/help`', - 'Shows this help message explaining available commands and configuration.', + 'Shows this detailed help message.', '', '---', - '**Note:** These commands only work in pull request comments.', + '## Environment Setup', '', - '**Environment Setup:**', '1. Set required secrets in your repository settings:', ' - `CPLN_TOKEN`', ' - `CPLN_ORG`', - '2. Optional: Configure `WAIT_TIMEOUT` in GitHub Actions variables to customize deployment timeout' + '', + '2. Optional: Configure `WAIT_TIMEOUT` in GitHub Actions variables to customize deployment timeout', + '', + '## Control Plane Integration', + '', + 'Review apps are deployed to Control Plane with the following configuration:', + '- App Name Format: `qa-react-webpack-rails-tutorial-pr-{PR_NUMBER}`', + '- Console URL: `https://console.cpln.io/console/org/{CPLN_ORG}/gvc/{APP_NAME}/-info`', + '', + '## Automatic Cleanup', + '', + 'Review apps are automatically deleted when:', + '- The PR is closed (merged or not merged)', + '- The PR is stale (via nightly cleanup job)', + '', + '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); diff --git a/.github/workflows/review-app-help.yml b/.github/workflows/review-app-help.yml index 4d74bc57..313101e4 100644 --- a/.github/workflows/review-app-help.yml +++ b/.github/workflows/review-app-help.yml @@ -1,42 +1,52 @@ -name: Review App Help +name: Show Quick Help on PR Creation on: pull_request: types: [opened] - issue_comment: - types: [created] permissions: - pull-requests: write issues: write + pull-requests: write jobs: - Post-Help-Message: - if: | - (github.event_name == 'pull_request') || - (github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/show-help') + show-quick-help: + if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - - name: Post Help Message + - name: Show Quick Reference uses: actions/github-script@v7 with: script: | - const helpMessage = [ - '## Review App Commands', - '', - '- `/deploy-review-app` - Deploy a review app for this PR', - '- `/delete-review-app` - Delete the review app for this PR', - '- `/show-help` - Show this help message', - '', - 'The review app will be automatically deleted when the PR is closed or merged.' - ].join('\n'); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number || context.payload.pull_request.number, - body: helpMessage - }); + try { + console.log('Creating quick reference message...'); + const helpMessage = [ + '# 🚀 Quick Review App Commands', + '', + 'Welcome! Here are the commands you can use in this PR:', + '', + '### `/deploy-review-app`', + 'Deploy your PR branch for testing', + '', + '### `/delete-review-app`', + 'Remove the review app when done', + '', + '### `/help`', + 'Show detailed documentation', + '', + '---', + '**Note:** Type `/help` for detailed instructions, environment setup, and configuration options.' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: helpMessage + }); + + console.log('Quick reference posted successfully'); + } catch (error) { + console.error('Error posting quick reference:', error); + core.setFailed(`Failed to post quick reference: ${error.message}`); + } From 515ae370b91abd35aa791929133c33374fa031b0 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 01:29:09 -1000 Subject: [PATCH 13/14] wip --- .github/actions/deploy-to-control-plane/action.yml | 9 --------- .../actions/deploy-to-control-plane/scripts/deploy.sh | 9 --------- .github/workflows/deploy-to-control-plane.yml | 2 +- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 2d2a8073..b8f9b733 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -142,15 +142,6 @@ runs: cpflow setup-app -a ${{ inputs.app_name }} fi - echo "🔧 Ensuring rails template is applied..." - if ! cpflow list-workloads -a ${{ inputs.app_name }} --org ${{ inputs.org }} | grep -q "rails"; then - echo "📦 Applying rails template..." - if ! cpflow apply-template rails -a ${{ inputs.app_name }} --org ${{ inputs.org }}; then - echo "❌ Failed to apply rails template" - exit 1 - fi - fi - - name: Update Status - Building uses: actions/github-script@v7 with: diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index fcb7c138..73bb8968 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -29,15 +29,6 @@ fi TEMP_OUTPUT=$(mktemp) trap 'rm -f "$TEMP_OUTPUT"' EXIT -# Build the Docker image -echo "🏗️ Building Docker image" -if ! cpflow build-image -a "$APP_NAME" --org "$CPLN_ORG" --verbose 2>&1 | tee "$TEMP_OUTPUT"; then - echo "❌ Image build failed" - echo "Full output:" - cat "$TEMP_OUTPUT" - exit 1 -fi - # Deploy the application echo "🚀 Deploying to Control Plane (timeout: ${WAIT_TIMEOUT}s)" if ! timeout "${WAIT_TIMEOUT}" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose 2>&1 | tee "$TEMP_OUTPUT"; then diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 9cdc4599..2de7d655 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,6 +1,6 @@ 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) }} +run-name: ${{ github.event_name == 'issue_comment' && format('Deploying Review App for PR #{0}', github.event.issue.number) || format('Updating Review App for PR #{0}', env.PR_NUMBER) }} on: issue_comment: From fcc1ce02d504e57a1d92f6998739a4863e10eb2c Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 26 Jan 2025 01:33:43 -1000 Subject: [PATCH 14/14] wip --- .github/workflows/deploy-to-control-plane.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 2de7d655..9cdc4599 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,6 +1,6 @@ name: Deploy Review App to Control Plane -run-name: ${{ github.event_name == 'issue_comment' && format('Deploying Review App for PR #{0}', github.event.issue.number) || format('Updating Review App for PR #{0}', env.PR_NUMBER) }} +run-name: ${{ github.event_name == 'issue_comment' && 'Deploying Review App' || format('Updating Review App for {0}', github.ref_name) }} on: issue_comment: