From 788e600d152cc96a529758d6cbd03d328fbcc4f5 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 16:26:28 -1000 Subject: [PATCH 01/11] separate to two jobs and staging --- .controlplane/controlplane.yml | 2 +- ...=> deploy-to-control-plane-review-app.yml} | 123 ++++++++---------- .../deploy-to-control-plane-staging.yml | 84 ++++++++++-- 3 files changed, 131 insertions(+), 78 deletions(-) rename .github/workflows/{deploy-to-control-plane.yml => deploy-to-control-plane-review-app.yml} (89%) diff --git a/.controlplane/controlplane.yml b/.controlplane/controlplane.yml index f394fe1c..357b54fe 100644 --- a/.controlplane/controlplane.yml +++ b/.controlplane/controlplane.yml @@ -55,7 +55,7 @@ apps: # QA Apps are like Heroku review apps, but the use `prefix` so you can run a commmand like # this to create a QA app for the tutorial app. # `cpflow setup gvc postgres redis rails -a qa-react-webpack-rails-tutorial-pr-1234` - qa-react-webpack-rails-tutorial: + qa-react-webpack-rails-tutorial-pr: <<: *common # Order matters! setup_app_templates: diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane-review-app.yml similarity index 89% rename from .github/workflows/deploy-to-control-plane.yml rename to .github/workflows/deploy-to-control-plane-review-app.yml index d8a9783f..a22433e2 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane-review-app.yml @@ -33,10 +33,10 @@ 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 + debug_enabled: false + + process-deployment: + needs: debug if: | (github.event_name == 'pull_request') || (github.event_name == 'push') || @@ -45,12 +45,13 @@ jobs: github.event.issue.pull_request && contains(github.event.comment.body, '/deploy-review-app')) runs-on: ubuntu-latest - permissions: - contents: read - deployments: write - pull-requests: write - issues: write - + outputs: + pr_number: ${{ env.PR_NUMBER }} + pr_sha: ${{ env.PR_SHA }} + pr_ref: ${{ steps.getRef.outputs.PR_REF }} + do_deploy: ${{ env.DO_DEPLOY }} + comment_id: ${{ steps.create-comment.outputs.comment-id }} + deployment_id: ${{ steps.init-deployment.outputs.result }} steps: # Initial checkout only for pull_request and push events - name: Checkout code @@ -157,13 +158,6 @@ jobs: 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' - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ steps.getRef.outputs.PR_SHA }} - - name: Setup Environment uses: ./.github/actions/setup-environment with: @@ -253,26 +247,6 @@ 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' @@ -305,30 +279,6 @@ jobs: 'https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)' ); - - name: Update Status - 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 ' + '${{ 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: Checkout PR Branch - 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 @@ -359,17 +309,58 @@ jobs: return deployment.data.id; + build: + needs: process-deployment + if: needs.process-deployment.outputs.do_deploy != 'false' + runs-on: ubuntu-latest + outputs: + image_tag: ${{ steps.build.outputs.image_tag }} + comment_id: ${{ needs.process-deployment.outputs.comment_id }} + pr_number: ${{ needs.process-deployment.outputs.pr_number }} + do_deploy: ${{ needs.process-deployment.outputs.do_deploy }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ needs.process-deployment.outputs.pr_ref }} + + - name: Update Status - Building + uses: actions/github-script@v7 + with: + script: | + const buildingMessage = [ + '🏗️ Building Docker image for PR #${{ needs.process-deployment.outputs.pr_number }}, commit ${{ needs.process-deployment.outputs.pr_sha }}', + '', + '📝 [View Build Logs](${{ env.WORKFLOW_URL }})', + '', + process.env.CONSOLE_LINK + ].join('\n'); + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ needs.process-deployment.outputs.comment_id }}, + body: buildingMessage + }); + - name: Build Docker Image - if: env.DO_DEPLOY != 'false' + id: build uses: ./.github/actions/build-docker-image with: app_name: ${{ env.APP_NAME }} org: ${{ vars.CPLN_ORG_STAGING }} - commit: ${{ env.PR_SHA }} - PR_NUMBER: ${{ env.PR_NUMBER }} + commit: ${{ needs.process-deployment.outputs.pr_sha }} + PR_NUMBER: ${{ needs.process-deployment.outputs.pr_number }} + + deploy: + needs: build + if: needs.build.outputs.do_deploy != 'false' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 - name: Update Status - Deploying - if: env.DO_DEPLOY != 'false' uses: actions/github-script@v7 with: script: | @@ -378,7 +369,7 @@ jobs: '', '⏳ Waiting for deployment to be ready...', '', - '📝 [View Deploy Logs](' + process.env.WORKFLOW_URL + ')', + '📝 [View Deploy Logs](${{ env.WORKFLOW_URL }})', '', process.env.CONSOLE_LINK ].join('\n'); diff --git a/.github/workflows/deploy-to-control-plane-staging.yml b/.github/workflows/deploy-to-control-plane-staging.yml index 898c447c..1a49bad8 100644 --- a/.github/workflows/deploy-to-control-plane-staging.yml +++ b/.github/workflows/deploy-to-control-plane-staging.yml @@ -1,32 +1,94 @@ # Control Plane GitHub Action -name: Deploy Main Branch to Control Plane Staging +name: Deploy to Control Plane Staging +run-name: Deploy Control Plane Staging App # Controls when the workflow will run on: - # Uncomment the lines you want actions that will cause the workflow to Triggers the workflow on push or pull request events but only for the main branch push: - branches: [master] - - # Allows you to run this workflow manually from the Actions tab + branches: + - 'main' + - 'master' + - ${{ github.vars.STAGING_APP_BRANCH }} workflow_dispatch: # Convert the GitHub secret variables to environment variables for use by the Control Plane CLI env: - CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }} + APP_NAME: ${{ vars.STAGING_APP_NAME }} CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} + CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }} + STAGING_APP_BRANCH: ${{ vars.STAGING_APP_BRANCH }} + +concurrency: + group: deploy-staging + cancel-in-progress: true jobs: - deploy-to-control-plane-staging: + debug: + uses: ./.github/workflows/debug-workflow.yml + with: + debug_enabled: false + + validate-branch: runs-on: ubuntu-latest + steps: + - name: Check if allowed branch + run: | + if [[ -n "${STAGING_APP_BRANCH}" ]]; then + if [[ "${GITHUB_REF#refs/heads/}" != "${STAGING_APP_BRANCH}" ]]; then + echo "This workflow only runs on configured branch: ${STAGING_APP_BRANCH}" + echo "Current branch: ${GITHUB_REF#refs/heads/}" + exit 1 + fi + elif [[ "${GITHUB_REF}" != "refs/heads/main" && "${GITHUB_REF}" != "refs/heads/master" ]]; then + echo "This workflow only runs on main or master branch (no STAGING_APP_BRANCH configured)" + echo "Current branch: ${GITHUB_REF#refs/heads/}" + exit 1 + fi + build: + needs: validate-branch + runs-on: ubuntu-latest + outputs: + image_tag: ${{ steps.build.outputs.image_tag }} steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 with: - fetch-depth: 0 # Fetch all history for proper SHA handling - ref: master # Explicitly checkout master branch + fetch-depth: 0 + + - name: Setup Environment + uses: ./.github/actions/setup-environment + with: + token: ${{ secrets.CPLN_TOKEN_STAGING }} + org: ${{ vars.CPLN_ORG_STAGING }} + + - name: Build Docker Image + id: build + uses: ./.github/actions/build-docker-image + with: + app_name: ${{ env.APP_NAME }} + org: ${{ vars.CPLN_ORG_STAGING }} + commit: ${{ github.sha }} + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup-environment + with: + token: ${{ secrets.CPLN_TOKEN_STAGING }} + org: ${{ vars.CPLN_ORG_STAGING }} - - uses: ./.github/actions/deploy-to-control-plane + - name: Deploy to Control Plane + uses: ./.github/actions/deploy-to-control-plane with: app_name: ${{ vars.STAGING_APP_NAME }} org: ${{ vars.CPLN_ORG_STAGING }} + github_token: ${{ secrets.GITHUB_TOKEN }} + wait_timeout: ${{ vars.WAIT_TIMEOUT || 900 }} + cpln_token: ${{ secrets.CPLN_TOKEN_STAGING }} From ec8ab3fc105dc71d4e02ca67b8473c381d2d9921 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 17:02:16 -1000 Subject: [PATCH 02/11] fix quick help --- .github/workflows/review-app-help.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/review-app-help.yml b/.github/workflows/review-app-help.yml index a54bfdf0..d5eed23c 100644 --- a/.github/workflows/review-app-help.yml +++ b/.github/workflows/review-app-help.yml @@ -37,9 +37,9 @@ jobs: 'Remove the review app when done', '', '### `/help`', - 'Show detailed instructions, environment setup, and configuration options.' + 'Show detailed instructions, environment setup, and configuration options.', '', - '---', + '---' ].join('\n'); await github.rest.issues.createComment({ From 33ce218f3f3be9ead1be114e32a5ea27d2dfb723 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 17:40:56 -1000 Subject: [PATCH 03/11] Change app name to include -pr-1234 --- .controlplane/controlplane.yml | 2 +- .github/workflows/deploy-to-control-plane-review-app.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.controlplane/controlplane.yml b/.controlplane/controlplane.yml index 357b54fe..f394fe1c 100644 --- a/.controlplane/controlplane.yml +++ b/.controlplane/controlplane.yml @@ -55,7 +55,7 @@ apps: # QA Apps are like Heroku review apps, but the use `prefix` so you can run a commmand like # this to create a QA app for the tutorial app. # `cpflow setup gvc postgres redis rails -a qa-react-webpack-rails-tutorial-pr-1234` - qa-react-webpack-rails-tutorial-pr: + qa-react-webpack-rails-tutorial: <<: *common # Order matters! setup_app_templates: diff --git a/.github/workflows/deploy-to-control-plane-review-app.yml b/.github/workflows/deploy-to-control-plane-review-app.yml index a22433e2..634f56da 100644 --- a/.github/workflows/deploy-to-control-plane-review-app.yml +++ b/.github/workflows/deploy-to-control-plane-review-app.yml @@ -24,7 +24,7 @@ concurrency: cancel-in-progress: true env: - APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }} + APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-pr-${{ 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 }} From 0c5fb5061d1068cfc0475ca829e28f75b0ec6a95 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:00:32 -1000 Subject: [PATCH 04/11] Refactor, inline help-command --- .github/actions/help-command/action.yml | 98 --------------- .github/workflows/help-command.yml | 156 +++++++++++++++++++----- 2 files changed, 127 insertions(+), 127 deletions(-) delete mode 100644 .github/actions/help-command/action.yml diff --git a/.github/actions/help-command/action.yml b/.github/actions/help-command/action.yml deleted file mode 100644 index 9988479c..00000000 --- a/.github/actions/help-command/action.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: 'Show Help Command' -description: 'Displays help information for available commands in PR comments' - -inputs: - github-token: - description: 'GitHub token for posting comments' - required: true - issue-number: - description: 'PR/Issue number to post the comment to (optional, defaults to event context)' - required: false - -runs: - using: "composite" - steps: - - name: Show Available Commands - uses: actions/github-script@v7 - with: - github-token: ${{ inputs.github-token }} - script: | - const helpText = [ - '# Available Commands', - '', - '## `/deploy`', - '**Purpose:** Deploy a review app for your pull request', - '', - '**What it does:**', - '- Creates a new review app in Control Plane', - '- Deploys your changes to the review environment', - '- Provides a unique URL to preview your changes', - '- Shows build and deployment progress in real-time', - '', - '**Optional Configuration:**', - '- `WAIT_TIMEOUT`: Deployment timeout in seconds (default: 900)', - ' - Must be a positive integer', - ' - Example: `/deploy timeout=1800`', - '', - '## `/destroy`', - '**Purpose:** Remove the review app for your pull request', - '', - '**What it does:**', - '- Deletes the review app from Control Plane', - '- Cleans up associated resources', - '- Updates PR with deletion status', - '', - '---', - '## Environment Setup', - '', - '**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: Configure `WAIT_TIMEOUT` in GitHub Actions variables to customize deployment timeout', - '', - '## Control Plane Integration', - '', - '1. Review app naming convention:', - ' ```', - ' ${{ vars.REVIEW_APP_PREFIX }}-', - ' ```', - '2. Console URL: `https://console.cpln.io/console/org/{CPLN_ORG}/gvc/{APP_NAME}/-info`', - '', - '## Automatic Cleanup', - '', - 'Review apps are automatically destroyed when:', - '1. The pull request is closed', - '2. The `/destroy` command is used', - '3. A new deployment is requested (old one is cleaned up first)', - '', - '## Need Help?', - '', - 'For additional assistance:', - '1. Check the [Control Plane documentation](https://docs.controlplane.com/)', - '2. Contact the infrastructure team', - '3. Open an issue in this repository', - ].join('\n'); - - const issueNumber = inputs['issue-number'] || - (context.eventName === 'issue_comment' ? context.payload.issue.number : null); - - if (issueNumber) { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issueNumber, - body: helpText - }); - } else { - console.log(helpText); - } diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 121d4712..df13041b 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -1,42 +1,140 @@ -name: Show Help for Commands +name: Help Command on: - push: - branches: - - "**" # Trigger on all branches, including feature branches issue_comment: types: [created] - workflow_dispatch: - inputs: - issue-number: - description: 'PR/Issue number to post the help comment to' - required: true - type: number permissions: issues: write 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' || - (github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/help') + help: + if: ${{ github.event.issue.pull_request && github.event.comment.body == '/help' }} runs-on: ubuntu-latest - + steps: - - name: Checkout - uses: actions/checkout - - - name: Process Help Command - uses: ./.github/actions/help-command + - name: Show Available Commands + uses: actions/github-script@v7 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ github.event.inputs.issue-number }} \ No newline at end of file + script: | + const sections = { + commands: { + deploy: { + title: '## `/deploy`', + purpose: '**Purpose:** Deploy a review app for your pull request', + details: [ + '**What it does:**', + '- Creates a new review app in Control Plane', + '- Deploys your changes to the review environment', + '- Provides a unique URL to preview your changes', + '- Shows build and deployment progress in real-time', + '', + '**Optional Configuration:**', + '- `WAIT_TIMEOUT`: Deployment timeout in seconds (default: 900)', + ' - Must be a positive integer', + ' - Example: `/deploy timeout=1800`' + ] + }, + destroy: { + title: '## `/destroy`', + purpose: '**Purpose:** Remove the review app for your pull request', + details: [ + '**What it does:**', + '- Deletes the review app from Control Plane', + '- Cleans up associated resources', + '- Updates PR with deletion status' + ] + } + }, + setup: { + title: '## Environment Setup', + sections: [ + { + title: '**Required Environment Secrets:**', + items: [ + '- `CPLN_TOKEN_STAGING`: Control Plane authentication token', + '- `CPLN_TOKEN_PRODUCTION`: Control Plane authentication token' + ] + }, + { + title: '**Required GitHub Actions Variables:**', + items: [ + '- `CPLN_ORG_STAGING`: Control Plane authentication token', + '- `CPLN_ORG_PRODUCTION`: Control Plane authentication token' + ] + }, + { + title: '**Required GitHub Actions Variables (these need to match your control_plane.yml file:**', + items: [ + '- `PRODUCTION_APP_NAME`: Control Plane production app name', + '- `STAGING_APP_NAME`: Control Plane staging app name', + '- `REVIEW_APP_PREFIX`: Control Plane review app prefix' + ] + } + ], + note: 'Optional: Configure `WAIT_TIMEOUT` in GitHub Actions variables to customize deployment timeout' + }, + integration: { + title: '## Control Plane Integration', + details: [ + '1. Review app naming convention:', + ' ```', + ' ${{ vars.REVIEW_APP_PREFIX }}-', + ' ```', + '2. Console URL: `https://console.cpln.io/console/org/{CPLN_ORG}/gvc/{APP_NAME}/-info`' + ] + }, + cleanup: { + title: '## Automatic Cleanup', + details: [ + 'Review apps are automatically destroyed when:', + '1. The pull request is closed', + '2. The `/destroy` command is used', + '3. A new deployment is requested (old one is cleaned up first)' + ] + }, + help: { + title: '## Need Help?', + details: [ + 'For additional assistance:', + '1. Check the [Control Plane documentation](https://docs.controlplane.com/)', + '2. Contact the infrastructure team', + '3. Open an issue in this repository' + ] + } + }; + + const generateHelpText = () => { + const parts = ['# Available Commands', '']; + + // Add commands + Object.values(sections.commands).forEach(cmd => { + parts.push(cmd.title, cmd.purpose, '', ...cmd.details, ''); + }); + + parts.push('---'); + + // Add setup section + parts.push(sections.setup.title, ''); + sections.setup.sections.forEach(section => { + parts.push(section.title, ...section.items, ''); + }); + parts.push(sections.setup.note, ''); + + // Add remaining sections + ['integration', 'cleanup', 'help'].forEach(section => { + parts.push(sections[section].title, '', ...sections[section].details, ''); + }); + + return parts.join('\n'); + }; + + const helpText = generateHelpText(); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: helpText + }); \ No newline at end of file From 742e247029e23cc61de065569f95130238a07e33 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:04:36 -1000 Subject: [PATCH 05/11] fix build/deploy to run setup --- .../workflows/deploy-to-control-plane-review-app.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/deploy-to-control-plane-review-app.yml b/.github/workflows/deploy-to-control-plane-review-app.yml index 634f56da..331d5416 100644 --- a/.github/workflows/deploy-to-control-plane-review-app.yml +++ b/.github/workflows/deploy-to-control-plane-review-app.yml @@ -324,6 +324,12 @@ jobs: with: ref: ${{ needs.process-deployment.outputs.pr_ref }} + - name: Setup Environment + uses: ./.github/actions/setup-environment + with: + token: ${{ secrets.CPLN_TOKEN_STAGING }} + org: ${{ vars.CPLN_ORG_STAGING }} + - name: Update Status - Building uses: actions/github-script@v7 with: @@ -360,6 +366,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Setup Environment + uses: ./.github/actions/setup-environment + with: + token: ${{ secrets.CPLN_TOKEN_STAGING }} + org: ${{ vars.CPLN_ORG_STAGING }} + - name: Update Status - Deploying uses: actions/github-script@v7 with: From 7d2f639bc2e9120a7be9ce1e09765213590811d1 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:14:55 -1000 Subject: [PATCH 06/11] update to allow testing help on branch --- .github/workflows/help-command.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index df13041b..153a2de6 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -3,6 +3,12 @@ name: Help Command on: issue_comment: types: [created] + workflow_dispatch: + inputs: + pr_number: + description: 'Pull Request number to post help comment on' + required: true + type: string permissions: issues: write @@ -10,7 +16,7 @@ permissions: jobs: help: - if: ${{ github.event.issue.pull_request && github.event.comment.body == '/help' }} + if: ${{ (github.event.issue.pull_request && github.event.comment.body == '/help') || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest steps: @@ -132,9 +138,13 @@ jobs: const helpText = generateHelpText(); + const prNumber = context.eventName === 'workflow_dispatch' + ? parseInt(context.payload.inputs.pr_number) + : context.issue.number; + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: context.issue.number, + issue_number: prNumber, body: helpText }); \ No newline at end of file From 8112b7ff6703ca609a825495af1e3edb32f98461 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:33:59 -1000 Subject: [PATCH 07/11] validations --- .../delete-control-plane-app/action.yml | 20 ---------- .../delete-control-plane-app/delete-app.sh | 36 ----------------- .../actions/validate-required-vars/action.yml | 28 +++++++++++++ .github/workflows/delete-review-app.yml | 40 ++++++------------- .../deploy-to-control-plane-review-app.yml | 23 +---------- 5 files changed, 41 insertions(+), 106 deletions(-) delete mode 100644 .github/actions/delete-control-plane-app/action.yml delete mode 100755 .github/actions/delete-control-plane-app/delete-app.sh create mode 100644 .github/actions/validate-required-vars/action.yml diff --git a/.github/actions/delete-control-plane-app/action.yml b/.github/actions/delete-control-plane-app/action.yml deleted file mode 100644 index 9c6993c6..00000000 --- a/.github/actions/delete-control-plane-app/action.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Delete Control Plane App -description: 'Deletes a Control Plane application and all its resources' - -inputs: - app_name: - description: 'Name of the application to delete' - required: true - org: - description: 'Organization name' - required: true - -runs: - using: "composite" - steps: - - name: Delete Application - shell: bash - 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 deleted file mode 100755 index 92e8fbc3..00000000 --- a/.github/actions/delete-control-plane-app/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/validate-required-vars/action.yml b/.github/actions/validate-required-vars/action.yml new file mode 100644 index 00000000..c370039d --- /dev/null +++ b/.github/actions/validate-required-vars/action.yml @@ -0,0 +1,28 @@ +name: 'Validate Required Variables' +description: 'Validates that all required secrets and variables for Control Plane operations' + +runs: + using: 'composite' + steps: + - name: Validate Required Secrets and Variables + shell: bash + run: | + missing=() + + # Check required secrets + if [ -z "$CPLN_TOKEN_STAGING" ]; then + missing+=("Secret: CPLN_TOKEN_STAGING") + fi + + # Check required variables + if [ -z "$CPLN_ORG_STAGING" ]; then + missing+=("Variable: CPLN_ORG_STAGING") + fi + if [ -z "$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 diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index 754b5cd1..a0b3611a 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -5,6 +5,12 @@ on: types: [closed] issue_comment: types: [created] + workflow_dispatch: + inputs: + pr_number: + description: 'PR number to delete review app for' + required: true + type: string permissions: contents: read @@ -15,8 +21,8 @@ permissions: env: 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 }} + APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-pr-${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }} + PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }} jobs: debug: @@ -29,37 +35,15 @@ jobs: github.event.issue.pull_request && github.event.comment.body == '/delete-review-app') || (github.event_name == 'pull_request' && - github.event.action == 'closed') + github.event.action == 'closed') || + github.event_name == 'workflow_dispatch' 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 - 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: Validate Required Secrets and Variables + uses: ./.github/actions/validate-required-vars - name: Setup Environment uses: ./.github/actions/setup-environment diff --git a/.github/workflows/deploy-to-control-plane-review-app.yml b/.github/workflows/deploy-to-control-plane-review-app.yml index 331d5416..ea05f98b 100644 --- a/.github/workflows/deploy-to-control-plane-review-app.yml +++ b/.github/workflows/deploy-to-control-plane-review-app.yml @@ -70,28 +70,7 @@ jobs: 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 + uses: ./.github/actions/validate-required-vars - name: Get PR HEAD Ref id: getRef From c336d221217b8544439d1e65596e44901d37da7b Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:43:59 -1000 Subject: [PATCH 08/11] Fix deploy to staging --- .../deploy-to-control-plane-staging.yml | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-staging.yml b/.github/workflows/deploy-to-control-plane-staging.yml index 1a49bad8..94199ecc 100644 --- a/.github/workflows/deploy-to-control-plane-staging.yml +++ b/.github/workflows/deploy-to-control-plane-staging.yml @@ -7,9 +7,7 @@ run-name: Deploy Control Plane Staging App on: push: branches: - - 'main' - - 'master' - - ${{ github.vars.STAGING_APP_BRANCH }} + - '*' workflow_dispatch: # Convert the GitHub secret variables to environment variables for use by the Control Plane CLI @@ -31,23 +29,29 @@ jobs: validate-branch: runs-on: ubuntu-latest + outputs: + is_deployable: ${{ steps.check_branch.outputs.is_deployable }} steps: - name: Check if allowed branch + id: check_branch run: | if [[ -n "${STAGING_APP_BRANCH}" ]]; then - if [[ "${GITHUB_REF#refs/heads/}" != "${STAGING_APP_BRANCH}" ]]; then - echo "This workflow only runs on configured branch: ${STAGING_APP_BRANCH}" - echo "Current branch: ${GITHUB_REF#refs/heads/}" - exit 1 + if [[ "${GITHUB_REF#refs/heads/}" == "${STAGING_APP_BRANCH}" ]]; then + echo "is_deployable=true" >> $GITHUB_OUTPUT + else + echo "Branch '${GITHUB_REF#refs/heads/}' is not the configured deployment branch '${STAGING_APP_BRANCH}'" + echo "is_deployable=false" >> $GITHUB_OUTPUT fi - elif [[ "${GITHUB_REF}" != "refs/heads/main" && "${GITHUB_REF}" != "refs/heads/master" ]]; then - echo "This workflow only runs on main or master branch (no STAGING_APP_BRANCH configured)" - echo "Current branch: ${GITHUB_REF#refs/heads/}" - exit 1 + elif [[ "${GITHUB_REF}" == "refs/heads/main" || "${GITHUB_REF}" == "refs/heads/master" ]]; then + echo "is_deployable=true" >> $GITHUB_OUTPUT + else + echo "Branch '${GITHUB_REF#refs/heads/}' is not main/master (no STAGING_APP_BRANCH configured)" + echo "is_deployable=false" >> $GITHUB_OUTPUT fi build: needs: validate-branch + if: needs.validate-branch.outputs.is_deployable == 'true' runs-on: ubuntu-latest outputs: image_tag: ${{ steps.build.outputs.image_tag }} From e25c1409a6b36d0a83cb74194e108d02bd23927d Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:50:46 -1000 Subject: [PATCH 09/11] add output --- .github/actions/build-docker-image/action.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml index e1b5df73..f5bc72fb 100644 --- a/.github/actions/build-docker-image/action.yml +++ b/.github/actions/build-docker-image/action.yml @@ -25,8 +25,15 @@ runs: echo "🏗️ Building Docker image for PR #${PR_NUMBER} (commit ${{ inputs.commit }})..." if cpflow build-image -a "${{ inputs.app_name }}" --commit="${{ inputs.commit }}" --org="${{ inputs.org }}"; then + image_tag="${{ inputs.org }}/${{ inputs.app_name }}:${{ inputs.commit }}" + echo "image_tag=${image_tag}" >> $GITHUB_OUTPUT echo "✅ Docker image build successful for PR #${PR_NUMBER} (commit ${{ inputs.commit }})" else echo "❌ Docker image build failed for PR #${PR_NUMBER} (commit ${{ inputs.commit }})" exit 1 fi + +outputs: + image_tag: + description: 'The tag of the built Docker image' + value: ${{ steps.build.outputs.image_tag }} From 91fa0da037979f5b212e66c2d457251ac8bf6e3c Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:57:27 -1000 Subject: [PATCH 10/11] fixes --- .github/actions/build-docker-image/action.yml | 18 +++++++++--------- .../deploy-to-control-plane-staging.yml | 2 -- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml index f5bc72fb..45a12434 100644 --- a/.github/actions/build-docker-image/action.yml +++ b/.github/actions/build-docker-image/action.yml @@ -13,7 +13,7 @@ inputs: required: true PR_NUMBER: description: 'PR number' - required: true + required: false runs: using: "composite" @@ -22,18 +22,18 @@ runs: id: build shell: bash run: | - echo "🏗️ Building Docker image for PR #${PR_NUMBER} (commit ${{ inputs.commit }})..." + PR_INFO="" + if [ -n "${PR_NUMBER}" ]; then + PR_INFO=" for PR #${PR_NUMBER}" + fi + + echo "🏗️ Building Docker image${PR_INFO} (commit ${{ inputs.commit }})..." if cpflow build-image -a "${{ inputs.app_name }}" --commit="${{ inputs.commit }}" --org="${{ inputs.org }}"; then image_tag="${{ inputs.org }}/${{ inputs.app_name }}:${{ inputs.commit }}" echo "image_tag=${image_tag}" >> $GITHUB_OUTPUT - echo "✅ Docker image build successful for PR #${PR_NUMBER} (commit ${{ inputs.commit }})" + echo "✅ Docker image build successful${PR_INFO} (commit ${{ inputs.commit }})" else - echo "❌ Docker image build failed for PR #${PR_NUMBER} (commit ${{ inputs.commit }})" + echo "❌ Docker image build failed${PR_INFO} (commit ${{ inputs.commit }})" exit 1 fi - -outputs: - image_tag: - description: 'The tag of the built Docker image' - value: ${{ steps.build.outputs.image_tag }} diff --git a/.github/workflows/deploy-to-control-plane-staging.yml b/.github/workflows/deploy-to-control-plane-staging.yml index 94199ecc..d789d1ee 100644 --- a/.github/workflows/deploy-to-control-plane-staging.yml +++ b/.github/workflows/deploy-to-control-plane-staging.yml @@ -53,8 +53,6 @@ jobs: needs: validate-branch if: needs.validate-branch.outputs.is_deployable == 'true' runs-on: ubuntu-latest - outputs: - image_tag: ${{ steps.build.outputs.image_tag }} steps: - name: Checkout code uses: actions/checkout@v4 From a21745240afb0051f881281711f27dab44fbab58 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 28 Jan 2025 18:59:28 -1000 Subject: [PATCH 11/11] EOL --- .github/workflows/help-command.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 153a2de6..51ce2566 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -147,4 +147,5 @@ jobs: repo: context.repo.repo, issue_number: prNumber, body: helpText - }); \ No newline at end of file + }); + \ No newline at end of file