From 180ee9093227fc7f2c4da235e1cf1cf059b738ce Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Mon, 27 Jan 2025 23:40:39 -1000 Subject: [PATCH 1/3] clean up duplicates --- .../deploy-to-control-plane/action.yml | 74 +------------ .../scripts/get-commit-sha.sh | 34 ------ .github/workflows/deploy-to-control-plane.yml | 103 ++++++++++++++---- 3 files changed, 84 insertions(+), 127 deletions(-) delete mode 100755 .github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 3ec17068..fcb68439 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -32,80 +32,16 @@ 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 - shell: bash - run: ${{ github.action_path }}/scripts/get-commit-sha.sh - env: - GITHUB_TOKEN: ${{ inputs.github_token }} - PR_NUMBER: ${{ inputs.pr_number }} - - name: Deploy to Control Plane id: deploy shell: bash env: + APP_NAME: ${{ inputs.app_name }} + CPLN_ORG: ${{ inputs.org }} CPLN_TOKEN: ${{ inputs.cpln_token }} - PR_NUMBER: ${{ inputs.pr_number }} + WAIT_TIMEOUT: ${{ inputs.wait_timeout }} 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}" + # Run the deployment script + if ! ${{ github.action_path }}/scripts/deploy.sh; then 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/deploy-to-control-plane/scripts/get-commit-sha.sh b/.github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh deleted file mode 100755 index 9dd32cd0..00000000 --- a/.github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# This script retrieves the commit SHA for deployment -# It handles both PR and direct branch deployments -# -# Required environment variables: -# - PR_NUMBER: Pull request number (optional) -# - GITHUB_TOKEN: GitHub token for API access -# -# Outputs: -# - sha: Full commit SHA -# - sha_short: Short (7 char) commit SHA - -set -e - -if [ -n "${PR_NUMBER}" ]; then - # If PR_NUMBER is set, get the PR's head SHA - if ! PR_SHA=$(gh pr view "${PR_NUMBER}" --json headRefOid --jq '.headRefOid'); then - echo "Failed to get PR head SHA" >&2 - exit 1 - fi - echo "sha=${PR_SHA}" >> "$GITHUB_OUTPUT" - echo "sha_short=${PR_SHA:0:7}" >> "$GITHUB_OUTPUT" - echo "Using PR head commit SHA: ${PR_SHA:0:7}" -else - # For direct branch deployments, use the current commit SHA - if ! CURRENT_SHA=$(git rev-parse HEAD); then - echo "Failed to get current SHA" >&2 - exit 1 - fi - echo "sha=${CURRENT_SHA}" >> "$GITHUB_OUTPUT" - echo "sha_short=${CURRENT_SHA:0:7}" >> "$GITHUB_OUTPUT" - echo "Using branch commit SHA: ${CURRENT_SHA:0:7}" -fi diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 60f081c3..c52cee31 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -24,7 +24,7 @@ concurrency: cancel-in-progress: true env: - APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }} + APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }} CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }} @@ -62,27 +62,61 @@ jobs: with: fetch-depth: 0 + - name: Validate Required Secrets and Variables + shell: bash + run: | + missing=() + + # Check secrets + if [ -z "${{ secrets.CPLN_TOKEN_STAGING }}" ]; then + missing+=("Secret: CPLN_TOKEN_STAGING") + fi + + # Check variables + if [ -z "${{ vars.CPLN_ORG_STAGING }}" ]; then + missing+=("Variable: CPLN_ORG_STAGING") + fi + + if [ -z "${{ vars.REVIEW_APP_PREFIX }}" ]; then + missing+=("Variable: REVIEW_APP_PREFIX") + fi + + if [ ${#missing[@]} -ne 0 ]; then + echo "Required secrets/variables are not set: ${missing[*]}" + exit 1 + fi + - name: Get PR HEAD Ref id: getRef env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - PR_NUMBER="${{ github.event.inputs.pr }}" - elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then - PR_NUMBER="${{ github.event.issue.number }}" - elif [[ "${{ github.event_name }}" == "pull_request" ]]; then - PR_NUMBER="${{ github.event.pull_request.number }}" - elif [[ "${{ github.event_name }}" == "push" ]]; then - # For push events, find associated PR - PR_DATA=$(gh pr list --head "${{ github.ref_name }}" --json number --jq '.[0].number') - if [[ -n "$PR_DATA" ]]; then - PR_NUMBER="$PR_DATA" - else - echo "Error: No PR found for branch ${{ github.ref_name }}" + # Get PR number based on event type + case "${{ github.event_name }}" in + "workflow_dispatch") + PR_NUMBER="${{ github.event.inputs.pr_number }}" + ;; + "issue_comment") + PR_NUMBER="${{ github.event.issue.number }}" + ;; + "pull_request") + PR_NUMBER="${{ github.event.pull_request.number }}" + ;; + "push") + # For push events, find associated PR + PR_DATA=$(gh pr list --head "${{ github.ref_name }}" --json number --jq '.[0].number') + if [[ -n "$PR_DATA" ]]; then + PR_NUMBER="$PR_DATA" + else + echo "Error: No PR found for branch ${{ github.ref_name }}" + exit 1 + fi + ;; + *) + echo "Error: Unsupported event type ${{ github.event_name }}" exit 1 - fi - fi + ;; + esac if [[ -z "$PR_NUMBER" ]]; then echo "Error: Could not determine PR number" @@ -91,7 +125,7 @@ jobs: # Set environment variables echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV - echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-$PR_NUMBER" >> $GITHUB_ENV + echo "APP_NAME=${{ vars.REVIEW_APP_PREFIX }}-$PR_NUMBER" >> $GITHUB_ENV # Get PR data using GitHub CLI PR_DATA=$(gh pr view $PR_NUMBER --repo shakacode/react-webpack-rails-tutorial --json headRefName,headRefOid) @@ -150,6 +184,7 @@ jobs: - name: Create Initial Comment if: env.DO_DEPLOY != 'false' uses: actions/github-script@v7 + id: create-comment with: script: | const result = await github.rest.issues.createComment({ @@ -160,6 +195,26 @@ jobs: }); core.setOutput('comment-id', result.data.id); + - name: Update Comment - Building + if: env.DO_DEPLOY != 'false' + uses: actions/github-script@v7 + with: + script: | + const buildingMessage = [ + `🏗️ Building Docker image for PR #${process.env.PR_NUMBER}, commit ${process.env.PR_SHA}`, + '', + `📝 [View Build Logs](${process.env.WORKFLOW_URL})`, + '', + process.env.CONSOLE_LINK + ].join('\n'); + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ steps.create-comment.outputs.comment-id }}, + body: buildingMessage + }); + - name: Set Deployment URLs id: set-urls if: env.DO_DEPLOY != 'false' @@ -180,7 +235,7 @@ jobs: core.exportVariable('WORKFLOW_URL', workflowUrl); core.exportVariable('CONSOLE_LINK', '🎮 [Control Plane Console](' + - 'https://console.cpln.io/console/org/' + process.env.CPLN_ORG_STAGING + '/gvc/' + process.env.APP_NAME + '/-info)' + 'https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)' ); - name: Update Status - Building @@ -189,7 +244,7 @@ jobs: with: script: | const buildingMessage = [ - '🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}', + '🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + process.env.PR_SHA, '', '📝 [View Build Logs](' + process.env.WORKFLOW_URL + ')', '', @@ -212,8 +267,8 @@ jobs: uses: ./.github/actions/build-docker-image with: app_name: ${{ env.APP_NAME }} - org: ${{ env.CPLN_ORG_STAGING }} - commit: ${{ env.COMMIT_HASH }} + org: ${{ vars.CPLN_ORG_STAGING }} + commit: ${{ env.PR_SHA }} PR_NUMBER: ${{ env.PR_NUMBER }} - name: Update Status - Deploying @@ -243,7 +298,7 @@ jobs: uses: ./.github/actions/deploy-to-control-plane with: app_name: ${{ env.APP_NAME }} - org: ${{ env.CPLN_ORG_STAGING }} + org: ${{ vars.CPLN_ORG_STAGING }} github_token: ${{ secrets.GITHUB_TOKEN }} wait_timeout: ${{ vars.WAIT_TIMEOUT || 900 }} cpln_token: ${{ secrets.CPLN_TOKEN_STAGING }} @@ -276,7 +331,7 @@ jobs: // Define messages based on deployment status const successMessage = [ - '✅ Deployment complete for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', + '✅ Deployment complete for PR #' + prNumber + ', commit ' + '${{ env.PR_SHA }}', '', '🚀 [Review App for PR #' + prNumber + '](' + appUrl + ')', consoleLink, @@ -285,7 +340,7 @@ jobs: ].join('\n'); const failureMessage = [ - '❌ Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', + '❌ Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.PR_SHA }}', '', consoleLink, '', From 751eb870b071adb4adc773a77043a0e6c03bfd05 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 13:55:10 -1000 Subject: [PATCH 2/3] handle calling cpflow setup for new app --- .../scripts/delete-app.sh | 36 ---- .../deploy-to-control-plane/scripts/deploy.sh | 14 +- .github/workflows/debug-workflow.yml | 36 ++++ .github/workflows/deploy-to-control-plane.yml | 203 +++++++++++++----- 4 files changed, 192 insertions(+), 97 deletions(-) delete mode 100755 .github/actions/deploy-to-control-plane/scripts/delete-app.sh create mode 100644 .github/workflows/debug-workflow.yml diff --git a/.github/actions/deploy-to-control-plane/scripts/delete-app.sh b/.github/actions/deploy-to-control-plane/scripts/delete-app.sh deleted file mode 100755 index 92e8fbc3..00000000 --- a/.github/actions/deploy-to-control-plane/scripts/delete-app.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# Script to delete a Control Plane application -# Required environment variables: -# - APP_NAME: Name of the application to delete -# - CPLN_ORG: Organization name - -set -e - -# Validate required environment variables -: "${APP_NAME:?APP_NAME environment variable is required}" -: "${CPLN_ORG:?CPLN_ORG environment variable is required}" - -# Safety check: prevent deletion of production or staging apps -if echo "$APP_NAME" | grep -iqE '(production|staging)'; then - echo "❌ ERROR: Cannot delete apps containing 'production' or 'staging' in their name" >&2 - echo "🛑 This is a safety measure to prevent accidental deletion of production or staging environments" >&2 - echo " App name: $APP_NAME" >&2 - exit 1 -fi - -# Check if app exists before attempting to delete -echo "🔍 Checking if application exists: $APP_NAME" -if ! cpflow exists -a "$APP_NAME"; then - echo "⚠️ Application does not exist: $APP_NAME" - exit 0 -fi - -# Delete the application -echo "🗑️ Deleting application: $APP_NAME" -if ! cpflow delete -a "$APP_NAME" --force; then - echo "❌ Failed to delete application: $APP_NAME" >&2 - exit 1 -fi - -echo "✅ Successfully deleted application: $APP_NAME" diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index 73bb8968..f90ede23 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -11,7 +11,7 @@ # Must be a positive integer # # Outputs: -# - rails_url: URL of the deployed Rails application +# - ENV APP_URL: URL of the deployed application set -e @@ -39,11 +39,9 @@ if ! timeout "${WAIT_TIMEOUT}" cpflow deploy-image -a "$APP_NAME" --run-release- 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" - echo "Full output:" - cat "$TEMP_OUTPUT" +APP_URL=$(grep -oP 'https://[^[:space:]]*\.cpln\.app(?=\s|$)' "$TEMP_OUTPUT" | head -n1) +if [ -z "$APP_URL" ]; then + echo "❌ Error: Could not find app URL in deployment output" exit 1 fi @@ -62,5 +60,5 @@ if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"$APP_NAME\"" 2>&1 | fi echo "✅ Deployment successful" -echo "🌐 Rails URL: $RAILS_URL" -echo "rails_url=$RAILS_URL" >> "$GITHUB_OUTPUT" +echo "🌐 App URL: $APP_URL" +echo "APP_URL=$APP_URL" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/debug-workflow.yml b/.github/workflows/debug-workflow.yml new file mode 100644 index 00000000..4ee0071a --- /dev/null +++ b/.github/workflows/debug-workflow.yml @@ -0,0 +1,36 @@ +name: Debug Workflow Information + +on: + workflow_call: + inputs: + debug_enabled: + required: false + type: boolean + default: false + description: 'Enable debug logging (defaults to false)' + +jobs: + debug-info: + runs-on: ubuntu-latest + if: inputs.debug_enabled || vars.DEBUG_WORKFLOW == 'true' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Log Branch Info + run: | + echo "Branch for this run:" + if [ "${{ github.event_name }}" == "pull_request" ]; then + echo "Pull Request Source Branch: ${{ github.head_ref }}" + else + echo "Branch: ${{ github.ref_name }}" + fi + + - name: Debug GitHub Context + run: | + echo "Event name: ${{ github.event_name }}" + echo "Event path: ${{ github.event_path }}" + echo "Repository: ${{ github.repository }}" + echo "Full GitHub context:" + echo '${{ toJson(github) }}' \ No newline at end of file diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index c52cee31..d8a9783f 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 +name: Deploy PR Review App to Control Plane -run-name: Deploy Review App - ${{ github.ref_name }} +run-name: Deploy PR Review App - PR #${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }} on: pull_request: @@ -30,14 +30,20 @@ env: PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }} jobs: + debug: + uses: ./.github/workflows/debug-workflow.yml + with: + debug_enabled: false # Will still run if vars.DEBUG_WORKFLOW is true + Process-Deployment-Command: + needs: debug # Add this to ensure debug runs first if: | (github.event_name == 'pull_request') || (github.event_name == 'push') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '/deploy-review-app') + contains(github.event.comment.body, '/deploy-review-app')) runs-on: ubuntu-latest permissions: contents: read @@ -91,51 +97,65 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - # Get PR number based on event type - case "${{ github.event_name }}" in - "workflow_dispatch") - PR_NUMBER="${{ github.event.inputs.pr_number }}" - ;; - "issue_comment") - PR_NUMBER="${{ github.event.issue.number }}" - ;; - "pull_request") - PR_NUMBER="${{ github.event.pull_request.number }}" - ;; - "push") - # For push events, find associated PR - PR_DATA=$(gh pr list --head "${{ github.ref_name }}" --json number --jq '.[0].number') - if [[ -n "$PR_DATA" ]]; then - PR_NUMBER="$PR_DATA" - else - echo "Error: No PR found for branch ${{ github.ref_name }}" + # For push events, try to find associated PR first + if [[ "${{ github.event_name }}" == "push" ]]; then + PR_DATA=$(gh pr list --head "${{ github.ref_name }}" --json number,headRefName,headRefOid --jq '.[0]') + if [[ -n "$PR_DATA" ]]; then + PR_NUMBER=$(echo "$PR_DATA" | jq -r .number) + else + echo "No PR found for branch ${{ github.ref_name }}, skipping deployment" + echo "DO_DEPLOY=false" >> $GITHUB_ENV + exit 0 + fi + else + # Get PR number based on event type + case "${{ github.event_name }}" in + "workflow_dispatch") + PR_NUMBER="${{ github.event.inputs.pr_number }}" + ;; + "issue_comment") + PR_NUMBER="${{ github.event.issue.number }}" + ;; + "pull_request") + PR_NUMBER="${{ github.event.pull_request.number }}" + ;; + *) + echo "Error: Unsupported event type ${{ github.event_name }}" exit 1 - fi - ;; - *) - echo "Error: Unsupported event type ${{ github.event_name }}" - exit 1 - ;; - esac - + ;; + esac + fi + if [[ -z "$PR_NUMBER" ]]; then echo "Error: Could not determine PR number" + echo "Event type: ${{ github.event_name }}" + echo "Event action: ${{ github.event.action }}" + echo "Ref name: ${{ github.ref_name }}" + echo "Available event data:" + echo "- PR number from inputs: ${{ github.event.inputs.pr_number }}" + echo "- PR number from issue: ${{ github.event.issue.number }}" + echo "- PR number from pull_request: ${{ github.event.pull_request.number }}" exit 1 fi - # Set environment variables + # Get PR data + if [[ -z "$PR_DATA" ]]; then + PR_DATA=$(gh pr view "$PR_NUMBER" --json headRefName,headRefOid) + if [[ -z "$PR_DATA" ]]; then + echo "Error: PR DATA for PR #$PR_NUMBER not found" + echo "Event type: ${{ github.event_name }}" + echo "Event action: ${{ github.event.action }}" + echo "Ref name: ${{ github.ref_name }}" + echo "Attempted to fetch PR data with: gh pr view $PR_NUMBER" + exit 1 + fi + fi + + # Extract and set PR data echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV echo "APP_NAME=${{ vars.REVIEW_APP_PREFIX }}-$PR_NUMBER" >> $GITHUB_ENV - - # Get PR data using GitHub CLI - PR_DATA=$(gh pr view $PR_NUMBER --repo shakacode/react-webpack-rails-tutorial --json headRefName,headRefOid) - if [[ $? -eq 0 ]]; then - echo "PR_REF=$(echo $PR_DATA | jq -r .headRefName)" >> $GITHUB_OUTPUT - echo "PR_SHA=$(echo $PR_DATA | jq -r .headRefOid)" >> $GITHUB_ENV - else - echo "Error: Could not fetch PR data for PR #$PR_NUMBER" - exit 1 - fi + echo "PR_REF=$(echo $PR_DATA | jq -r .headRefName)" >> $GITHUB_OUTPUT + echo "PR_SHA=$(echo $PR_DATA | jq -r .headRefOid)" >> $GITHUB_ENV - name: Checkout PR code if: github.event_name == 'workflow_dispatch' || github.event_name == 'issue_comment' @@ -152,7 +172,6 @@ jobs: - name: Check if Review App Exists id: check-app - if: github.event_name == 'pull_request' env: CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} run: | @@ -162,25 +181,64 @@ jobs: exit 1 fi - # Then check if app exists + # Check if app exists and save state if ! cpflow exists -a ${{ env.APP_NAME }}; then - echo "No review app exists for this PR" - echo "DO_DEPLOY=false" >> $GITHUB_ENV + echo "APP_EXISTS=false" >> $GITHUB_ENV else - echo "DO_DEPLOY=true" >> $GITHUB_ENV + echo "APP_EXISTS=true" >> $GITHUB_ENV fi - name: Validate Deployment Request id: validate - if: env.DO_DEPLOY != 'false' run: | + # Skip validation if deployment is already disabled + if [[ "${{ env.DO_DEPLOY }}" == "false" ]]; then + echo "Skipping validation - deployment already disabled" + exit 0 + fi + if ! [[ "${{ github.event_name }}" == "workflow_dispatch" || \ - ("${{ github.event_name }}" == "issue_comment" && "${{ github.event.comment.body }}" == "/deploy-review-app") || \ - "${{ github.event_name }}" == "pull_request" ]]; then - echo "Skipping deployment - not a valid trigger (event: ${{ github.event_name }})" + "${{ github.event_name }}" == "issue_comment" || \ + "${{ github.event_name }}" == "pull_request" || \ + "${{ github.event_name }}" == "push" ]]; then + echo "Error: Unsupported event type ${{ github.event_name }}" exit 1 fi + # Set DO_DEPLOY based on event type and conditions + if [[ "${{ github.event_name }}" == "pull_request" && \ + ("${{ github.event.action }}" == "opened" || \ + "${{ github.event.action }}" == "synchronize" || \ + "${{ github.event.action }}" == "reopened") ]]; then + echo "DO_DEPLOY=true" >> $GITHUB_ENV + elif [[ "${{ github.event_name }}" == "push" ]]; then + echo "DO_DEPLOY=true" >> $GITHUB_ENV + elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "DO_DEPLOY=true" >> $GITHUB_ENV + elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then + if [[ "${{ github.event.issue.pull_request }}" ]]; then + # Trim spaces and check for exact command + COMMENT_BODY=$(echo "${{ github.event.comment.body }}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + if [[ "$COMMENT_BODY" == "/deploy-review-app" ]]; then + echo "DO_DEPLOY=true" >> $GITHUB_ENV + else + echo "DO_DEPLOY=false" >> $GITHUB_ENV + echo "Skipping deployment - comment '$COMMENT_BODY' does not match '/deploy-review-app'" + fi + else + echo "DO_DEPLOY=false" >> $GITHUB_ENV + echo "Skipping deployment for non-PR comment" + fi + fi + + - name: Setup Control Plane App if Not Existing + if: env.DO_DEPLOY == 'true' && env.APP_EXISTS == 'false' + env: + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} + run: | + echo "🔧 Setting up new Control Plane app..." + cpflow setup-app -a ${{ env.APP_NAME }} --org ${{ vars.CPLN_ORG_STAGING }} + - name: Create Initial Comment if: env.DO_DEPLOY != 'false' uses: actions/github-script@v7 @@ -228,7 +286,16 @@ jobs: repo: context.repo.repo, run_id: runId }); - return run.html_url; + + // Get the job ID for this specific job + const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: runId + }); + + const currentJob = jobs.jobs.find(job => job.name === context.job); + return `${run.html_url}/job/${currentJob.id}`; }; const workflowUrl = await getWorkflowUrl(context.runId); @@ -244,7 +311,7 @@ jobs: with: script: | const buildingMessage = [ - '🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + process.env.PR_SHA, + '🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.PR_SHA }}', '', '📝 [View Build Logs](' + process.env.WORKFLOW_URL + ')', '', @@ -262,6 +329,36 @@ jobs: if: env.DO_DEPLOY != 'false' run: git checkout ${{ steps.getRef.outputs.PR_REF }} + - name: Initialize GitHub Deployment + if: env.DO_DEPLOY != 'false' + uses: actions/github-script@v7 + id: init-deployment + with: + script: | + const ref = process.env.PR_SHA; + const environment = process.env.ENVIRONMENT_NAME || 'review-app'; + + const deployment = await github.rest.repos.createDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: ref, + environment: environment, + auto_merge: false, + required_contexts: [], + description: `Deployment for PR #${process.env.PR_NUMBER}` + }); + + // Create initial deployment status + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.data.id, + state: 'in_progress', + description: 'Deployment started' + }); + + return deployment.data.id; + - name: Build Docker Image if: env.DO_DEPLOY != 'false' uses: ./.github/actions/build-docker-image @@ -310,7 +407,7 @@ jobs: with: script: | const prNumber = process.env.PR_NUMBER; - const appUrl = process.env.REVIEW_APP_URL; + const appUrl = process.env.APP_URL; const workflowUrl = process.env.WORKFLOW_URL; const isSuccess = '${{ job.status }}' === 'success'; @@ -320,7 +417,7 @@ jobs: const deploymentStatus = { owner: context.repo.owner, repo: context.repo.repo, - deployment_id: ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }}, + deployment_id: ${{ steps.init-deployment.outputs.result }}, state: isSuccess ? 'success' : 'failure', environment_url: isSuccess ? appUrl : undefined, log_url: workflowUrl, From e113f47ca2852fe507bd2d194c792bdc56d41a30 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 15:43:44 -1000 Subject: [PATCH 3/3] add debugging --- .../delete-control-plane-app/action.yml | 2 +- .../delete-control-plane-app/delete-app.sh | 36 +++++++++++++++++++ .github/workflows/delete-review-app.yml | 4 +++ .github/workflows/help-command.yml | 5 +++ .github/workflows/review-app-help.yml | 5 +++ 5 files changed, 51 insertions(+), 1 deletion(-) create mode 100755 .github/actions/delete-control-plane-app/delete-app.sh diff --git a/.github/actions/delete-control-plane-app/action.yml b/.github/actions/delete-control-plane-app/action.yml index d5d13ef7..9c6993c6 100644 --- a/.github/actions/delete-control-plane-app/action.yml +++ b/.github/actions/delete-control-plane-app/action.yml @@ -14,7 +14,7 @@ runs: steps: - name: Delete Application shell: bash - run: ${{ github.action_path }}/../deploy-to-control-plane/scripts/delete-app.sh + run: ${{ github.action_path }}/scripts/delete-app.sh env: APP_NAME: ${{ inputs.app_name }} CPLN_ORG: ${{ inputs.org }} diff --git a/.github/actions/delete-control-plane-app/delete-app.sh b/.github/actions/delete-control-plane-app/delete-app.sh new file mode 100755 index 00000000..92e8fbc3 --- /dev/null +++ b/.github/actions/delete-control-plane-app/delete-app.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Script to delete a Control Plane application +# Required environment variables: +# - APP_NAME: Name of the application to delete +# - CPLN_ORG: Organization name + +set -e + +# Validate required environment variables +: "${APP_NAME:?APP_NAME environment variable is required}" +: "${CPLN_ORG:?CPLN_ORG environment variable is required}" + +# Safety check: prevent deletion of production or staging apps +if echo "$APP_NAME" | grep -iqE '(production|staging)'; then + echo "❌ ERROR: Cannot delete apps containing 'production' or 'staging' in their name" >&2 + echo "🛑 This is a safety measure to prevent accidental deletion of production or staging environments" >&2 + echo " App name: $APP_NAME" >&2 + exit 1 +fi + +# Check if app exists before attempting to delete +echo "🔍 Checking if application exists: $APP_NAME" +if ! cpflow exists -a "$APP_NAME"; then + echo "⚠️ Application does not exist: $APP_NAME" + exit 0 +fi + +# Delete the application +echo "🗑️ Deleting application: $APP_NAME" +if ! cpflow delete -a "$APP_NAME" --force; then + echo "❌ Failed to delete application: $APP_NAME" >&2 + exit 1 +fi + +echo "✅ Successfully deleted application: $APP_NAME" diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index b45282e8..754b5cd1 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -19,6 +19,10 @@ env: PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: + debug: + uses: ./.github/workflows/debug-workflow.yml + with: + debug_enabled: false # Will still run if vars.DEBUG_WORKFLOW is true Process-Delete-Command: if: | (github.event_name == 'issue_comment' && diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 37330a3e..121d4712 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -18,6 +18,11 @@ permissions: pull-requests: write jobs: + debug: + uses: ./.github/workflows/debug-workflow.yml + with: + debug_enabled: false # Will still run if vars.DEBUG_WORKFLOW is true + show-help: if: | github.event_name == 'workflow_dispatch' || diff --git a/.github/workflows/review-app-help.yml b/.github/workflows/review-app-help.yml index fbe5d198..a54bfdf0 100644 --- a/.github/workflows/review-app-help.yml +++ b/.github/workflows/review-app-help.yml @@ -9,6 +9,11 @@ permissions: pull-requests: write jobs: + debug: + uses: ./.github/workflows/debug-workflow.yml + with: + debug_enabled: false # Will still run if vars.DEBUG_WORKFLOW is true + show-quick-help: if: github.event_name == 'pull_request' runs-on: ubuntu-latest