From ee08d3a52f7b6faad6fdd723fe3583a24eca9cca Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 15:58:21 -1000 Subject: [PATCH 01/59] Pass correct arg --- .controlplane/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.controlplane/Dockerfile b/.controlplane/Dockerfile index 3ca0447e..8a809700 100644 --- a/.controlplane/Dockerfile +++ b/.controlplane/Dockerfile @@ -2,6 +2,10 @@ ARG RUBY_VERSION=3.3.4 FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base +# Current commit hash environment variable +ARG GIT_COMMIT +ENV GIT_COMMIT_SHA=${GIT_COMMIT} + # Install packages needed to build gems and node modules RUN apt-get update -qq && \ apt-get install --no-install-recommends -y build-essential curl git libpq-dev libvips node-gyp pkg-config python-is-python3 @@ -76,7 +80,3 @@ ENTRYPOINT ["./.controlplane/entrypoint.sh"] # Default args to pass to the entry point that can be overridden # For Kubernetes and ControlPlane, these are the "workload args" CMD ["./bin/rails", "server"] - -# Current commit hash environment variable -ARG GIT_COMMIT_SHA -ENV GIT_COMMIT_SHA=${GIT_COMMIT_SHA} From c7901513f60b4f7015d41b1cf2bb93f49e6eb2ae Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 16:00:06 -1000 Subject: [PATCH 02/59] Set args with = --- .github/actions/deploy-to-control-plane/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 43a9eb97..091d0238 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -47,7 +47,7 @@ runs: cpln image docker-login # Use BUILDKIT_PROGRESS=plain to get more verbose logging of the build # BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}} - cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}} + cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.vars.outputs.sha_short}} --org=${{inputs.org}} # --cache /tmp/.docker-cache - name: Deploy to Control Plane shell: bash From 8355030bc982d69f3ee6756077bb79fe3453a953 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 16:20:52 -1000 Subject: [PATCH 03/59] Address deprecation messages deploy-to-control-plane-review The `set-output` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ deploy-to-control-plane-review Your workflow is using a version of actions/cache that is scheduled for deprecation, actions/cache@v2. Please update your workflow to use either v3 or v4 of actions/cache to avoid interruptions. Learn more: https://github.blog/changelog/2024-12-05-notice-of-upcoming-releases-and-breaking-changes-for-github-actions/#actions-cache-v1-v2-and-actions-toolkit-cache-package-closing-down --- .../actions/deploy-to-control-plane/action.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 091d0238..65b56e04 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -7,11 +7,9 @@ inputs: app_name: description: 'The name of the app to deploy' required: true - default: org: description: 'The org of the app to deploy' required: true - default: runs: using: 'composite' @@ -22,13 +20,14 @@ runs: - name: Set Short SHA id: vars shell: bash - run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + run: | + echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" - # Caching step - - uses: actions/cache@v2 + # Updated caching step to v3 + - uses: actions/cache@v3 with: path: /tmp/.docker-cache - key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }}-${{ github.sha }} + key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }}-${{ github.sha }} restore-keys: | ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }} ${{ runner.os }}-docker- @@ -39,6 +38,7 @@ runs: if ! cpflow exists -a ${{ inputs.app_name }} ; then cpflow setup-app -a ${{ inputs.app_name }} fi + # Provision all infrastructure on Control Plane. # app react-webpack-rails-tutorial will be created per definition in .controlplane/controlplane.yml - name: cpflow build-image @@ -48,9 +48,9 @@ runs: # Use BUILDKIT_PROGRESS=plain to get more verbose logging of the build # BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}} cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.vars.outputs.sha_short}} --org=${{inputs.org}} - # --cache /tmp/.docker-cache + - name: Deploy to Control Plane shell: bash run: | echo "Deploying to Control Plane" - cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose + cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose From f19d79f404cb86d7aa59e7e97d71c25205dce093 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 16:45:52 -1000 Subject: [PATCH 04/59] Updates to deployment --- .github/actions/setup-environment/action.yml | 4 +- .../deploy-to-control-plane-review.yml | 122 ++++++++++-------- 2 files changed, 72 insertions(+), 54 deletions(-) diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml index 96185f7b..ea06f3a9 100644 --- a/.github/actions/setup-environment/action.yml +++ b/.github/actions/setup-environment/action.yml @@ -14,9 +14,9 @@ runs: - name: Install Control Plane CLI and cpflow gem shell: bash run: | - sudo npm install -g @controlplane/cli@3.1.0 + sudo npm install -g @controlplane/cli@3.3.0 cpln --version - gem install cpflow -v 4.0.0 + gem install cpflow -v 4.1.0 cpflow --version - name: cpln profile diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 9d6a6d82..b625add2 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -1,85 +1,103 @@ -# Control Plane GitHub Action - name: Deploy Review App to Control Plane -# Controls when the workflow will run on: - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: - - # Uncomment these lines to trigger the workflow on pull request events - # pull_request: - # branches: - # - master - - # deploy on comment "/deploy-review-app" + pull_request: + types: [opened, synchronize, reopened] + branches: [master] issue_comment: - types: [created, edited] + types: [created] + +concurrency: + group: review-app-${{ github.event.pull_request.number || github.event.issue.number }} + cancel-in-progress: true -# Convert the GitHub secret variables to environment variables for use by the Control Plane CLI env: CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}} CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}} - # Uncomment this line to use the PR number from the pull requests trigger event (that trigger is commented) - # PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} - PR_NUMBER: ${{ github.event.issue.number }} + PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: deploy-to-control-plane-review: - if: ${{ github.event_name != 'issue_comment' || (github.event.comment.body == '/deploy-review-app' && github.event.issue.pull_request) }} + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'pull_request' || + (github.event_name == 'issue_comment' && + github.event.comment.body == '/deploy-review-app' && + github.event.issue.pull_request) runs-on: ubuntu-latest + outputs: + app_url: ${{ steps.deploy.outputs.app_url }} + deployment_id: ${{ steps.create-deployment.outputs.deployment_id }} + steps: + - name: Create GitHub Deployment + id: create-deployment + uses: actions/github-script@v7 + with: + script: | + const deployment = await github.rest.repos.createDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: context.sha, + environment: 'review-app', + auto_merge: false, + required_contexts: [] + }); + return deployment.data.id; + - name: Get PR HEAD Ref if: ${{ github.event_name == 'issue_comment' }} id: getRef - run: echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT + run: | + echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Checkout source code from Github + - name: Checkout source code uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} - - name: Add GitHub Comment - if: ${{ github.event_name == 'issue_comment' }} + - name: Update deployment status (in_progress) uses: actions/github-script@v7 with: script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, + await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, - body: "We started working on your review-app deployment. You can track progress in the `Actions` Tab [here](https://github.com/shakacode/react-webpack-rails-tutorial/actions/workflows/deploy-to-control-plane-review.yml) on Github." - }) + deployment_id: ${{ steps.create-deployment.outputs.deployment_id }}, + state: 'in_progress', + description: 'Deployment is in progress' + }); - - name: Get PR number - if: ${{ github.event_name != 'issue_comment' }} - run: | - echo "GITHUB_REPOSITORY: \"$GITHUB_REPOSITORY\"" - if [ -z "$PR_NUMBER" ]; then - echo "PR_NUMBER is not in the trigger event. Fetching PR number from open PRs." - REF="${{ github.ref }}" - REF=${REF#refs/heads/} # Remove 'refs/heads/' prefix - echo "REF: \"$REF\"" - API_RESPONSE=$(curl --location --request GET "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls?state=open" \ - --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}') - PR_NUMBER=$(echo "$API_RESPONSE" | jq '.[] | select(.head.ref=="'$REF'") | .number') - fi - echo "PR_NUMBER: $PR_NUMBER" - if [ -z "$PR_NUMBER" ]; then - echo "PR_NUMBER is not set. Aborting." - exit 1 - fi - echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV - - name: Get App Name - run: | - echo "PR_NUMBER: ${{ env.PR_NUMBER }}" - echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" >> "$GITHUB_ENV" - echo "App Name: ${{ env.APP_NAME }}" - - uses: ./.github/actions/deploy-to-control-plane + # ... rest of your existing steps ... + + - name: Update deployment status (success) + if: success() + uses: actions/github-script@v7 with: - app_name: ${{ env.APP_NAME }} - org: ${{ env.CPLN_ORG }} + script: | + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: ${{ steps.create-deployment.outputs.deployment_id }}, + state: 'success', + environment_url: '${{ steps.deploy.outputs.app_url }}', + description: 'Deployment successful' + }); + + - name: Update deployment status (failure) + if: failure() + uses: actions/github-script@v7 + with: + script: | + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: ${{ steps.create-deployment.outputs.deployment_id }}, + state: 'failure', + description: 'Deployment failed' + }); From e487791158a2610cec8b63aacbb87e6c79abe43a Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 16:53:54 -1000 Subject: [PATCH 05/59] updates --- .../deploy-to-control-plane-review.yml | 83 +++++++++++++++++-- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index b625add2..a0cfd0ae 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -18,20 +18,56 @@ env: PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: + check-concurrent: + runs-on: ubuntu-latest + outputs: + cancelled: ${{ steps.check.outputs.cancelled }} + steps: + - name: Check for concurrent deployment + id: check + run: | + if [ "${{ github.run_attempt }}" != "1" ]; then + echo "āš ļø Cancelling previous deployment due to new code push..." + echo "cancelled=true" >> $GITHUB_OUTPUT + else + echo "cancelled=false" >> $GITHUB_OUTPUT + fi + deploy-to-control-plane-review: + needs: check-concurrent if: | - github.event_name == 'workflow_dispatch' || - github.event_name == 'pull_request' || - (github.event_name == 'issue_comment' && - github.event.comment.body == '/deploy-review-app' && - github.event.issue.pull_request) + needs.check-concurrent.outputs.cancelled != 'true' && + (github.event_name == 'workflow_dispatch' || + github.event_name == 'pull_request' || + (github.event_name == 'issue_comment' && + github.event.comment.body == '/deploy-review-app' && + github.event.issue.pull_request)) runs-on: ubuntu-latest + permissions: + contents: read + deployments: write + pull-requests: write + outputs: app_url: ${{ steps.deploy.outputs.app_url }} deployment_id: ${{ steps.create-deployment.outputs.deployment_id }} steps: + - name: Notify deployment start + uses: actions/github-script@v7 + with: + script: | + const message = `šŸš€ Starting new deployment for commit: ${context.sha.substring(0, 7)} + ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''}`; + + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); + - name: Create GitHub Deployment id: create-deployment uses: actions/github-script@v7 @@ -73,13 +109,37 @@ jobs: description: 'Deployment is in progress' }); - # ... rest of your existing steps ... + - name: Configure app name + id: app-config + run: | + APP_NAME="qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" + echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV + echo "app_name=$APP_NAME" >> $GITHUB_OUTPUT + + - name: Deploy to Control Plane + id: deploy + uses: ./.github/actions/deploy-to-control-plane + with: + app_name: ${{ env.APP_NAME }} + org: ${{ env.CPLN_ORG }} - name: Update deployment status (success) if: success() uses: actions/github-script@v7 with: script: | + const message = `āœ… Deployment successful! + Environment: review-app + Commit: ${context.sha.substring(0, 7)} + URL: ${{ steps.deploy.outputs.app_url }}`; + + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); + await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, @@ -94,6 +154,17 @@ jobs: uses: actions/github-script@v7 with: script: | + const message = `āŒ Deployment failed + Commit: ${context.sha.substring(0, 7)} + Please check the [workflow logs](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}) for details.`; + + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); + await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, From 25e9502f7515de7bce3f09acf39eda74dbca3c6b Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 16:58:42 -1000 Subject: [PATCH 06/59] Fixed the deployment_id output in the Create GitHub Deployment step --- .github/workflows/deploy-to-control-plane-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index a0cfd0ae..e81a94ad 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -81,7 +81,7 @@ jobs: auto_merge: false, required_contexts: [] }); - return deployment.data.id; + return { deployment_id: deployment.data.id }; - name: Get PR HEAD Ref if: ${{ github.event_name == 'issue_comment' }} From de55983e36dfb285eabc4f4adb7e59100d82f37c Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 17:05:09 -1000 Subject: [PATCH 07/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index e81a94ad..a01b8d3f 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -51,7 +51,7 @@ jobs: outputs: app_url: ${{ steps.deploy.outputs.app_url }} - deployment_id: ${{ steps.create-deployment.outputs.deployment_id }} + deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }} steps: - name: Notify deployment start @@ -104,7 +104,7 @@ jobs: await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.deployment_id }}, + deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }}, state: 'in_progress', description: 'Deployment is in progress' }); @@ -143,7 +143,7 @@ jobs: await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.deployment_id }}, + deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }}, state: 'success', environment_url: '${{ steps.deploy.outputs.app_url }}', description: 'Deployment successful' @@ -168,7 +168,7 @@ jobs: await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.deployment_id }}, + deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }}, state: 'failure', description: 'Deployment failed' }); From 5240c9bbffc7e0cfc42e1baf194208125a4e1b64 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 17:10:44 -1000 Subject: [PATCH 08/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index a01b8d3f..1af79c83 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -51,7 +51,7 @@ jobs: outputs: app_url: ${{ steps.deploy.outputs.app_url }} - deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }} + deployment_id: ${{ steps.create-deployment.outputs.result }} steps: - name: Notify deployment start @@ -81,7 +81,7 @@ jobs: auto_merge: false, required_contexts: [] }); - return { deployment_id: deployment.data.id }; + return deployment.data.id; - name: Get PR HEAD Ref if: ${{ github.event_name == 'issue_comment' }} @@ -104,7 +104,7 @@ jobs: await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }}, + deployment_id: ${{ steps.create-deployment.outputs.result }}, state: 'in_progress', description: 'Deployment is in progress' }); @@ -143,7 +143,7 @@ jobs: await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }}, + deployment_id: ${{ steps.create-deployment.outputs.result }}, state: 'success', environment_url: '${{ steps.deploy.outputs.app_url }}', description: 'Deployment successful' @@ -168,7 +168,7 @@ jobs: await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.result.deployment_id }}, + deployment_id: ${{ steps.create-deployment.outputs.result }}, state: 'failure', description: 'Deployment failed' }); From 2a1b9a3ab96388ebe8e6e20ee17be12fa0fbdecd Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 17:16:23 -1000 Subject: [PATCH 09/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 1af79c83..07ddc857 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -59,7 +59,8 @@ jobs: with: script: | const message = `šŸš€ Starting new deployment for commit: ${context.sha.substring(0, 7)} - ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''}`; + ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''} + Status: ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, @@ -131,7 +132,8 @@ jobs: const message = `āœ… Deployment successful! Environment: review-app Commit: ${context.sha.substring(0, 7)} - URL: ${{ steps.deploy.outputs.app_url }}`; + URL: ${{ steps.deploy.outputs.app_url }} + Status: ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, @@ -156,7 +158,7 @@ jobs: script: | const message = `āŒ Deployment failed Commit: ${context.sha.substring(0, 7)} - Please check the [workflow logs](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}) for details.`; + Status: ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, From 8918cd22c3a24e4a3c29775fe31d9f4e39dd7c6b Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 17:39:34 -1000 Subject: [PATCH 10/59] fixes --- .../deploy-to-control-plane-review.yml | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 07ddc857..53497e06 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -16,6 +16,7 @@ env: CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}} CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} + STATUS_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/jobs/${{ github.job }}?pr=${{ github.event.pull_request.number || github.event.issue.number }} jobs: check-concurrent: @@ -54,20 +55,31 @@ jobs: deployment_id: ${{ steps.create-deployment.outputs.result }} steps: + - name: Create comment + id: create-comment + uses: actions/github-script@v7 + with: + script: | + const createComment = async (message) => { + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); + }; + + core.exportVariable('createComment', createComment); + - name: Notify deployment start uses: actions/github-script@v7 with: script: | const message = `šŸš€ Starting new deployment for commit: ${context.sha.substring(0, 7)} ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''} - Status: ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; + Status: ${{ env.STATUS_URL }}`; - await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: message - }); + await eval(process.env.createComment)(message); - name: Create GitHub Deployment id: create-deployment @@ -133,14 +145,9 @@ jobs: Environment: review-app Commit: ${context.sha.substring(0, 7)} URL: ${{ steps.deploy.outputs.app_url }} - Status: ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; + Status: ${{ env.STATUS_URL }}`; - await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: message - }); + await eval(process.env.createComment)(message); await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, @@ -158,14 +165,9 @@ jobs: script: | const message = `āŒ Deployment failed Commit: ${context.sha.substring(0, 7)} - Status: ${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; + Status: ${{ env.STATUS_URL }}`; - await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: message - }); + await eval(process.env.createComment)(message); await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, From fe262cb6d82ff920249aaebfd86b46f0b944b5e3 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 18:27:09 -1000 Subject: [PATCH 11/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 53497e06..2e013da6 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -60,26 +60,20 @@ jobs: uses: actions/github-script@v7 with: script: | - const createComment = async (message) => { + async function createComment(message) { await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, body: message }); - }; + } - core.exportVariable('createComment', createComment); - - - name: Notify deployment start - uses: actions/github-script@v7 - with: - script: | const message = `šŸš€ Starting new deployment for commit: ${context.sha.substring(0, 7)} ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''} Status: ${{ env.STATUS_URL }}`; - await eval(process.env.createComment)(message); + await createComment(message); - name: Create GitHub Deployment id: create-deployment From 80d841bf4d50a06f7dca0d8616c90276266eac10 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 18:29:46 -1000 Subject: [PATCH 12/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 2e013da6..4cbb467d 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -16,7 +16,7 @@ env: CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}} CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} - STATUS_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/jobs/${{ github.job }}?pr=${{ github.event.pull_request.number || github.event.issue.number }} + STATUS_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ github.job_id }}?pr=${{ github.event.pull_request.number || github.event.issue.number }} jobs: check-concurrent: From 084f0d05b923c5649a93988fb20cf93250e03801 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 18:32:58 -1000 Subject: [PATCH 13/59] fixes --- .../deploy-to-control-plane-review.yml | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 4cbb467d..39ab645c 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -16,7 +16,7 @@ env: CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}} CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} - STATUS_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ github.job_id }}?pr=${{ github.event.pull_request.number || github.event.issue.number }} + STATUS_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ steps.get_job_id.outputs.job_id }}?pr=${{ github.event.pull_request.number || github.event.issue.number }} jobs: check-concurrent: @@ -55,9 +55,27 @@ jobs: deployment_id: ${{ steps.create-deployment.outputs.result }} steps: + - name: Get job ID + id: get_job_id + uses: actions/github-script@v7 + with: + script: | + const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.runId, + }); + + const currentJob = jobs.jobs.find(job => job.name === context.job); + const jobId = currentJob.id; + + return jobId; + - name: Create comment id: create-comment uses: actions/github-script@v7 + env: + JOB_ID: ${{ steps.get_job_id.outputs.result }} with: script: | async function createComment(message) { @@ -71,7 +89,7 @@ jobs: const message = `šŸš€ Starting new deployment for commit: ${context.sha.substring(0, 7)} ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''} - Status: ${{ env.STATUS_URL }}`; + Status: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${JOB_ID}?pr=${context.issue.number || context.payload.pull_request.number}`; await createComment(message); From cac41c4f7f26725110a54bafac94600062e81f8a Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 18:38:31 -1000 Subject: [PATCH 14/59] Fixed failure to deploy to review app Invalid workflow file: .github/workflows/deploy-to-control-plane-review.yml#L19 The workflow is not valid. .github/workflows/deploy-to-control-plane-review.yml (Line: 19, Col: 15): Unrecognized named-value: 'steps'. Located at position 1 within expression: steps.get_job_id.outputs.job_id --- .../deploy-to-control-plane-review.yml | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 39ab645c..d8f0cd57 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -16,7 +16,6 @@ env: CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}} CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} - STATUS_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ steps.get_job_id.outputs.job_id }}?pr=${{ github.event.pull_request.number || github.event.issue.number }} jobs: check-concurrent: @@ -55,11 +54,12 @@ jobs: deployment_id: ${{ steps.create-deployment.outputs.result }} steps: - - name: Get job ID - id: get_job_id + - name: Create initial comment and get job URL + id: init uses: actions/github-script@v7 with: script: | + // Get the job ID from the Actions API const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, @@ -67,31 +67,23 @@ jobs: }); const currentJob = jobs.jobs.find(job => job.name === context.job); - const jobId = currentJob.id; - - return jobId; - - - name: Create comment - id: create-comment - uses: actions/github-script@v7 - env: - JOB_ID: ${{ steps.get_job_id.outputs.result }} - with: - script: | - async function createComment(message) { - await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: message - }); + if (!currentJob) { + throw new Error('Could not find current job in the workflow run'); } + const statusUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${currentJob.id}?pr=${context.issue.number || context.payload.pull_request.number}`; + core.exportVariable('statusUrl', statusUrl); + const message = `šŸš€ Starting new deployment for commit: ${context.sha.substring(0, 7)} ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''} - Status: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${JOB_ID}?pr=${context.issue.number || context.payload.pull_request.number}`; + Status: ${statusUrl}`; - await createComment(message); + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); - name: Create GitHub Deployment id: create-deployment @@ -148,7 +140,7 @@ jobs: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} - - name: Update deployment status (success) + - name: Update deployment status success if: success() uses: actions/github-script@v7 with: @@ -157,9 +149,14 @@ jobs: Environment: review-app Commit: ${context.sha.substring(0, 7)} URL: ${{ steps.deploy.outputs.app_url }} - Status: ${{ env.STATUS_URL }}`; + Status: ${process.env.statusUrl}`; - await eval(process.env.createComment)(message); + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, @@ -170,16 +167,21 @@ jobs: description: 'Deployment successful' }); - - name: Update deployment status (failure) + - name: Update deployment status failure if: failure() uses: actions/github-script@v7 with: script: | const message = `āŒ Deployment failed Commit: ${context.sha.substring(0, 7)} - Status: ${{ env.STATUS_URL }}`; + Status: ${process.env.statusUrl}`; - await eval(process.env.createComment)(message); + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, From 745ca0ea8da747797cc613ad560fd197070fa849 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 19:14:53 -1000 Subject: [PATCH 15/59] fixes --- .../deploy-to-control-plane-review.yml | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index d8f0cd57..90f7ae1e 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -140,6 +140,25 @@ jobs: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} + - name: Extract deployment URL + id: extract-url + run: | + RAILS_URL=$(echo "${{ steps.deploy.outputs.deployment_output }}" | grep -o 'https://rails-[^[:space:]]*\.cpln\.app') + echo "RAILS_URL=$RAILS_URL" >> $GITHUB_ENV + echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT + + - name: Update PR commit message + if: success() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_SHA=$(gh pr view ${{ env.PR_NUMBER }} --json commits --jq '.commits[-1].oid') + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git pull --rebase + git commit --amend -m "Rails review app deployed to ${{ env.RAILS_URL }}" + git push --force-with-lease origin HEAD + - name: Update deployment status success if: success() uses: actions/github-script@v7 @@ -148,7 +167,7 @@ jobs: const message = `āœ… Deployment successful! Environment: review-app Commit: ${context.sha.substring(0, 7)} - URL: ${{ steps.deploy.outputs.app_url }} + URL: ${{ env.RAILS_URL }} Status: ${process.env.statusUrl}`; await github.rest.issues.createComment({ @@ -163,7 +182,7 @@ jobs: repo: context.repo.repo, deployment_id: ${{ steps.create-deployment.outputs.result }}, state: 'success', - environment_url: '${{ steps.deploy.outputs.app_url }}', + environment_url: '${{ env.RAILS_URL }}', description: 'Deployment successful' }); From f77a610c1cdcdf2443e735315beef2def7ab26db Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 22 Jan 2025 19:17:22 -1000 Subject: [PATCH 16/59] fixes --- .../deploy-to-control-plane/action.yml | 25 ++++++++++++++----- .../deploy-to-control-plane-review.yml | 1 + 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 65b56e04..24087afc 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -10,6 +10,9 @@ inputs: org: description: 'The org of the app to deploy' required: true + github_token: + description: 'The GitHub token for authentication' + required: true runs: using: 'composite' @@ -17,11 +20,21 @@ runs: - name: Setup Environment uses: ./.github/actions/setup-environment - - name: Set Short SHA - id: vars + - name: Get correct commit SHA + id: get_sha shell: bash run: | - echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + if [[ "$GITHUB_EVENT_NAME" == "issue_comment" ]]; then + PR_SHA=$(gh pr view ${{ env.PR_NUMBER }} --json headRefOid --jq '.headRefOid') + echo "sha=$PR_SHA" >> $GITHUB_OUTPUT + echo "sha_short=${PR_SHA:0:7}" >> $GITHUB_OUTPUT + else + echo "sha=$GITHUB_SHA" >> $GITHUB_OUTPUT + echo "sha_short=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT + fi + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + PR_NUMBER: ${{ env.PR_NUMBER }} # Updated caching step to v3 - uses: actions/cache@v3 @@ -41,13 +54,13 @@ runs: # Provision all infrastructure on Control Plane. # app react-webpack-rails-tutorial will be created per definition in .controlplane/controlplane.yml - - name: cpflow build-image + - name: Build and deploy shell: bash run: | cpln image docker-login # Use BUILDKIT_PROGRESS=plain to get more verbose logging of the build - # BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}} - cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.vars.outputs.sha_short}} --org=${{inputs.org}} + # BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.get_sha.outputs.sha_short}} --org ${{inputs.org}} + cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} - name: Deploy to Control Plane shell: bash diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 90f7ae1e..2a572487 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -139,6 +139,7 @@ jobs: with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} + github_token: ${{ secrets.GITHUB_TOKEN }} - name: Extract deployment URL id: extract-url From 87662fa2cdf1056b254d5b57a3c62b6256daf683 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 16:17:15 -1000 Subject: [PATCH 17/59] Updates, fix crash --- .../deploy-to-control-plane/action.yml | 44 ++++++++++++++- .../deploy-to-control-plane-review.yml | 54 ++++++++++++------- 2 files changed, 77 insertions(+), 21 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 24087afc..d6c43773 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -14,6 +14,11 @@ inputs: description: 'The GitHub token for authentication' required: true +outputs: + rails_url: + description: 'The URL of the deployed Rails application' + value: ${{ steps.deploy.outputs.rails_url }} + runs: using: 'composite' steps: @@ -63,7 +68,42 @@ runs: cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} - name: Deploy to Control Plane + id: deploy shell: bash run: | - echo "Deploying to Control Plane" - cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose + # Deploy rails workload + echo "šŸš€ Starting deployment process..." + echo "šŸ“¦ Building image with commit SHA: ${{steps.get_sha.outputs.sha_short}}" + + # Create a temporary file for the output + TEMP_OUTPUT=$(mktemp) + + # Run the command and tee output to both stdout and temp file + set -o pipefail # Make sure we get the correct exit code from the cpln command + + echo "šŸ”„ Updating Rails workload..." + if cpln workload update rails --gvc ${{ inputs.app_name }} --org ${{ inputs.org }} --set spec.containers.rails.image=/org/${{ inputs.org }}/image/${{ inputs.app_name }}:${{steps.get_sha.outputs.sha_short}} | tee "$TEMP_OUTPUT"; then + # Extract the URL from the deployment output + RAILS_URL=$(grep -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT" || true) + if [ -n "$RAILS_URL" ]; then + echo "🌐 Found Rails deployment URL: $RAILS_URL" + echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT + + echo "šŸ”„ Updating daily-task workload..." + if cpln workload update daily-task --gvc ${{ inputs.app_name }} --org ${{ inputs.org }} --set spec.containers.daily-task.image=/org/${{ inputs.org }}/image/${{ inputs.app_name }}:${{steps.get_sha.outputs.sha_short}} | tee "$TEMP_OUTPUT"; then + echo "āœ… Both workloads updated successfully!" + else + echo "āš ļø Daily-task update failed, but Rails deployment was successful" + fi + + rm "$TEMP_OUTPUT" + else + rm "$TEMP_OUTPUT" + echo "āŒ Failed to extract Rails URL from deployment output" + exit 1 + fi + else + rm "$TEMP_OUTPUT" + echo "āŒ Rails deployment failed" + exit 1 + fi diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 2a572487..8f3f30c5 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -141,35 +141,48 @@ jobs: org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} - - name: Extract deployment URL - id: extract-url - run: | - RAILS_URL=$(echo "${{ steps.deploy.outputs.deployment_output }}" | grep -o 'https://rails-[^[:space:]]*\.cpln\.app') - echo "RAILS_URL=$RAILS_URL" >> $GITHUB_ENV - echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT - - name: Update PR commit message if: success() env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RAILS_URL: ${{ steps.deploy.outputs.rails_url }} run: | - PR_SHA=$(gh pr view ${{ env.PR_NUMBER }} --json commits --jq '.commits[-1].oid') - git config user.name "GitHub Actions" - git config user.email "actions@github.com" - git pull --rebase - git commit --amend -m "Rails review app deployed to ${{ env.RAILS_URL }}" - git push --force-with-lease origin HEAD + if [ -n "$RAILS_URL" ]; then + echo "šŸ”„ Updating PR commit message with deployment URL..." + PR_SHA=$(gh pr view ${{ env.PR_NUMBER }} --json commits --jq '.commits[-1].oid') + if [ -n "$PR_SHA" ]; then + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git pull --rebase + git commit --amend -m "Rails review app deployed to $RAILS_URL" + if git push --force-with-lease origin HEAD; then + echo "āœ… Successfully updated commit message" + else + echo "āŒ Failed to push updated commit message" + exit 1 + fi + else + echo "āŒ Failed to get PR SHA" + exit 1 + fi + else + echo "āŒ No Rails URL found in deployment output" + exit 1 + fi - name: Update deployment status success if: success() uses: actions/github-script@v7 + env: + RAILS_URL: ${{ steps.deploy.outputs.rails_url }} with: script: | const message = `āœ… Deployment successful! + Environment: review-app Commit: ${context.sha.substring(0, 7)} - URL: ${{ env.RAILS_URL }} - Status: ${process.env.statusUrl}`; + Rails URL: ${process.env.RAILS_URL} + Workflow Status: ${process.env.statusUrl}`; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, @@ -183,18 +196,21 @@ jobs: repo: context.repo.repo, deployment_id: ${{ steps.create-deployment.outputs.result }}, state: 'success', - environment_url: '${{ env.RAILS_URL }}', - description: 'Deployment successful' + environment_url: process.env.RAILS_URL, + description: 'āœ… Deployment successful' }); - name: Update deployment status failure if: failure() uses: actions/github-script@v7 + env: + RAILS_URL: ${{ steps.deploy.outputs.rails_url }} with: script: | const message = `āŒ Deployment failed + Commit: ${context.sha.substring(0, 7)} - Status: ${process.env.statusUrl}`; + Workflow Status: ${process.env.statusUrl}`; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, @@ -208,5 +224,5 @@ jobs: repo: context.repo.repo, deployment_id: ${{ steps.create-deployment.outputs.result }}, state: 'failure', - description: 'Deployment failed' + description: 'āŒ Deployment failed' }); From 4970fbeac1c531847c9ab519ee924e968d4da89f Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 16:59:57 -1000 Subject: [PATCH 18/59] fixes --- .../deploy-to-control-plane-review.yml | 49 +++---------------- 1 file changed, 8 insertions(+), 41 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 8f3f30c5..6fe63212 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -141,36 +141,7 @@ jobs: org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} - - name: Update PR commit message - if: success() - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RAILS_URL: ${{ steps.deploy.outputs.rails_url }} - run: | - if [ -n "$RAILS_URL" ]; then - echo "šŸ”„ Updating PR commit message with deployment URL..." - PR_SHA=$(gh pr view ${{ env.PR_NUMBER }} --json commits --jq '.commits[-1].oid') - if [ -n "$PR_SHA" ]; then - git config user.name "GitHub Actions" - git config user.email "actions@github.com" - git pull --rebase - git commit --amend -m "Rails review app deployed to $RAILS_URL" - if git push --force-with-lease origin HEAD; then - echo "āœ… Successfully updated commit message" - else - echo "āŒ Failed to push updated commit message" - exit 1 - fi - else - echo "āŒ Failed to get PR SHA" - exit 1 - fi - else - echo "āŒ No Rails URL found in deployment output" - exit 1 - fi - - - name: Update deployment status success + - name: Post deployment status if: success() uses: actions/github-script@v7 env: @@ -178,11 +149,9 @@ jobs: with: script: | const message = `āœ… Deployment successful! - - Environment: review-app - Commit: ${context.sha.substring(0, 7)} - Rails URL: ${process.env.RAILS_URL} - Workflow Status: ${process.env.statusUrl}`; + + šŸš€ Rails app: ${process.env.RAILS_URL} + šŸ“Š Status: ${process.env.statusUrl}`; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, @@ -200,17 +169,15 @@ jobs: description: 'āœ… Deployment successful' }); - - name: Update deployment status failure + - name: Post deployment failure if: failure() uses: actions/github-script@v7 - env: - RAILS_URL: ${{ steps.deploy.outputs.rails_url }} with: script: | const message = `āŒ Deployment failed - - Commit: ${context.sha.substring(0, 7)} - Workflow Status: ${process.env.statusUrl}`; + +Commit: ${context.sha.substring(0, 7)} +Workflow Status: ${process.env.statusUrl}`; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, From e26cc7214c3bdad0eab504da2de918d92de78c57 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 17:05:17 -1000 Subject: [PATCH 19/59] fixes --- .../workflows/deploy-to-control-plane-review.yml | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 6fe63212..df29ea75 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -74,9 +74,9 @@ jobs: const statusUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${currentJob.id}?pr=${context.issue.number || context.payload.pull_request.number}`; core.exportVariable('statusUrl', statusUrl); - const message = `šŸš€ Starting new deployment for commit: ${context.sha.substring(0, 7)} - ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''} - Status: ${statusUrl}`; + const message = "šŸš€ Starting new deployment for commit: " + context.sha.substring(0, 7) + + "\nChanges: " + (context.payload.commits ? context.payload.commits[0].message : '') + + "\nStatus: " + statusUrl; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, @@ -148,10 +148,7 @@ jobs: RAILS_URL: ${{ steps.deploy.outputs.rails_url }} with: script: | - const message = `āœ… Deployment successful! - - šŸš€ Rails app: ${process.env.RAILS_URL} - šŸ“Š Status: ${process.env.statusUrl}`; + const message = "āœ… Deployment successful!\n\nšŸš€ Rails app: " + process.env.RAILS_URL + "\nšŸ“Š Status: " + process.env.statusUrl; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, @@ -174,10 +171,7 @@ jobs: uses: actions/github-script@v7 with: script: | - const message = `āŒ Deployment failed - -Commit: ${context.sha.substring(0, 7)} -Workflow Status: ${process.env.statusUrl}`; + const message = "āŒ Deployment failed\n\nCommit: " + context.sha.substring(0, 7) + "\nWorkflow Status: " + process.env.statusUrl; await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, From 29ade6f73e8cb0ddc9f8871aec4833e7bcd70334 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 17:26:23 -1000 Subject: [PATCH 20/59] Fixes --- .../deploy-to-control-plane/action.yml | 27 +++++++----- .../deploy-to-control-plane-review.yml | 41 +++++++++++-------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index d6c43773..b3c8fa88 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -71,6 +71,17 @@ runs: id: deploy shell: bash run: | + # Debug git commit information + echo "šŸ” Debugging git commit information:" + echo "Current directory: $(pwd)" + echo "Git status:" + git status + echo "Git log (last 5 commits):" + git log -n 5 --oneline + echo "steps.get_sha.outputs.sha_short: ${{steps.get_sha.outputs.sha_short}}" + echo "Full SHA from git rev-parse HEAD: $(git rev-parse HEAD)" + echo "Short SHA from git rev-parse --short HEAD: $(git rev-parse --short HEAD)" + # Deploy rails workload echo "šŸš€ Starting deployment process..." echo "šŸ“¦ Building image with commit SHA: ${{steps.get_sha.outputs.sha_short}}" @@ -81,21 +92,15 @@ runs: # Run the command and tee output to both stdout and temp file set -o pipefail # Make sure we get the correct exit code from the cpln command - echo "šŸ”„ Updating Rails workload..." - if cpln workload update rails --gvc ${{ inputs.app_name }} --org ${{ inputs.org }} --set spec.containers.rails.image=/org/${{ inputs.org }}/image/${{ inputs.app_name }}:${{steps.get_sha.outputs.sha_short}} | tee "$TEMP_OUTPUT"; then + echo "šŸ”„ Building and deploying with cpflow..." + if cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} | tee "$TEMP_OUTPUT" && \ + cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose | tee -a "$TEMP_OUTPUT"; then + # Extract the URL from the deployment output RAILS_URL=$(grep -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT" || true) if [ -n "$RAILS_URL" ]; then echo "🌐 Found Rails deployment URL: $RAILS_URL" echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT - - echo "šŸ”„ Updating daily-task workload..." - if cpln workload update daily-task --gvc ${{ inputs.app_name }} --org ${{ inputs.org }} --set spec.containers.daily-task.image=/org/${{ inputs.org }}/image/${{ inputs.app_name }}:${{steps.get_sha.outputs.sha_short}} | tee "$TEMP_OUTPUT"; then - echo "āœ… Both workloads updated successfully!" - else - echo "āš ļø Daily-task update failed, but Rails deployment was successful" - fi - rm "$TEMP_OUTPUT" else rm "$TEMP_OUTPUT" @@ -104,6 +109,6 @@ runs: fi else rm "$TEMP_OUTPUT" - echo "āŒ Rails deployment failed" + echo "āŒ Deployment command failed" exit 1 fi diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index df29ea75..a9576768 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -19,6 +19,7 @@ env: jobs: check-concurrent: + name: Deploy Review App to Control Plane / check-concurrent runs-on: ubuntu-latest outputs: cancelled: ${{ steps.check.outputs.cancelled }} @@ -55,35 +56,34 @@ jobs: steps: - name: Create initial comment and get job URL - id: init + id: create-comment uses: actions/github-script@v7 with: script: | - // Get the job ID from the Actions API - const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ + const currentJob = await github.rest.actions.getJobForWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, - run_id: context.runId, - }); - - const currentJob = jobs.jobs.find(job => job.name === context.job); - if (!currentJob) { - throw new Error('Could not find current job in the workflow run'); - } + job_id: context.runId + }).then(response => response.data); const statusUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${currentJob.id}?pr=${context.issue.number || context.payload.pull_request.number}`; core.exportVariable('statusUrl', statusUrl); - const message = "šŸš€ Starting new deployment for commit: " + context.sha.substring(0, 7) + + const deploymentId = Date.now().toString(); + core.exportVariable('deploymentId', deploymentId); + + const message = "šŸš€ Starting new deployment [" + deploymentId + "] for commit: " + context.sha.substring(0, 7) + "\nChanges: " + (context.payload.commits ? context.payload.commits[0].message : '') + "\nStatus: " + statusUrl; - await github.rest.issues.createComment({ + const comment = await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, body: message }); + + core.setOutput('comment-id', comment.data.id); - name: Create GitHub Deployment id: create-deployment @@ -146,14 +146,16 @@ jobs: uses: actions/github-script@v7 env: RAILS_URL: ${{ steps.deploy.outputs.rails_url }} + COMMENT_ID: ${{ steps.create-comment.outputs.comment-id }} + DEPLOYMENT_ID: ${{ env.deploymentId }} with: script: | - const message = "āœ… Deployment successful!\n\nšŸš€ Rails app: " + process.env.RAILS_URL + "\nšŸ“Š Status: " + process.env.statusUrl; + const message = "āœ… Deployment [" + process.env.DEPLOYMENT_ID + "] successful!\n\nšŸš€ Rails app: " + process.env.RAILS_URL + "\nšŸ“Š Status: " + process.env.statusUrl; - await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, + await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, + comment_id: process.env.COMMENT_ID, body: message }); @@ -169,14 +171,17 @@ jobs: - name: Post deployment failure if: failure() uses: actions/github-script@v7 + env: + COMMENT_ID: ${{ steps.create-comment.outputs.comment-id }} + DEPLOYMENT_ID: ${{ env.deploymentId }} with: script: | - const message = "āŒ Deployment failed\n\nCommit: " + context.sha.substring(0, 7) + "\nWorkflow Status: " + process.env.statusUrl; + const message = "āŒ Deployment [" + process.env.DEPLOYMENT_ID + "] failed\n\nCommit: " + context.sha.substring(0, 7) + "\nWorkflow Status: " + process.env.statusUrl; - await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, + await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, + comment_id: process.env.COMMENT_ID, body: message }); From 8db05114bda58671ea78ec3924d73b67da04bcd6 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 17:32:48 -1000 Subject: [PATCH 21/59] fixes --- .../deploy-to-control-plane-review.yml | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index a9576768..bc814e9f 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -176,19 +176,38 @@ jobs: DEPLOYMENT_ID: ${{ env.deploymentId }} with: script: | - const message = "āŒ Deployment [" + process.env.DEPLOYMENT_ID + "] failed\n\nCommit: " + context.sha.substring(0, 7) + "\nWorkflow Status: " + process.env.statusUrl; + console.log('Debug info:'); + console.log('COMMENT_ID:', process.env.COMMENT_ID); + console.log('DEPLOYMENT_ID:', process.env.DEPLOYMENT_ID); + console.log('create-deployment result:', ${{ steps.create-deployment.outputs.result }}); - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: message - }); + const message = "āŒ Deployment [" + (process.env.DEPLOYMENT_ID || 'unknown') + "] failed\n\nCommit: " + context.sha.substring(0, 7) + "\nWorkflow Status: " + process.env.statusUrl; - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.result }}, - state: 'failure', - description: 'āŒ Deployment failed' - }); + // Only try to update comment if we have a comment ID + if (process.env.COMMENT_ID) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: process.env.COMMENT_ID, + body: message + }); + } else { + // Fall back to creating a new comment + await github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); + } + + // Only create deployment status if we have a deployment ID + if (${{ steps.create-deployment.outputs.result }}) { + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: ${{ steps.create-deployment.outputs.result }}, + state: 'failure', + description: 'āŒ Deployment failed' + }); + } From b7a7229886aa362723e78b069faacfddd37e9bcb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 17:39:14 -1000 Subject: [PATCH 22/59] fixes --- .../deploy-to-control-plane/action.yml | 94 ++------- .../actions/post-deployment-status/action.yml | 70 +++++++ .../deploy-to-control-plane-review.yml | 195 +++--------------- 3 files changed, 121 insertions(+), 238 deletions(-) create mode 100644 .github/actions/post-deployment-status/action.yml diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index b3c8fa88..6ff04e76 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -1,114 +1,58 @@ # Control Plane GitHub Action -name: Deploy-To-Control-Plane -description: 'Deploys both to staging and to review apps' +name: Deploy to Control Plane +description: 'Deploys the application to Control Plane' inputs: app_name: - description: 'The name of the app to deploy' + description: 'Name of the application' required: true org: - description: 'The org of the app to deploy' + description: 'Organization name' required: true github_token: - description: 'The GitHub token for authentication' + description: 'GitHub token' required: true outputs: rails_url: - description: 'The URL of the deployed Rails application' + description: 'URL of the deployed Rails application' value: ${{ steps.deploy.outputs.rails_url }} runs: - using: 'composite' + using: "composite" steps: - - name: Setup Environment - uses: ./.github/actions/setup-environment - - - name: Get correct commit SHA + - name: Get commit SHA id: get_sha shell: bash run: | - if [[ "$GITHUB_EVENT_NAME" == "issue_comment" ]]; then - PR_SHA=$(gh pr view ${{ env.PR_NUMBER }} --json headRefOid --jq '.headRefOid') - echo "sha=$PR_SHA" >> $GITHUB_OUTPUT - echo "sha_short=${PR_SHA:0:7}" >> $GITHUB_OUTPUT - else - echo "sha=$GITHUB_SHA" >> $GITHUB_OUTPUT - echo "sha_short=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT - fi - env: - GITHUB_TOKEN: ${{ inputs.github_token }} - PR_NUMBER: ${{ env.PR_NUMBER }} - - # Updated caching step to v3 - - uses: actions/cache@v3 - with: - path: /tmp/.docker-cache - key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }} - ${{ runner.os }}-docker- - - - name: cpflow setup-app - shell: bash - run: | - if ! cpflow exists -a ${{ inputs.app_name }} ; then - cpflow setup-app -a ${{ inputs.app_name }} - fi - - # Provision all infrastructure on Control Plane. - # app react-webpack-rails-tutorial will be created per definition in .controlplane/controlplane.yml - - name: Build and deploy - shell: bash - run: | - cpln image docker-login - # Use BUILDKIT_PROGRESS=plain to get more verbose logging of the build - # BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.get_sha.outputs.sha_short}} --org ${{inputs.org}} - cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} + echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "Using commit SHA: $(git rev-parse --short HEAD)" - name: Deploy to Control Plane id: deploy shell: bash run: | - # Debug git commit information - echo "šŸ” Debugging git commit information:" - echo "Current directory: $(pwd)" - echo "Git status:" - git status - echo "Git log (last 5 commits):" - git log -n 5 --oneline - echo "steps.get_sha.outputs.sha_short: ${{steps.get_sha.outputs.sha_short}}" - echo "Full SHA from git rev-parse HEAD: $(git rev-parse HEAD)" - echo "Short SHA from git rev-parse --short HEAD: $(git rev-parse --short HEAD)" - - # Deploy rails workload - echo "šŸš€ Starting deployment process..." - echo "šŸ“¦ Building image with commit SHA: ${{steps.get_sha.outputs.sha_short}}" - - # Create a temporary file for the output + # Create temp file for output TEMP_OUTPUT=$(mktemp) - # Run the command and tee output to both stdout and temp file - set -o pipefail # Make sure we get the correct exit code from the cpln command + echo "šŸš€ Deploying with commit: ${{steps.get_sha.outputs.sha_short}}" - echo "šŸ”„ Building and deploying with cpflow..." + # Build and deploy if cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} | tee "$TEMP_OUTPUT" && \ cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose | tee -a "$TEMP_OUTPUT"; then - # Extract the URL from the deployment output - RAILS_URL=$(grep -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT" || true) + # Extract Rails URL + RAILS_URL=$(grep -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT") if [ -n "$RAILS_URL" ]; then - echo "🌐 Found Rails deployment URL: $RAILS_URL" echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT - rm "$TEMP_OUTPUT" + echo "āœ… Deployment successful: $RAILS_URL" else - rm "$TEMP_OUTPUT" - echo "āŒ Failed to extract Rails URL from deployment output" + echo "āŒ Failed to extract Rails URL" exit 1 fi else - rm "$TEMP_OUTPUT" - echo "āŒ Deployment command failed" + echo "āŒ Deployment failed" exit 1 fi + rm -f "$TEMP_OUTPUT" diff --git a/.github/actions/post-deployment-status/action.yml b/.github/actions/post-deployment-status/action.yml new file mode 100644 index 00000000..4701502b --- /dev/null +++ b/.github/actions/post-deployment-status/action.yml @@ -0,0 +1,70 @@ +name: 'Post Deployment Status' +description: 'Posts deployment status updates to PR comments' +inputs: + status: + description: 'Status of deployment (success/failure)' + required: true + rails-url: + description: 'URL of the Rails app' + required: false + github-token: + description: 'GitHub token' + required: true + deployment-id: + description: 'Deployment ID' + required: false + default: 'unknown' + comment-id: + description: 'Comment ID to update' + required: false + workflow-url: + description: 'Workflow URL' + required: true + +runs: + using: "composite" + steps: + - name: Post status + uses: actions/github-script@v7 + env: + RAILS_URL: ${{ inputs.rails-url }} + COMMENT_ID: ${{ inputs.comment-id }} + DEPLOYMENT_ID: ${{ inputs.deployment-id }} + STATUS_URL: ${{ inputs.workflow-url }} + with: + github-token: ${{ inputs.github-token }} + script: | + const isSuccess = '${{ inputs.status }}' === 'success'; + + // Create appropriate message based on status + const message = isSuccess + ? `āœ… Deployment [${process.env.DEPLOYMENT_ID}] successful!\n\nšŸš€ Rails app: ${process.env.RAILS_URL}\nšŸ“Š Status: ${process.env.STATUS_URL}` + : `āŒ Deployment [${process.env.DEPLOYMENT_ID}] failed\n\nCommit: ${context.sha.substring(0, 7)}\nWorkflow Status: ${process.env.STATUS_URL}`; + + // Update or create comment + const commentParams = { + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }; + + try { + if (process.env.COMMENT_ID) { + await github.rest.issues.updateComment({ + ...commentParams, + comment_id: process.env.COMMENT_ID + }); + } else { + await github.rest.issues.createComment({ + ...commentParams, + issue_number: context.issue.number || context.payload.pull_request.number + }); + } + } catch (error) { + console.error('Failed to update/create comment:', error); + // Create a new comment if update fails + await github.rest.issues.createComment({ + ...commentParams, + issue_number: context.issue.number || context.payload.pull_request.number + }); + } diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index bc814e9f..c04aaa06 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -1,138 +1,67 @@ -name: Deploy Review App to Control Plane +name: Deploy Review App on: - workflow_dispatch: pull_request: types: [opened, synchronize, reopened] - branches: [master] issue_comment: types: [created] -concurrency: - group: review-app-${{ github.event.pull_request.number || github.event.issue.number }} - cancel-in-progress: true - env: - CPLN_ORG: ${{secrets.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 }} + CPLN_ORG: ${{ secrets.CPLN_ORG }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: check-concurrent: - name: Deploy Review App to Control Plane / check-concurrent + name: Check concurrent deployments runs-on: ubuntu-latest outputs: cancelled: ${{ steps.check.outputs.cancelled }} steps: - - name: Check for concurrent deployment + - uses: actions/github-script@v7 id: check - run: | - if [ "${{ github.run_attempt }}" != "1" ]; then - echo "āš ļø Cancelling previous deployment due to new code push..." - echo "cancelled=true" >> $GITHUB_OUTPUT - else - echo "cancelled=false" >> $GITHUB_OUTPUT - fi + with: + script: | + const runs = await github.rest.actions.listWorkflowRuns({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: context.workflow, + status: 'in_progress', + branch: context.payload.pull_request?.head.ref + }); + core.setOutput('cancelled', runs.data.total_count > 1 ? 'true' : 'false'); - deploy-to-control-plane-review: + deploy: needs: check-concurrent if: | - needs.check-concurrent.outputs.cancelled != 'true' && - (github.event_name == 'workflow_dispatch' || - github.event_name == 'pull_request' || - (github.event_name == 'issue_comment' && - github.event.comment.body == '/deploy-review-app' && - github.event.issue.pull_request)) + needs.check-concurrent.outputs.cancelled != 'true' && + ((github.event_name == 'pull_request') || + (github.event_name == 'issue_comment' && github.event.comment.body == '/deploy-review-app')) runs-on: ubuntu-latest - permissions: contents: read deployments: write pull-requests: write - - outputs: - app_url: ${{ steps.deploy.outputs.app_url }} - deployment_id: ${{ steps.create-deployment.outputs.result }} + issues: write steps: - - name: Create initial comment and get job URL + - uses: actions/checkout@v4 + + - name: Create initial comment id: create-comment uses: actions/github-script@v7 with: script: | - const currentJob = await github.rest.actions.getJobForWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - job_id: context.runId - }).then(response => response.data); - - const statusUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${currentJob.id}?pr=${context.issue.number || context.payload.pull_request.number}`; - core.exportVariable('statusUrl', statusUrl); - const deploymentId = Date.now().toString(); core.exportVariable('deploymentId', deploymentId); - - const message = "šŸš€ Starting new deployment [" + deploymentId + "] for commit: " + context.sha.substring(0, 7) + - "\nChanges: " + (context.payload.commits ? context.payload.commits[0].message : '') + - "\nStatus: " + statusUrl; - const comment = await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, - body: message + body: `šŸš€ Starting deployment [${deploymentId}] for ${context.sha.substring(0, 7)}` }); - core.setOutput('comment-id', comment.data.id); - - name: Create GitHub Deployment - id: create-deployment - uses: actions/github-script@v7 - with: - script: | - const deployment = await github.rest.repos.createDeployment({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: context.sha, - environment: 'review-app', - auto_merge: false, - required_contexts: [] - }); - return deployment.data.id; - - - name: Get PR HEAD Ref - if: ${{ github.event_name == 'issue_comment' }} - id: getRef - run: | - echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout source code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} - - - name: Update deployment status (in_progress) - uses: actions/github-script@v7 - with: - script: | - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.result }}, - state: 'in_progress', - description: 'Deployment is in progress' - }); - - - name: Configure app name - id: app-config - run: | - APP_NAME="qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" - echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV - echo "app_name=$APP_NAME" >> $GITHUB_OUTPUT - - name: Deploy to Control Plane id: deploy uses: ./.github/actions/deploy-to-control-plane @@ -142,72 +71,12 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} - name: Post deployment status - if: success() - uses: actions/github-script@v7 - env: - RAILS_URL: ${{ steps.deploy.outputs.rails_url }} - COMMENT_ID: ${{ steps.create-comment.outputs.comment-id }} - DEPLOYMENT_ID: ${{ env.deploymentId }} + if: always() + uses: ./.github/actions/post-deployment-status with: - script: | - const message = "āœ… Deployment [" + process.env.DEPLOYMENT_ID + "] successful!\n\nšŸš€ Rails app: " + process.env.RAILS_URL + "\nšŸ“Š Status: " + process.env.statusUrl; - - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: message - }); - - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.result }}, - state: 'success', - environment_url: process.env.RAILS_URL, - description: 'āœ… Deployment successful' - }); - - - name: Post deployment failure - if: failure() - uses: actions/github-script@v7 - env: - COMMENT_ID: ${{ steps.create-comment.outputs.comment-id }} - DEPLOYMENT_ID: ${{ env.deploymentId }} - with: - script: | - console.log('Debug info:'); - console.log('COMMENT_ID:', process.env.COMMENT_ID); - console.log('DEPLOYMENT_ID:', process.env.DEPLOYMENT_ID); - console.log('create-deployment result:', ${{ steps.create-deployment.outputs.result }}); - - const message = "āŒ Deployment [" + (process.env.DEPLOYMENT_ID || 'unknown') + "] failed\n\nCommit: " + context.sha.substring(0, 7) + "\nWorkflow Status: " + process.env.statusUrl; - - // Only try to update comment if we have a comment ID - if (process.env.COMMENT_ID) { - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: message - }); - } else { - // Fall back to creating a new comment - await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: message - }); - } - - // Only create deployment status if we have a deployment ID - if (${{ steps.create-deployment.outputs.result }}) { - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: ${{ steps.create-deployment.outputs.result }}, - state: 'failure', - description: 'āŒ Deployment failed' - }); - } + status: ${{ job.status == 'success' && 'success' || 'failure' }} + rails-url: ${{ steps.deploy.outputs.rails_url }} + github-token: ${{ secrets.GITHUB_TOKEN }} + deployment-id: ${{ env.deploymentId }} + comment-id: ${{ steps.create-comment.outputs.comment-id }} + workflow-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} From 1cff9760d9b074ec5ae7417016fdf99bb109a485 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 17:42:56 -1000 Subject: [PATCH 23/59] fixes --- .../deploy-to-control-plane-review.yml | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index c04aaa06..84a50365 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -6,37 +6,23 @@ on: issue_comment: types: [created] +# Use concurrency to cancel in-progress runs +concurrency: + group: deploy-${{ github.event.pull_request.number || 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 }} CPLN_ORG: ${{ secrets.CPLN_ORG }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: - check-concurrent: - name: Check concurrent deployments - runs-on: ubuntu-latest - outputs: - cancelled: ${{ steps.check.outputs.cancelled }} - steps: - - uses: actions/github-script@v7 - id: check - with: - script: | - const runs = await github.rest.actions.listWorkflowRuns({ - owner: context.repo.owner, - repo: context.repo.repo, - workflow_id: context.workflow, - status: 'in_progress', - branch: context.payload.pull_request?.head.ref - }); - core.setOutput('cancelled', runs.data.total_count > 1 ? 'true' : 'false'); - deploy: - needs: check-concurrent if: | - needs.check-concurrent.outputs.cancelled != 'true' && - ((github.event_name == 'pull_request') || - (github.event_name == 'issue_comment' && github.event.comment.body == '/deploy-review-app')) + github.event_name == 'pull_request' || + (github.event_name == 'issue_comment' && + github.event.comment.body == '/deploy-review-app' && + github.event.issue.pull_request) runs-on: ubuntu-latest permissions: contents: read From 6cbdb04985a97c537e658f789f18136c7a249c38 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 17:53:11 -1000 Subject: [PATCH 24/59] fixes --- .github/actions/deploy-to-control-plane/action.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 6ff04e76..6f01bb46 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -22,6 +22,9 @@ outputs: runs: using: "composite" steps: + - name: Setup Environment + uses: ./.github/actions/setup-environment + - name: Get commit SHA id: get_sha shell: bash From 0b15816ca03d5b1e13ecadcfccb200dcea8987c8 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 18:01:25 -1000 Subject: [PATCH 25/59] fixes --- .github/actions/setup-environment/action.yml | 16 ++++++++++++++-- .../workflows/deploy-to-control-plane-review.yml | 6 +++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml index ea06f3a9..788cd48d 100644 --- a/.github/actions/setup-environment/action.yml +++ b/.github/actions/setup-environment/action.yml @@ -19,7 +19,19 @@ runs: gem install cpflow -v 4.1.0 cpflow --version - - name: cpln profile + - name: Setup Control Plane Profile shell: bash run: | - cpln profile update default + if [ -z "$CPLN_TOKEN" ]; then + echo " Error: CPLN_TOKEN environment variable is not set" + exit 1 + fi + + if [ -z "$CPLN_ORG" ]; then + echo " Error: CPLN_ORG environment variable is not set" + exit 1 + fi + + echo "Setting up Control Plane profile..." + echo "Organization: $CPLN_ORG" + cpln profile update default --org "$CPLN_ORG" --token "$CPLN_TOKEN" diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 84a50365..0552b9e5 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -13,7 +13,8 @@ concurrency: env: APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number }} - CPLN_ORG: ${{ secrets.CPLN_ORG }} + CPLN_ORG: ${{ secrets.CPLN_ORG_STAGING }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: @@ -51,6 +52,9 @@ jobs: - name: Deploy to Control Plane id: deploy uses: ./.github/actions/deploy-to-control-plane + env: + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} + CPLN_ORG: ${{ secrets.CPLN_ORG_STAGING }} with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} From ae8a473e90b63708fdbd56c8fa70c42d73b3a75d Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 18:17:11 -1000 Subject: [PATCH 26/59] fixes --- .../actions/post-deployment-status/action.yml | 70 --------------- .github/actions/setup-environment/action.yml | 3 + .../deploy-to-control-plane-review.yml | 88 ++++++++++++++++--- 3 files changed, 77 insertions(+), 84 deletions(-) delete mode 100644 .github/actions/post-deployment-status/action.yml diff --git a/.github/actions/post-deployment-status/action.yml b/.github/actions/post-deployment-status/action.yml deleted file mode 100644 index 4701502b..00000000 --- a/.github/actions/post-deployment-status/action.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: 'Post Deployment Status' -description: 'Posts deployment status updates to PR comments' -inputs: - status: - description: 'Status of deployment (success/failure)' - required: true - rails-url: - description: 'URL of the Rails app' - required: false - github-token: - description: 'GitHub token' - required: true - deployment-id: - description: 'Deployment ID' - required: false - default: 'unknown' - comment-id: - description: 'Comment ID to update' - required: false - workflow-url: - description: 'Workflow URL' - required: true - -runs: - using: "composite" - steps: - - name: Post status - uses: actions/github-script@v7 - env: - RAILS_URL: ${{ inputs.rails-url }} - COMMENT_ID: ${{ inputs.comment-id }} - DEPLOYMENT_ID: ${{ inputs.deployment-id }} - STATUS_URL: ${{ inputs.workflow-url }} - with: - github-token: ${{ inputs.github-token }} - script: | - const isSuccess = '${{ inputs.status }}' === 'success'; - - // Create appropriate message based on status - const message = isSuccess - ? `āœ… Deployment [${process.env.DEPLOYMENT_ID}] successful!\n\nšŸš€ Rails app: ${process.env.RAILS_URL}\nšŸ“Š Status: ${process.env.STATUS_URL}` - : `āŒ Deployment [${process.env.DEPLOYMENT_ID}] failed\n\nCommit: ${context.sha.substring(0, 7)}\nWorkflow Status: ${process.env.STATUS_URL}`; - - // Update or create comment - const commentParams = { - owner: context.repo.owner, - repo: context.repo.repo, - body: message - }; - - try { - if (process.env.COMMENT_ID) { - await github.rest.issues.updateComment({ - ...commentParams, - comment_id: process.env.COMMENT_ID - }); - } else { - await github.rest.issues.createComment({ - ...commentParams, - issue_number: context.issue.number || context.payload.pull_request.number - }); - } - } catch (error) { - console.error('Failed to update/create comment:', error); - // Create a new comment if update fails - await github.rest.issues.createComment({ - ...commentParams, - issue_number: context.issue.number || context.payload.pull_request.number - }); - } diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml index 788cd48d..829a9498 100644 --- a/.github/actions/setup-environment/action.yml +++ b/.github/actions/setup-environment/action.yml @@ -35,3 +35,6 @@ runs: echo "Setting up Control Plane profile..." echo "Organization: $CPLN_ORG" cpln profile update default --org "$CPLN_ORG" --token "$CPLN_TOKEN" + + echo "Setting up Docker login for Control Plane registry..." + cpln image docker-login --org "$CPLN_ORG" diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 0552b9e5..d7c40442 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -32,22 +32,61 @@ jobs: issues: write steps: + - name: Get PR HEAD Ref + if: ${{ github.event_name == 'issue_comment' }} + id: getRef + run: | + echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} - - name: Create initial comment - id: create-comment + - name: Initialize Deployment + id: init-deployment uses: actions/github-script@v7 with: script: | - const deploymentId = Date.now().toString(); - core.exportVariable('deploymentId', deploymentId); + // Create GitHub deployment + const deployment = await github.rest.repos.createDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: context.sha, + environment: 'review-app', + auto_merge: false, + required_contexts: [] + }); + + // Create initial comment const comment = await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment [${deploymentId}] for ${context.sha.substring(0, 7)}` + body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)}\nDeployment ID: ${deployment.data.id}` + }); + + // Set deployment status to in_progress + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.data.id, + state: 'in_progress', + description: 'Deployment is in progress' }); - core.setOutput('comment-id', comment.data.id); + + return { + deploymentId: deployment.data.id, + commentId: comment.data.id + }; + + - name: Setup cpflow app + run: | + if ! cpflow exists -a ${{ env.APP_NAME }} ; then + cpflow setup-app -a ${{ env.APP_NAME }} + fi - name: Deploy to Control Plane id: deploy @@ -60,13 +99,34 @@ jobs: org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} - - name: Post deployment status + - name: Update Status if: always() - uses: ./.github/actions/post-deployment-status + uses: actions/github-script@v7 with: - status: ${{ job.status == 'success' && 'success' || 'failure' }} - rails-url: ${{ steps.deploy.outputs.rails_url }} - github-token: ${{ secrets.GITHUB_TOKEN }} - deployment-id: ${{ env.deploymentId }} - comment-id: ${{ steps.create-comment.outputs.comment-id }} - workflow-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + script: | + const isSuccess = '${{ job.status }}' === 'success'; + const deploymentId = ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }}; + const commentId = ${{ fromJSON(steps.init-deployment.outputs.result).commentId }}; + const railsUrl = '${{ steps.deploy.outputs.rails_url }}'; + + // Update deployment status + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deploymentId, + state: isSuccess ? 'success' : 'failure', + ...(isSuccess && { environment_url: railsUrl }), + description: isSuccess ? 'āœ… Deployment successful' : 'āŒ Deployment failed' + }); + + // Update comment + const message = isSuccess + ? `āœ… Deployment successful!\n\nšŸš€ Rails app: ${railsUrl}\nšŸ“Š Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + : `āŒ Deployment failed\n\nCommit: ${context.sha.substring(0, 7)}\nWorkflow Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: message + }); From e6d50257af0feaccb54b817aa80f13cd2f9841a1 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 18:20:07 -1000 Subject: [PATCH 27/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index d7c40442..f3bad6e3 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -45,6 +45,9 @@ jobs: fetch-depth: 0 ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} + - name: Setup Environment + uses: ./.github/actions/setup-environment + - name: Initialize Deployment id: init-deployment uses: actions/github-script@v7 From 444ec85d340b58e2431df2d92e6a0636cd9d3b06 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 20:54:28 -1000 Subject: [PATCH 28/59] fixes --- .../deploy-to-control-plane/action.yml | 35 ++++++++++++++----- .../deploy-to-control-plane-review.yml | 2 +- .../deploy-to-control-plane-staging.yml | 6 ++-- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 6f01bb46..a3353634 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -29,22 +29,39 @@ runs: id: get_sha shell: bash run: | - echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - echo "Using commit SHA: $(git rev-parse --short HEAD)" + if [ -n "$PR_NUMBER" ]; then + # If PR_NUMBER is set, get the PR's head SHA + PR_SHA=$(gh pr view $PR_NUMBER --json headRefOid --jq '.headRefOid') + 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 + CURRENT_SHA=$(git rev-parse HEAD) + 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 + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + PR_NUMBER: ${{ env.PR_NUMBER }} + + - name: Build Image + id: build + shell: bash + run: | + echo "šŸ—ļø Building image with commit: ${{steps.get_sha.outputs.sha_short}}" + cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} - - name: Deploy to Control Plane + - name: Deploy Image id: deploy shell: bash run: | # Create temp file for output TEMP_OUTPUT=$(mktemp) - echo "šŸš€ Deploying with commit: ${{steps.get_sha.outputs.sha_short}}" - - # Build and deploy - if cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} | tee "$TEMP_OUTPUT" && \ - cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose | tee -a "$TEMP_OUTPUT"; then - + echo "šŸš€ Deploying image..." + if cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose | tee "$TEMP_OUTPUT"; then # Extract Rails URL RAILS_URL=$(grep -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT") if [ -n "$RAILS_URL" ]; then diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index f3bad6e3..c70e4604 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -1,4 +1,4 @@ -name: Deploy Review App +name: Deploy Review or Staging App on: pull_request: diff --git a/.github/workflows/deploy-to-control-plane-staging.yml b/.github/workflows/deploy-to-control-plane-staging.yml index 1f276b5c..2a6a5e80 100644 --- a/.github/workflows/deploy-to-control-plane-staging.yml +++ b/.github/workflows/deploy-to-control-plane-staging.yml @@ -21,8 +21,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Check out the repo - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for proper SHA handling + ref: master # Explicitly checkout master branch - uses: ./.github/actions/deploy-to-control-plane with: From 8041a01059cb3a7631064f80db5b2edbea0f4d10 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 21:04:25 -1000 Subject: [PATCH 29/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index c70e4604..a21dffce 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -63,12 +63,14 @@ jobs: required_contexts: [] }); + const runUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; + // Create initial comment const comment = await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)}\nDeployment ID: ${deployment.data.id}` + body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)}\nDeployment ID: ${deployment.data.id}\nGitHub Actions Run: ${runUrl}` }); // Set deployment status to in_progress From b03b6d7f3ac43adf822f5535ea28c6592374bf1f Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 21:07:37 -1000 Subject: [PATCH 30/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index a21dffce..bb16ab99 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -63,14 +63,13 @@ jobs: required_contexts: [] }); - const runUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${process.env.GITHUB_JOB}?pr=${context.issue.number || context.payload.pull_request.number}`; - // Create initial comment const comment = await github.rest.issues.createComment({ issue_number: context.issue.number || context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)}\nDeployment ID: ${deployment.data.id}\nGitHub Actions Run: ${runUrl}` + body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)} +GitHub Actions Run: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${process.env.GITHUB_JOB_ID}?pr=${context.issue.number || context.payload.pull_request.number}` }); // Set deployment status to in_progress From a12e0d4c9d8063d22d56248b37836adbde274346 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 21:09:31 -1000 Subject: [PATCH 31/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index bb16ab99..0867327f 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -68,8 +68,7 @@ jobs: issue_number: context.issue.number || context.payload.pull_request.number, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)} -GitHub Actions Run: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${process.env.GITHUB_JOB_ID}?pr=${context.issue.number || context.payload.pull_request.number}` + body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)}\nGitHub Actions Run: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${process.env.GITHUB_JOB_ID}?pr=${context.issue.number || context.payload.pull_request.number}` }); // Set deployment status to in_progress From 98649f2652fa017c07a4c7e5537524f6968ef09f Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 21:14:23 -1000 Subject: [PATCH 32/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 0867327f..1e94aba3 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -51,6 +51,8 @@ jobs: - name: Initialize Deployment id: init-deployment uses: actions/github-script@v7 + env: + JOB_ID: ${{ github.job }} with: script: | // Create GitHub deployment @@ -63,12 +65,14 @@ jobs: required_contexts: [] }); + const prNumber = context.issue.number || context.payload.pull_request.number; + // Create initial comment const comment = await github.rest.issues.createComment({ - issue_number: context.issue.number || context.payload.pull_request.number, + issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for ${context.sha.substring(0, 7)}\nGitHub Actions Run: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${process.env.GITHUB_JOB_ID}?pr=${context.issue.number || context.payload.pull_request.number}` + body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job}?pr=${prNumber}` }); // Set deployment status to in_progress From b2e710abc9f819c81dbee964c20f0ebeb229a709 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 21:20:38 -1000 Subject: [PATCH 33/59] fixes --- .github/workflows/deploy-to-control-plane-review.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 1e94aba3..1d259ff7 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -48,11 +48,15 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup-environment + - name: Get Job ID + id: get-job-id + run: echo "job_id=${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" >> $GITHUB_OUTPUT + - name: Initialize Deployment id: init-deployment uses: actions/github-script@v7 env: - JOB_ID: ${{ github.job }} + JOB_ID: ${{ steps.get-job-id.outputs.job_id }} with: script: | // Create GitHub deployment @@ -72,7 +76,7 @@ jobs: issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job}?pr=${prNumber}` + body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/jobs/${process.env.JOB_ID}?pr=${prNumber}` }); // Set deployment status to in_progress From c54a54481584616b60eea7cec9fd85ffd725f277 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 21:55:26 -1000 Subject: [PATCH 34/59] fixes --- .../deploy-to-control-plane-review.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 1d259ff7..1c577e01 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -48,15 +48,9 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup-environment - - name: Get Job ID - id: get-job-id - run: echo "job_id=${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}" >> $GITHUB_OUTPUT - - name: Initialize Deployment id: init-deployment uses: actions/github-script@v7 - env: - JOB_ID: ${{ steps.get-job-id.outputs.job_id }} with: script: | // Create GitHub deployment @@ -71,12 +65,21 @@ jobs: const prNumber = context.issue.number || context.payload.pull_request.number; + // Get the job ID from the workflow run + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.runId + }); + + const jobId = jobs.data.jobs.find(job => job.name === 'deploy')?.id; + // Create initial comment const comment = await github.rest.issues.createComment({ issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/jobs/${process.env.JOB_ID}?pr=${prNumber}` + body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${jobId}?pr=${prNumber}` }); // Set deployment status to in_progress From c80ff43caf15e00d065da996185be25abb9d9a64 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Thu, 23 Jan 2025 22:10:50 -1000 Subject: [PATCH 35/59] fixes --- .../deploy-to-control-plane/action.yml | 63 ++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index a3353634..729c03ed 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -25,7 +25,7 @@ runs: - name: Setup Environment uses: ./.github/actions/setup-environment - - name: Get commit SHA + - name: Get Commit SHA id: get_sha shell: bash run: | @@ -46,22 +46,69 @@ runs: GITHUB_TOKEN: ${{ inputs.github_token }} PR_NUMBER: ${{ env.PR_NUMBER }} - - name: Build Image + - name: Initialize Deployment + id: init-deployment + uses: actions/github-script@v7 + with: + script: | + // Create GitHub deployment + const deployment = await github.rest.repos.createDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: context.sha, + environment: 'review-app', + auto_merge: false, + required_contexts: [] + }); + + const prNumber = context.issue.number || context.payload.pull_request.number; + + // Get the job ID from the workflow run + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.runId + }); + + const jobId = jobs.data.jobs.find(job => job.name === 'deploy')?.id; + + // Create initial comment + const comment = await github.rest.issues.createComment({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${jobId}?pr=${prNumber}` + }); + + // Set deployment status to in_progress + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.data.id, + state: 'in_progress', + description: 'Deployment is in progress' + }); + + return { + deploymentId: deployment.data.id, + commentId: comment.data.id + }; + + - name: Build Docker Image id: build shell: bash run: | - echo "šŸ—ļø Building image with commit: ${{steps.get_sha.outputs.sha_short}}" - cpflow build-image -a ${{ inputs.app_name }} --commit=${{steps.get_sha.outputs.sha_short}} --org=${{inputs.org}} + echo "šŸ—ļø Building Docker image..." + cpflow build-image -a ${{ inputs.app_name }} --commit=${{ github.sha }} --org=${{ inputs.org }} - - name: Deploy Image + - name: Deploy to Control Plane id: deploy shell: bash run: | - # Create temp file for output + echo "šŸš€ Deploying to Control Plane..." TEMP_OUTPUT=$(mktemp) - echo "šŸš€ Deploying image..." - if cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose | tee "$TEMP_OUTPUT"; then + if cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{ inputs.org }} --verbose | tee "$TEMP_OUTPUT"; then # Extract Rails URL RAILS_URL=$(grep -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT") if [ -n "$RAILS_URL" ]; then From 40473cc05ed5e2d57ad86f4dd3512ba7c8c4c05b Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 11:49:02 -1000 Subject: [PATCH 36/59] fixes --- .../deploy-to-control-plane/action.yml | 22 +------------------ .../deploy-to-control-plane-review.yml | 6 ++--- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 729c03ed..924f3d95 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -61,25 +61,6 @@ runs: required_contexts: [] }); - const prNumber = context.issue.number || context.payload.pull_request.number; - - // Get the job ID from the workflow run - const jobs = await github.rest.actions.listJobsForWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.runId - }); - - const jobId = jobs.data.jobs.find(job => job.name === 'deploy')?.id; - - // Create initial comment - const comment = await github.rest.issues.createComment({ - issue_number: prNumber, - owner: context.repo.owner, - repo: context.repo.repo, - body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${jobId}?pr=${prNumber}` - }); - // Set deployment status to in_progress await github.rest.repos.createDeploymentStatus({ owner: context.repo.owner, @@ -90,8 +71,7 @@ runs: }); return { - deploymentId: deployment.data.id, - commentId: comment.data.id + deploymentId: deployment.data.id }; - name: Build Docker Image diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index 1c577e01..ebf910f4 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -133,10 +133,10 @@ jobs: description: isSuccess ? 'āœ… Deployment successful' : 'āŒ Deployment failed' }); - // Update comment + // Update the initial comment const message = isSuccess - ? `āœ… Deployment successful!\n\nšŸš€ Rails app: ${railsUrl}\nšŸ“Š Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` - : `āŒ Deployment failed\n\nCommit: ${context.sha.substring(0, 7)}\nWorkflow Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + ? `āœ… Deployment Successful for PR ${context.issue.number}\n\nšŸš€ Rails app: ${railsUrl}\nšŸ“Š Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + : `āŒ Deployment failed for PR ${context.issue.number}\n\nCommit: ${context.sha.substring(0, 7)}\nWorkflow Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; await github.rest.issues.updateComment({ owner: context.repo.owner, From 038cf8f968f84873019feabdff42e28b68f03129 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 12:04:33 -1000 Subject: [PATCH 37/59] fixes --- .../workflows/deploy-to-control-plane-review.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index ebf910f4..a47fcbb0 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -79,7 +79,9 @@ jobs: issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for PR ${prNumber}\nDeployment Log: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${jobId}?pr=${prNumber}` + body: `šŸš€ Starting deployment for PR ${prNumber} + +[View Deployment Log](${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${jobId}?pr=${prNumber})` }); // Set deployment status to in_progress @@ -135,8 +137,16 @@ jobs: // Update the initial comment const message = isSuccess - ? `āœ… Deployment Successful for PR ${context.issue.number}\n\nšŸš€ Rails app: ${railsUrl}\nšŸ“Š Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` - : `āŒ Deployment failed for PR ${context.issue.number}\n\nCommit: ${context.sha.substring(0, 7)}\nWorkflow Status: ${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + ? `āœ… Deployment Successful for PR ${context.issue.number} + +šŸš€ Rails App: [${railsUrl}](${railsUrl}) + +[View Workflow Status](${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` + : `āŒ Deployment failed for PR ${context.issue.number} + +Commit: ${context.sha.substring(0, 7)} + +[View Workflow Status](${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`; await github.rest.issues.updateComment({ owner: context.repo.owner, From c25211fd0e5ef8ffd40d72ee8d8a53dc7cd982f4 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 12:16:58 -1000 Subject: [PATCH 38/59] fixes --- .../deploy-to-control-plane/action.yml | 28 ---------- .../deploy-to-control-plane-review.yml | 52 +++++++++++++------ 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 924f3d95..034f8335 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -46,34 +46,6 @@ runs: GITHUB_TOKEN: ${{ inputs.github_token }} PR_NUMBER: ${{ env.PR_NUMBER }} - - name: Initialize Deployment - id: init-deployment - uses: actions/github-script@v7 - with: - script: | - // Create GitHub deployment - const deployment = await github.rest.repos.createDeployment({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: context.sha, - environment: 'review-app', - auto_merge: false, - required_contexts: [] - }); - - // Set deployment status to in_progress - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: deployment.data.id, - state: 'in_progress', - description: 'Deployment is in progress' - }); - - return { - deploymentId: deployment.data.id - }; - - name: Build Docker Image id: build shell: bash diff --git a/.github/workflows/deploy-to-control-plane-review.yml b/.github/workflows/deploy-to-control-plane-review.yml index a47fcbb0..5378820a 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane-review.yml @@ -53,6 +53,16 @@ jobs: uses: actions/github-script@v7 with: script: | + // Helper functions + const getWorkflowUrl = (runId) => + `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; + + const getJobUrl = (runId, jobId, prNumber) => + `${getWorkflowUrl(runId)}/job/${jobId}?pr=${prNumber}`; + + // Get PR number consistently + const prNumber = process.env.PR_NUMBER; + // Create GitHub deployment const deployment = await github.rest.repos.createDeployment({ owner: context.repo.owner, @@ -63,9 +73,7 @@ jobs: required_contexts: [] }); - const prNumber = context.issue.number || context.payload.pull_request.number; - - // Get the job ID from the workflow run + // Get the job ID const jobs = await github.rest.actions.listJobsForWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, @@ -73,15 +81,18 @@ jobs: }); const jobId = jobs.data.jobs.find(job => job.name === 'deploy')?.id; + const jobUrl = getJobUrl(context.runId, jobId, prNumber); // Create initial comment const comment = await github.rest.issues.createComment({ issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, - body: `šŸš€ Starting deployment for PR ${prNumber} - -[View Deployment Log](${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${jobId}?pr=${prNumber})` + body: [ + 'šŸš€ Starting deployment for PR ' + prNumber, + '', + '[View Deployment Log](' + jobUrl + ')' + ].join('\n') }); // Set deployment status to in_progress @@ -95,7 +106,8 @@ jobs: return { deploymentId: deployment.data.id, - commentId: comment.data.id + commentId: comment.data.id, + workflowUrl: getWorkflowUrl(context.runId) }; - name: Setup cpflow app @@ -123,7 +135,9 @@ jobs: const isSuccess = '${{ job.status }}' === 'success'; const deploymentId = ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }}; const commentId = ${{ fromJSON(steps.init-deployment.outputs.result).commentId }}; + const workflowUrl = ${{ fromJSON(steps.init-deployment.outputs.result).workflowUrl }}; const railsUrl = '${{ steps.deploy.outputs.rails_url }}'; + const prNumber = process.env.PR_NUMBER; // Update deployment status await github.rest.repos.createDeploymentStatus({ @@ -137,16 +151,20 @@ jobs: // Update the initial comment const message = isSuccess - ? `āœ… Deployment Successful for PR ${context.issue.number} - -šŸš€ Rails App: [${railsUrl}](${railsUrl}) - -[View Workflow Status](${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` - : `āŒ Deployment failed for PR ${context.issue.number} - -Commit: ${context.sha.substring(0, 7)} - -[View Workflow Status](${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`; + ? [ + 'āœ… Deployment Successful for PR ' + prNumber, + '', + 'šŸš€ Rails App: [' + railsUrl + '](' + railsUrl + ')', + '', + '[View Workflow Status](' + workflowUrl + ')' + ].join('\n') + : [ + 'āŒ Deployment failed for PR ' + prNumber, + '', + 'Commit: ' + context.sha.substring(0, 7), + '', + '[View Workflow Status](' + workflowUrl + ')' + ].join('\n'); await github.rest.issues.updateComment({ owner: context.repo.owner, From 304e642ac07fa61fc38aed11c34b4ae1bbfba6ba Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 12:46:29 -1000 Subject: [PATCH 39/59] fixes --- .github/actions/build-docker-image/action.yml | 36 ++++++++++++++ .../deploy-to-control-plane/action.yml | 48 +++++-------------- .../deploy-to-control-plane/scripts/deploy.sh | 34 +++++++++++++ .../scripts/get-commit-sha.sh | 28 +++++++++++ ...review.yml => deploy-to-control-plane.yml} | 11 +++-- 5 files changed, 118 insertions(+), 39 deletions(-) create mode 100644 .github/actions/build-docker-image/action.yml create mode 100755 .github/actions/deploy-to-control-plane/scripts/deploy.sh create mode 100755 .github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh rename .github/workflows/{deploy-to-control-plane-review.yml => deploy-to-control-plane.yml} (96%) diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml new file mode 100644 index 00000000..273fe2aa --- /dev/null +++ b/.github/actions/build-docker-image/action.yml @@ -0,0 +1,36 @@ +name: Build Docker Image +description: 'Builds a Docker image for the application' + +inputs: + app_name: + description: 'Name of the application' + required: true + org: + description: 'Organization name' + required: true + commit: + description: 'Commit SHA to tag the image with' + required: true + +runs: + using: "composite" + steps: + - name: Build Docker Image + id: build + shell: bash + run: | + # Redirect build output to a log file to keep Actions log clean + LOG_FILE=$(mktemp) + echo "šŸ—ļø Building Docker image... (detailed logs will be shown at the end if there's an error)" + + if cpflow build-image -a ${{ inputs.app_name }} --commit=${{ inputs.commit }} --org=${{ inputs.org }} > "$LOG_FILE" 2>&1; then + echo "āœ… Docker image build successful" + else + BUILD_EXIT_CODE=$? + echo "āŒ Docker image build failed" + echo "==== Build Logs ====" + cat "$LOG_FILE" + rm -f "$LOG_FILE" + exit $BUILD_EXIT_CODE + fi + rm -f "$LOG_FILE" diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 034f8335..113a6daa 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -29,49 +29,25 @@ runs: id: get_sha shell: bash run: | - if [ -n "$PR_NUMBER" ]; then - # If PR_NUMBER is set, get the PR's head SHA - PR_SHA=$(gh pr view $PR_NUMBER --json headRefOid --jq '.headRefOid') - 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 - CURRENT_SHA=$(git rev-parse HEAD) - 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 + chmod +x ${{ github.action_path }}/scripts/get-commit-sha.sh + ${{ github.action_path }}/scripts/get-commit-sha.sh env: GITHUB_TOKEN: ${{ inputs.github_token }} PR_NUMBER: ${{ env.PR_NUMBER }} - name: Build Docker Image - id: build - shell: bash - run: | - echo "šŸ—ļø Building Docker image..." - cpflow build-image -a ${{ inputs.app_name }} --commit=${{ github.sha }} --org=${{ inputs.org }} + uses: ./.github/actions/build-docker-image + with: + app_name: ${{ inputs.app_name }} + org: ${{ inputs.org }} + commit: ${{ github.sha }} - name: Deploy to Control Plane id: deploy shell: bash run: | - echo "šŸš€ Deploying to Control Plane..." - TEMP_OUTPUT=$(mktemp) - - if cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{ inputs.org }} --verbose | tee "$TEMP_OUTPUT"; then - # Extract Rails URL - RAILS_URL=$(grep -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT") - if [ -n "$RAILS_URL" ]; then - echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT - echo "āœ… Deployment successful: $RAILS_URL" - else - echo "āŒ Failed to extract Rails URL" - exit 1 - fi - else - echo "āŒ Deployment failed" - exit 1 - fi - rm -f "$TEMP_OUTPUT" + chmod +x ${{ github.action_path }}/scripts/deploy.sh + ${{ github.action_path }}/scripts/deploy.sh + env: + APP_NAME: ${{ inputs.app_name }} + CPLN_ORG: ${{ inputs.org }} diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh new file mode 100755 index 00000000..7de6ec9d --- /dev/null +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -0,0 +1,34 @@ +#!/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 +# +# Outputs: +# - rails_url: URL of the deployed Rails application + +set -e + +echo "šŸš€ Deploying to Control Plane..." +TEMP_OUTPUT=$(mktemp) + +# Deploy the application and capture output +if 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 -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT") + if [ -n "$RAILS_URL" ]; then + echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT + echo "āœ… Deployment successful: $RAILS_URL" + else + echo "āŒ Failed to extract Rails URL" + exit 1 + fi +else + echo "āŒ Deployment failed" + exit 1 +fi + +# Clean up temporary file +rm -f "$TEMP_OUTPUT" 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 new file mode 100755 index 00000000..a34dfef0 --- /dev/null +++ b/.github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh @@ -0,0 +1,28 @@ +#!/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 + PR_SHA=$(gh pr view $PR_NUMBER --json headRefOid --jq '.headRefOid') + 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 + CURRENT_SHA=$(git rev-parse HEAD) + 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-review.yml b/.github/workflows/deploy-to-control-plane.yml similarity index 96% rename from .github/workflows/deploy-to-control-plane-review.yml rename to .github/workflows/deploy-to-control-plane.yml index 5378820a..8eaddfdf 100644 --- a/.github/workflows/deploy-to-control-plane-review.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -140,14 +140,19 @@ jobs: const prNumber = process.env.PR_NUMBER; // Update deployment status - await github.rest.repos.createDeploymentStatus({ + const deploymentStatus = { owner: context.repo.owner, repo: context.repo.repo, deployment_id: deploymentId, state: isSuccess ? 'success' : 'failure', - ...(isSuccess && { environment_url: railsUrl }), description: isSuccess ? 'āœ… Deployment successful' : 'āŒ Deployment failed' - }); + }; + + if (isSuccess) { + deploymentStatus.environment_url = railsUrl; + } + + await github.rest.repos.createDeploymentStatus(deploymentStatus); // Update the initial comment const message = isSuccess From 4744c76386078fb4e70554fffa4090e2010ac241 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 12:55:30 -1000 Subject: [PATCH 40/59] fixes --- .../deploy-to-control-plane/action.yml | 7 ---- .../deploy-to-control-plane/scripts/deploy.sh | 18 +++++++--- .github/workflows/deploy-to-control-plane.yml | 36 ++++++++++--------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 113a6daa..b5d09dde 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -35,13 +35,6 @@ runs: GITHUB_TOKEN: ${{ inputs.github_token }} PR_NUMBER: ${{ env.PR_NUMBER }} - - name: Build Docker Image - uses: ./.github/actions/build-docker-image - with: - app_name: ${{ inputs.app_name }} - org: ${{ inputs.org }} - commit: ${{ github.sha }} - - 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 7de6ec9d..a1c677e0 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -11,22 +11,30 @@ set -e -echo "šŸš€ Deploying to Control Plane..." TEMP_OUTPUT=$(mktemp) -# Deploy the application and capture output +# Build the Docker image +echo "šŸ—ļø Building Docker image..." +if ! cpflow build-image -a "$APP_NAME" --commit="$GITHUB_SHA" --org="$CPLN_ORG"; then + echo "āŒ Docker image build failed" + exit 1 +fi + +# Deploy the application +echo "šŸš€ Deploying to Control Plane..." if 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 -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_OUTPUT") if [ -n "$RAILS_URL" ]; then echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT - echo "āœ… Deployment successful: $RAILS_URL" + echo "āœ… Deployment successful" + echo "šŸš€ Rails URL: $RAILS_URL" else - echo "āŒ Failed to extract Rails URL" + echo "āŒ Failed to extract Rails URL from deployment output" exit 1 fi else - echo "āŒ Deployment failed" + echo "āŒ Deployment to Control Plane failed" exit 1 fi diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 8eaddfdf..07116ba1 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,4 +1,6 @@ -name: Deploy Review or Staging App +name: Deploy 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: @@ -155,25 +157,25 @@ jobs: await github.rest.repos.createDeploymentStatus(deploymentStatus); // Update the initial comment - const message = isSuccess - ? [ - 'āœ… Deployment Successful for PR ' + prNumber, - '', - 'šŸš€ Rails App: [' + railsUrl + '](' + railsUrl + ')', - '', - '[View Workflow Status](' + workflowUrl + ')' - ].join('\n') - : [ - 'āŒ Deployment failed for PR ' + prNumber, - '', - 'Commit: ' + context.sha.substring(0, 7), - '', - '[View Workflow Status](' + workflowUrl + ')' - ].join('\n'); + const successMessage = [ + 'āœ… Deployment Successful for PR ' + prNumber, + '', + 'šŸš€ Rails App: [' + railsUrl + '](' + railsUrl + ')', + '', + '[View Workflow Status](' + workflowUrl + ')' + ].join('\n'); + + const failureMessage = [ + 'āŒ Deployment failed for PR ' + prNumber, + '', + 'Commit: ' + context.sha.substring(0, 7), + '', + '[View Workflow Status](' + workflowUrl + ')' + ].join('\n'); await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: commentId, - body: message + body: isSuccess ? successMessage : failureMessage }); From 5c8b3abb4c2ca44b0aee67f34816e44761b5a5eb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 14:57:43 -1000 Subject: [PATCH 41/59] fixes --- .../deploy-to-control-plane/scripts/deploy.sh | 21 ++++++--- .../scripts/get-commit-sha.sh | 18 +++++--- .github/workflows/deploy-to-control-plane.yml | 45 ++++++++++++++----- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index a1c677e0..bda9ab51 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -11,7 +11,16 @@ set -e +# Validate required environment variables +: "${APP_NAME:?APP_NAME environment variable is required}" +: "${CPLN_ORG:?CPLN_ORG environment variable is required}" +: "${GITHUB_SHA:?GITHUB_SHA environment variable is required}" + +# Set deployment timeout (15 minutes) +TIMEOUT=900 + TEMP_OUTPUT=$(mktemp) +trap 'rm -f "$TEMP_OUTPUT"' EXIT # Build the Docker image echo "šŸ—ļø Building Docker image..." @@ -22,21 +31,21 @@ fi # Deploy the application echo "šŸš€ Deploying to Control Plane..." -if cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then +if timeout "$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 -o 'https://rails-[^[:space:]]*\.cpln\.app' "$TEMP_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 "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 $TIMEOUT seconds" + exit 1 else echo "āŒ Deployment to Control Plane failed" exit 1 fi - -# Clean up temporary file -rm -f "$TEMP_OUTPUT" 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 index a34dfef0..12371f96 100755 --- a/.github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh +++ b/.github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh @@ -15,14 +15,20 @@ set -e if [ -n "$PR_NUMBER" ]; then # If PR_NUMBER is set, get the PR's head SHA - PR_SHA=$(gh pr view $PR_NUMBER --json headRefOid --jq '.headRefOid') - echo "sha=$PR_SHA" >> $GITHUB_OUTPUT - echo "sha_short=${PR_SHA:0:7}" >> $GITHUB_OUTPUT + 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 - CURRENT_SHA=$(git rev-parse HEAD) - echo "sha=$CURRENT_SHA" >> $GITHUB_OUTPUT - echo "sha_short=${CURRENT_SHA:0:7}" >> $GITHUB_OUTPUT + 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 07116ba1..6b601453 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,6 +1,6 @@ name: Deploy 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 == '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: @@ -114,8 +114,18 @@ jobs: - name: Setup cpflow app run: | + set -e + + # Validate required environment variables + : "${APP_NAME:?APP_NAME environment variable is required}" + if ! cpflow exists -a ${{ env.APP_NAME }} ; then - cpflow setup-app -a ${{ env.APP_NAME }} + echo "šŸ”§ Setting up new application: ${{ env.APP_NAME }}" + if ! cpflow setup-app -a ${{ env.APP_NAME }}; then + echo "āŒ Failed to setup application" + exit 1 + fi + echo "āœ… Application setup complete" fi - name: Deploy to Control Plane @@ -135,9 +145,10 @@ jobs: with: script: | const isSuccess = '${{ job.status }}' === 'success'; - const deploymentId = ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }}; - const commentId = ${{ fromJSON(steps.init-deployment.outputs.result).commentId }}; - const workflowUrl = ${{ fromJSON(steps.init-deployment.outputs.result).workflowUrl }}; + const result = ${{ steps.init-deployment.outputs.result }}; + const deploymentId = result.deploymentId; + const commentId = result.commentId; + const workflowUrl = result.workflowUrl; const railsUrl = '${{ steps.deploy.outputs.rails_url }}'; const prNumber = process.env.PR_NUMBER; @@ -154,7 +165,12 @@ jobs: deploymentStatus.environment_url = railsUrl; } - await github.rest.repos.createDeploymentStatus(deploymentStatus); + try { + await github.rest.repos.createDeploymentStatus(deploymentStatus); + } catch (error) { + console.error('Failed to update deployment status:', error); + throw error; + } // Update the initial comment const successMessage = [ @@ -173,9 +189,14 @@ jobs: '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: commentId, - body: isSuccess ? successMessage : failureMessage - }); + try { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: isSuccess ? successMessage : failureMessage + }); + } catch (error) { + console.error('Failed to update comment:', error); + throw error; + } From 2a51c928a2c721f9918c11bc0da757422a396387 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 15:09:38 -1000 Subject: [PATCH 42/59] fixes --- .../delete-control-plane-app/action.yml | 20 +++++ .../deploy-to-control-plane/action.yml | 8 +- .../scripts/delete-app.sh | 36 +++++++++ .github/workflows/deploy-to-control-plane.yml | 73 +++++++++++++++++-- .../nightly-remove-stale-review-apps.yml | 37 +++++++++- 5 files changed, 158 insertions(+), 16 deletions(-) create mode 100644 .github/actions/delete-control-plane-app/action.yml create mode 100755 .github/actions/deploy-to-control-plane/scripts/delete-app.sh diff --git a/.github/actions/delete-control-plane-app/action.yml b/.github/actions/delete-control-plane-app/action.yml new file mode 100644 index 00000000..d5d13ef7 --- /dev/null +++ b/.github/actions/delete-control-plane-app/action.yml @@ -0,0 +1,20 @@ +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 }}/../deploy-to-control-plane/scripts/delete-app.sh + env: + APP_NAME: ${{ inputs.app_name }} + CPLN_ORG: ${{ inputs.org }} diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index b5d09dde..769243fe 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -28,9 +28,7 @@ runs: - name: Get Commit SHA id: get_sha shell: bash - run: | - chmod +x ${{ github.action_path }}/scripts/get-commit-sha.sh - ${{ github.action_path }}/scripts/get-commit-sha.sh + run: ${{ github.action_path }}/scripts/get-commit-sha.sh env: GITHUB_TOKEN: ${{ inputs.github_token }} PR_NUMBER: ${{ env.PR_NUMBER }} @@ -38,9 +36,7 @@ runs: - name: Deploy to Control Plane id: deploy shell: bash - run: | - chmod +x ${{ github.action_path }}/scripts/deploy.sh - ${{ github.action_path }}/scripts/deploy.sh + run: ${{ github.action_path }}/scripts/deploy.sh env: APP_NAME: ${{ inputs.app_name }} CPLN_ORG: ${{ inputs.org }} diff --git a/.github/actions/deploy-to-control-plane/scripts/delete-app.sh b/.github/actions/deploy-to-control-plane/scripts/delete-app.sh new file mode 100755 index 00000000..92e8fbc3 --- /dev/null +++ b/.github/actions/deploy-to-control-plane/scripts/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/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 6b601453..4a1e238e 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,6 +1,6 @@ name: Deploy 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 == '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: @@ -20,11 +20,12 @@ env: PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: - deploy: + process-command: if: | github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && - github.event.comment.body == '/deploy-review-app' && + (github.event.comment.body == '/deploy-review-app' || + github.event.comment.body == '/delete-app') && github.event.issue.pull_request) runs-on: ubuntu-latest permissions: @@ -34,8 +35,67 @@ jobs: issues: write steps: + - name: Determine Action + id: determine_action + run: | + if [[ "${{ github.event.comment.body }}" == "/delete-app" ]]; then + echo "action=delete" >> $GITHUB_OUTPUT + else + echo "action=deploy" >> $GITHUB_OUTPUT + fi + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} + + - name: Setup Environment + uses: ./.github/actions/setup-environment + + # Delete App Steps + - name: Create Initial Delete Comment + if: steps.determine_action.outputs.action == 'delete' + uses: actions/github-script@v7 + id: init-delete + with: + script: | + 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...' + }); + return { commentId: comment.data.id }; + + - name: Delete App + if: steps.determine_action.outputs.action == 'delete' + id: delete + uses: ./.github/actions/delete-control-plane-app + continue-on-error: true + with: + app_name: ${{ env.APP_NAME }} + org: ${{ env.CPLN_ORG }} + + - name: Update Delete Status + if: steps.determine_action.outputs.action == 'delete' + uses: actions/github-script@v7 + with: + script: | + const success = '${{ steps.delete.outcome }}' === 'success'; + const message = success + ? 'āœ… App deletion successful' + : 'āŒ App deletion failed'; + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ fromJSON(steps.init-delete.outputs.result).commentId }}, + body: message + }); + + # Deploy Steps (existing steps) - name: Get PR HEAD Ref - if: ${{ github.event_name == 'issue_comment' }} + if: steps.determine_action.outputs.action == 'deploy' id: getRef run: | echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT @@ -47,9 +107,6 @@ jobs: fetch-depth: 0 ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} - - name: Setup Environment - uses: ./.github/actions/setup-environment - - name: Initialize Deployment id: init-deployment uses: actions/github-script@v7 @@ -82,7 +139,7 @@ jobs: run_id: context.runId }); - const jobId = jobs.data.jobs.find(job => job.name === 'deploy')?.id; + const jobId = jobs.data.jobs.find(job => job.name === 'process-command')?.id; const jobUrl = getJobUrl(context.runId, jobId, prNumber); // Create initial comment diff --git a/.github/workflows/nightly-remove-stale-review-apps.yml b/.github/workflows/nightly-remove-stale-review-apps.yml index 9f3985ba..234fe838 100644 --- a/.github/workflows/nightly-remove-stale-review-apps.yml +++ b/.github/workflows/nightly-remove-stale-review-apps.yml @@ -21,9 +21,42 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup-environment - - name: Run cleanup-stale-apps script + - name: Get Stale PRs + id: stale_prs + uses: actions/github-script@v7 + with: + script: | + const thirtyDaysAgo = new Date(); + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); + + const prs = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'closed', + sort: 'updated', + direction: 'desc' + }); + + const stalePRs = prs.data + .filter(pr => new Date(pr.updated_at) < thirtyDaysAgo) + .map(pr => pr.number); + + console.log('Found stale PRs:', stalePRs); + return stalePRs; + + - name: Delete Stale Review Apps + uses: ./.github/actions/delete-control-plane-app + if: ${{ steps.stale_prs.outputs.result != '[]' }} + env: + STALE_PRS: ${{ steps.stale_prs.outputs.result }} run: | - cpflow cleanup-stale-apps -a qa-react-webpack-rails-tutorial -y + for pr in $(echo "$STALE_PRS" | jq -r '.[]'); do + APP_NAME="qa-react-webpack-rails-tutorial-pr-$pr" + echo "šŸ—‘ļø Deleting stale review app for PR #$pr: $APP_NAME" + ./.github/actions/delete-control-plane-app/action.yml \ + --app_name "$APP_NAME" \ + --org "$CPLN_ORG" + done - name: Run cleanup-images script run: | From 61213b9f5720587341f99b879ae214bdfc613a91 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 15:35:49 -1000 Subject: [PATCH 43/59] fixes --- .github/actions/build-docker-image/action.yml | 6 +- .github/workflows/deploy-to-control-plane.yml | 100 ++++++------------ 2 files changed, 38 insertions(+), 68 deletions(-) diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml index 273fe2aa..f9b2dea0 100644 --- a/.github/actions/build-docker-image/action.yml +++ b/.github/actions/build-docker-image/action.yml @@ -21,13 +21,13 @@ runs: run: | # Redirect build output to a log file to keep Actions log clean LOG_FILE=$(mktemp) - echo "šŸ—ļø Building Docker image... (detailed logs will be shown at the end if there's an error)" + echo "šŸ—ļø Building Docker image for commit ${{ inputs.commit }}... (detailed logs will be shown at the end if there's an error)" if cpflow build-image -a ${{ inputs.app_name }} --commit=${{ inputs.commit }} --org=${{ inputs.org }} > "$LOG_FILE" 2>&1; then - echo "āœ… Docker image build successful" + echo "āœ… Docker image build successful for commit ${{ inputs.commit }}" else BUILD_EXIT_CODE=$? - echo "āŒ Docker image build failed" + echo "āŒ Docker image build failed for commit ${{ inputs.commit }}" echo "==== Build Logs ====" cat "$LOG_FILE" rm -f "$LOG_FILE" diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 4a1e238e..ed4a75ed 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -20,12 +20,12 @@ env: PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: - process-command: + Process-Deployment-Command: if: | github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && (github.event.comment.body == '/deploy-review-app' || - github.event.comment.body == '/delete-app') && + github.event.comment.body == '/delete-review-app') && github.event.issue.pull_request) runs-on: ubuntu-latest permissions: @@ -35,10 +35,19 @@ jobs: issues: write steps: + - name: Get PR HEAD Ref + if: github.event_name == 'issue_comment' + id: getRef + run: | + echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT + echo "PR_SHA=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefOid | jq -r '.headRefOid')" >> $GITHUB_OUTPUT + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Determine Action id: determine_action run: | - if [[ "${{ github.event.comment.body }}" == "/delete-app" ]]; then + if [[ "${{ github.event.comment.body }}" == "/delete-review-app" ]]; then echo "action=delete" >> $GITHUB_OUTPUT else echo "action=deploy" >> $GITHUB_OUTPUT @@ -83,8 +92,8 @@ jobs: script: | const success = '${{ steps.delete.outcome }}' === 'success'; const message = success - ? 'āœ… App deletion successful' - : 'āŒ App deletion failed'; + ? 'āœ… Review app successfully deleted' + : 'āŒ Review app deletion failed'; await github.rest.issues.updateComment({ owner: context.repo.owner, @@ -93,53 +102,38 @@ jobs: body: message }); - # Deploy Steps (existing steps) - - name: Get PR HEAD Ref - if: steps.determine_action.outputs.action == 'deploy' - id: getRef - run: | - echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} - + # Deploy Steps - name: Initialize Deployment + if: steps.determine_action.outputs.action == 'deploy' id: init-deployment uses: actions/github-script@v7 with: script: | - // Helper functions + const prNumber = process.env.PR_NUMBER; const getWorkflowUrl = (runId) => `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; - - const getJobUrl = (runId, jobId, prNumber) => - `${getWorkflowUrl(runId)}/job/${jobId}?pr=${prNumber}`; - // Get PR number consistently - const prNumber = process.env.PR_NUMBER; + const getJobUrl = (runId, jobId, prNumber) => + `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}?pr=${prNumber}`; - // Create GitHub deployment + // Create deployment const deployment = await github.rest.repos.createDeployment({ owner: context.repo.owner, repo: context.repo.repo, ref: context.sha, - environment: 'review-app', + environment: 'review-' + prNumber, auto_merge: false, required_contexts: [] }); - // Get the job ID + // Get job URL const jobs = await github.rest.actions.listJobsForWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, run_id: context.runId }); - const jobId = jobs.data.jobs.find(job => job.name === 'process-command')?.id; + const jobId = jobs.data.jobs.find(job => job.name === 'Process-Deployment-Command')?.id; const jobUrl = getJobUrl(context.runId, jobId, prNumber); // Create initial comment @@ -147,20 +141,7 @@ jobs: issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, - body: [ - 'šŸš€ Starting deployment for PR ' + prNumber, - '', - '[View Deployment Log](' + jobUrl + ')' - ].join('\n') - }); - - // Set deployment status to in_progress - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: deployment.data.id, - state: 'in_progress', - description: 'Deployment is in progress' + body: 'šŸš€ Deploying to Control Plane...\n\n[View Deployment Progress](' + jobUrl + ')' }); return { @@ -169,35 +150,23 @@ jobs: workflowUrl: getWorkflowUrl(context.runId) }; - - name: Setup cpflow app - run: | - set -e - - # Validate required environment variables - : "${APP_NAME:?APP_NAME environment variable is required}" - - if ! cpflow exists -a ${{ env.APP_NAME }} ; then - echo "šŸ”§ Setting up new application: ${{ env.APP_NAME }}" - if ! cpflow setup-app -a ${{ env.APP_NAME }}; then - echo "āŒ Failed to setup application" - exit 1 - fi - echo "āœ… Application setup complete" - fi + - name: Build Docker Image + if: steps.determine_action.outputs.action == 'deploy' + uses: ./.github/actions/build-docker-image + with: + github_token: ${{ secrets.GITHUB_TOKEN }} - name: Deploy to Control Plane + if: steps.determine_action.outputs.action == 'deploy' id: deploy uses: ./.github/actions/deploy-to-control-plane - env: - CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} - CPLN_ORG: ${{ secrets.CPLN_ORG_STAGING }} with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} - name: Update Status - if: always() + if: steps.determine_action.outputs.action == 'deploy' uses: actions/github-script@v7 with: script: | @@ -208,6 +177,7 @@ jobs: const workflowUrl = result.workflowUrl; const railsUrl = '${{ steps.deploy.outputs.rails_url }}'; const prNumber = process.env.PR_NUMBER; + const commitSha = '${{ github.event.comment.body && steps.getRef.outputs.PR_SHA || github.sha }}'; // Update deployment status const deploymentStatus = { @@ -231,9 +201,9 @@ jobs: // Update the initial comment const successMessage = [ - 'āœ… Deployment Successful for PR ' + prNumber, + 'šŸš€ Rails App Deployed to Control Plane for Commit ' + commitSha.substring(0, 7), '', - 'šŸš€ Rails App: [' + railsUrl + '](' + railsUrl + ')', + '🌐 Rails App: [' + railsUrl + '](' + railsUrl + ')', '', '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); @@ -241,7 +211,7 @@ jobs: const failureMessage = [ 'āŒ Deployment failed for PR ' + prNumber, '', - 'Commit: ' + context.sha.substring(0, 7), + 'Commit: ' + commitSha.substring(0, 7), '', '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); From e431bdfddd272a65abe1f0f0408073a5ed62e601 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 15:42:39 -1000 Subject: [PATCH 44/59] fixes --- .github/workflows/deploy-to-control-plane.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index ed4a75ed..0c64e309 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -92,7 +92,11 @@ jobs: script: | const success = '${{ steps.delete.outcome }}' === 'success'; const message = success - ? 'āœ… Review app successfully deleted' + ? [ + 'āœ… Review app successfully deleted', + '', + '⚔ [Control Plane Console](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/workload)' + ].join('\n') : 'āŒ Review app deletion failed'; await github.rest.issues.updateComment({ @@ -154,7 +158,9 @@ jobs: if: steps.determine_action.outputs.action == 'deploy' uses: ./.github/actions/build-docker-image with: - github_token: ${{ secrets.GITHUB_TOKEN }} + app_name: ${{ env.APP_NAME }} + org: ${{ env.CPLN_ORG }} + commit: ${{ github.event.comment.body && steps.getRef.outputs.PR_SHA || github.sha }} - name: Deploy to Control Plane if: steps.determine_action.outputs.action == 'deploy' @@ -205,6 +211,8 @@ jobs: '', '🌐 Rails App: [' + railsUrl + '](' + railsUrl + ')', '', + '⚔ [Control Plane Console for Review App](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/workload)', + '', '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); From 895986c51809d009a4020064fc55d4d90f107e31 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 15:48:22 -1000 Subject: [PATCH 45/59] fixes --- .github/workflows/deploy-to-control-plane.yml | 8 +++----- .../workflows/nightly-remove-stale-review-apps.yml | 11 ++++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 0c64e309..f4f09b52 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -79,11 +79,9 @@ jobs: - name: Delete App if: steps.determine_action.outputs.action == 'delete' id: delete - uses: ./.github/actions/delete-control-plane-app - continue-on-error: true - with: - app_name: ${{ env.APP_NAME }} - org: ${{ env.CPLN_ORG }} + run: | + echo "šŸ—‘ļø Deleting review app: $APP_NAME" + ${{ github.workspace }}/.github/actions/deploy-to-control-plane/scripts/delete-app.sh - name: Update Delete Status if: steps.determine_action.outputs.action == 'delete' diff --git a/.github/workflows/nightly-remove-stale-review-apps.yml b/.github/workflows/nightly-remove-stale-review-apps.yml index 234fe838..c5f0376a 100644 --- a/.github/workflows/nightly-remove-stale-review-apps.yml +++ b/.github/workflows/nightly-remove-stale-review-apps.yml @@ -45,18 +45,15 @@ jobs: return stalePRs; - name: Delete Stale Review Apps - uses: ./.github/actions/delete-control-plane-app if: ${{ steps.stale_prs.outputs.result != '[]' }} - env: - STALE_PRS: ${{ steps.stale_prs.outputs.result }} run: | - for pr in $(echo "$STALE_PRS" | jq -r '.[]'); do + for pr in $(echo "${{ steps.stale_prs.outputs.result }}" | jq -r '.[]'); do APP_NAME="qa-react-webpack-rails-tutorial-pr-$pr" echo "šŸ—‘ļø Deleting stale review app for PR #$pr: $APP_NAME" - ./.github/actions/delete-control-plane-app/action.yml \ - --app_name "$APP_NAME" \ - --org "$CPLN_ORG" + ${{ github.workspace }}/.github/actions/deploy-to-control-plane/scripts/delete-app.sh done + env: + APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ steps.stale_prs.outputs.result }} - name: Run cleanup-images script run: | From 3fe506ea9b5ddeaaeaaa4687c6549464f9ed0597 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 16:13:24 -1000 Subject: [PATCH 46/59] fixes --- .github/actions/build-docker-image/action.yml | 13 ++--- .github/workflows/deploy-to-control-plane.yml | 49 ++++++++----------- 2 files changed, 24 insertions(+), 38 deletions(-) diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml index f9b2dea0..22d46aeb 100644 --- a/.github/actions/build-docker-image/action.yml +++ b/.github/actions/build-docker-image/action.yml @@ -19,18 +19,11 @@ runs: id: build shell: bash run: | - # Redirect build output to a log file to keep Actions log clean - LOG_FILE=$(mktemp) - echo "šŸ—ļø Building Docker image for commit ${{ inputs.commit }}... (detailed logs will be shown at the end if there's an error)" + echo "šŸ—ļø Building Docker image for commit ${{ inputs.commit }}..." - if cpflow build-image -a ${{ inputs.app_name }} --commit=${{ inputs.commit }} --org=${{ inputs.org }} > "$LOG_FILE" 2>&1; then + if cpflow build-image -a ${{ inputs.app_name }} --commit=${{ inputs.commit }} --org=${{ inputs.org }}; then echo "āœ… Docker image build successful for commit ${{ inputs.commit }}" else - BUILD_EXIT_CODE=$? echo "āŒ Docker image build failed for commit ${{ inputs.commit }}" - echo "==== Build Logs ====" - cat "$LOG_FILE" - rm -f "$LOG_FILE" - exit $BUILD_EXIT_CODE + exit 1 fi - rm -f "$LOG_FILE" diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index f4f09b52..05728729 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -39,8 +39,10 @@ jobs: if: github.event_name == 'issue_comment' id: getRef run: | - echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT - echo "PR_SHA=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefOid | jq -r '.headRefOid')" >> $GITHUB_OUTPUT + # 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 }} @@ -56,7 +58,10 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - ref: ${{ steps.getRef.outputs.PR_REF || github.ref }} + # For PR events: use the head SHA + # For PR comments: use the PR head SHA + # For other events: use the push SHA + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }} - name: Setup Environment uses: ./.github/actions/setup-environment @@ -158,7 +163,8 @@ jobs: with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} - commit: ${{ github.event.comment.body && steps.getRef.outputs.PR_SHA || github.sha }} + # Use the same commit resolution as checkout + commit: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }} - name: Deploy to Control Plane if: steps.determine_action.outputs.action == 'deploy' @@ -181,7 +187,6 @@ jobs: const workflowUrl = result.workflowUrl; const railsUrl = '${{ steps.deploy.outputs.rails_url }}'; const prNumber = process.env.PR_NUMBER; - const commitSha = '${{ github.event.comment.body && steps.getRef.outputs.PR_SHA || github.sha }}'; // Update deployment status const deploymentStatus = { @@ -196,40 +201,28 @@ jobs: deploymentStatus.environment_url = railsUrl; } - try { - await github.rest.repos.createDeploymentStatus(deploymentStatus); - } catch (error) { - console.error('Failed to update deployment status:', error); - throw error; - } + await github.rest.repos.createDeploymentStatus(deploymentStatus); // Update the initial comment const successMessage = [ - 'šŸš€ Rails App Deployed to Control Plane for Commit ' + commitSha.substring(0, 7), + 'āœ… Deployment successful for PR #' + prNumber, '', - '🌐 Rails App: [' + railsUrl + '](' + railsUrl + ')', + 'šŸš€ [Deployed Review App](' + railsUrl + ')', '', - '⚔ [Control Plane Console for Review App](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/workload)', + '⚔ [Control Plane Console](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/workload)', '', '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); const failureMessage = [ - 'āŒ Deployment failed for PR ' + prNumber, - '', - 'Commit: ' + commitSha.substring(0, 7), + 'āŒ Deployment failed for PR #' + prNumber, '', '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); - try { - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: commentId, - body: isSuccess ? successMessage : failureMessage - }); - } catch (error) { - console.error('Failed to update comment:', error); - throw error; - } + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: isSuccess ? successMessage : failureMessage + }); From 585c02d5baeb3db678c772b822893add475bc64c Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 16:24:30 -1000 Subject: [PATCH 47/59] fixes --- .github/actions/build-docker-image/action.yml | 9 ++++-- .../deploy-to-control-plane/action.yml | 32 ++++++++++++++++--- .../deploy-to-control-plane/scripts/deploy.sh | 8 ----- .github/workflows/deploy-to-control-plane.yml | 10 ++++-- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml index 22d46aeb..ba5d7445 100644 --- a/.github/actions/build-docker-image/action.yml +++ b/.github/actions/build-docker-image/action.yml @@ -11,6 +11,9 @@ inputs: commit: description: 'Commit SHA to tag the image with' required: true + PR_NUMBER: + description: 'PR number' + required: true runs: using: "composite" @@ -19,11 +22,11 @@ runs: id: build shell: bash run: | - echo "šŸ—ļø Building Docker image for commit ${{ inputs.commit }}..." + 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 - echo "āœ… Docker image build successful for commit ${{ inputs.commit }}" + echo "āœ… Docker image build successful for PR #$PR_NUMBER (commit ${{ inputs.commit }})" else - echo "āŒ Docker image build failed for commit ${{ inputs.commit }}" + echo "āŒ Docker image build failed for PR #$PR_NUMBER (commit ${{ inputs.commit }})" exit 1 fi diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 769243fe..497c527c 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -1,7 +1,7 @@ # Control Plane GitHub Action name: Deploy to Control Plane -description: 'Deploys the application to Control Plane' +description: 'Deploys an application to Control Plane' inputs: app_name: @@ -36,7 +36,29 @@ runs: - name: Deploy to Control Plane id: deploy shell: bash - run: ${{ github.action_path }}/scripts/deploy.sh - env: - APP_NAME: ${{ inputs.app_name }} - CPLN_ORG: ${{ inputs.org }} + run: | + echo "šŸš€ Deploying app for PR #$PR_NUMBER..." + + # Deploy the application using the already-built image + if ! cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{ inputs.org }}; then + echo "āŒ Deployment failed for PR #$PR_NUMBER" + exit 1 + fi + + # Wait for the deployment to be ready + echo "ā³ Waiting for deployment to be ready..." + if ! cpflow wait-ready -a ${{ inputs.app_name }} --org=${{ inputs.org }} --timeout=300; then + echo "āŒ Deployment did not become ready for PR #$PR_NUMBER" + exit 1 + fi + + # Get the Rails URL + RAILS_URL=$(cpflow get-url -a ${{ inputs.app_name }} --org=${{ inputs.org }}) + if [ -z "$RAILS_URL" ]; then + echo "āŒ Failed to get Rails URL for PR #$PR_NUMBER" + exit 1 + fi + + echo "āœ… Deployment successful for PR #$PR_NUMBER" + echo "🌐 Rails URL: $RAILS_URL" + echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index bda9ab51..4f12a52f 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -14,7 +14,6 @@ set -e # Validate required environment variables : "${APP_NAME:?APP_NAME environment variable is required}" : "${CPLN_ORG:?CPLN_ORG environment variable is required}" -: "${GITHUB_SHA:?GITHUB_SHA environment variable is required}" # Set deployment timeout (15 minutes) TIMEOUT=900 @@ -22,13 +21,6 @@ TIMEOUT=900 TEMP_OUTPUT=$(mktemp) trap 'rm -f "$TEMP_OUTPUT"' EXIT -# Build the Docker image -echo "šŸ—ļø Building Docker image..." -if ! cpflow build-image -a "$APP_NAME" --commit="$GITHUB_SHA" --org="$CPLN_ORG"; then - echo "āŒ Docker image build failed" - exit 1 -fi - # Deploy the application echo "šŸš€ Deploying to Control Plane..." if timeout "$TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 05728729..e22abcf8 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -157,14 +157,20 @@ jobs: workflowUrl: getWorkflowUrl(context.runId) }; + - name: Set commit hash + if: steps.determine_action.outputs.action == 'deploy' + 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: Build Docker Image if: steps.determine_action.outputs.action == 'deploy' uses: ./.github/actions/build-docker-image with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} - # Use the same commit resolution as checkout - commit: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }} + commit: ${{ env.COMMIT_HASH }} + PR_NUMBER: ${{ env.PR_NUMBER }} - name: Deploy to Control Plane if: steps.determine_action.outputs.action == 'deploy' From c46f5951d8cdd1539c468b9c4c038461241224fb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 16:27:54 -1000 Subject: [PATCH 48/59] fixes --- .github/workflows/deploy-to-control-plane.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index e22abcf8..e0b6fa09 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -24,7 +24,7 @@ jobs: if: | github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && - (github.event.comment.body == '/deploy-review-app' || + (github.event.comment.body == '/deploy-review-pp' || github.event.comment.body == '/delete-review-app') && github.event.issue.pull_request) runs-on: ubuntu-latest @@ -211,13 +211,13 @@ jobs: // Update the initial comment const successMessage = [ - 'āœ… Deployment successful for PR #' + prNumber, + 'āœ… Deployment successful for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', '', - 'šŸš€ [Deployed Review App](' + railsUrl + ')', + 'šŸš€ Rails App: [' + railsUrl + '](' + railsUrl + ')', '', '⚔ [Control Plane Console](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/workload)', '', - '[View Workflow Status](' + workflowUrl + ')' + '[View Completed Action Build and Deploy Logs](' + workflowUrl + ')' ].join('\n'); const failureMessage = [ From 65c64d14a233a347e36f54fc813efbd82711eac6 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 17:21:13 -1000 Subject: [PATCH 49/59] fixes --- .../deploy-to-control-plane/action.yml | 29 ++++++++---- .github/workflows/deploy-to-control-plane.yml | 46 ++++++++++++++++++- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 497c527c..17b8377f 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -13,6 +13,10 @@ inputs: github_token: description: 'GitHub token' required: true + wait_timeout: + description: 'Timeout in seconds for waiting for workloads to be ready' + required: false + default: 600 outputs: rails_url: @@ -39,23 +43,28 @@ runs: run: | echo "šŸš€ Deploying app for PR #$PR_NUMBER..." - # Deploy the application using the already-built image - if ! cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{ inputs.org }}; then + # Deploy the application and capture the Rails URL + if ! DEPLOY_OUTPUT=$(cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{ inputs.org }}); then echo "āŒ Deployment failed for PR #$PR_NUMBER" exit 1 fi - # Wait for the deployment to be ready - echo "ā³ Waiting for deployment to be ready..." - if ! cpflow wait-ready -a ${{ inputs.app_name }} --org=${{ inputs.org }} --timeout=300; then - echo "āŒ Deployment did not become ready for PR #$PR_NUMBER" + # Extract Rails URL from deployment output + RAILS_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' | head -n1) + if [ -z "$RAILS_URL" ]; then + echo "āŒ Failed to get Rails URL from deployment output" exit 1 fi - # Get the Rails URL - RAILS_URL=$(cpflow get-url -a ${{ inputs.app_name }} --org=${{ inputs.org }}) - if [ -z "$RAILS_URL" ]; then - echo "āŒ Failed to get Rails URL for PR #$PR_NUMBER" + # 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)..." + if ! timeout $WAIT_TIMEOUT cpflow ps:wait -a ${{ inputs.app_name }}; then + if [ $? -eq 124 ]; then + echo "āŒ Timed out waiting for workloads after ${WAIT_TIMEOUT} seconds" + else + echo "āŒ Workloads did not become ready for PR #$PR_NUMBER" + fi exit 1 fi diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index e0b6fa09..e27ab9de 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -163,6 +163,27 @@ jobs: FULL_COMMIT="${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }}" echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV + - name: Update Status - Building + if: steps.determine_action.outputs.action == 'deploy' + uses: actions/github-script@v7 + with: + script: | + const result = ${{ steps.init-deployment.outputs.result }}; + const commentId = result.commentId; + + const buildingMessage = [ + 'šŸ—ļø Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}', + '', + '[View Build Logs](' + result.workflowUrl + ')' + ].join('\n'); + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: buildingMessage + }); + - name: Build Docker Image if: steps.determine_action.outputs.action == 'deploy' uses: ./.github/actions/build-docker-image @@ -172,6 +193,29 @@ jobs: commit: ${{ env.COMMIT_HASH }} PR_NUMBER: ${{ env.PR_NUMBER }} + - name: Update Status - Deploying + if: steps.determine_action.outputs.action == 'deploy' + uses: actions/github-script@v7 + with: + script: | + const result = ${{ steps.init-deployment.outputs.result }}; + const commentId = result.commentId; + + const deployingMessage = [ + 'šŸš€ Deploying to Control Plane for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}', + '', + 'ā³ Waiting for deployment to be ready...', + '', + '[View Deploy Logs](' + result.workflowUrl + ')' + ].join('\n'); + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: deployingMessage + }); + - name: Deploy to Control Plane if: steps.determine_action.outputs.action == 'deploy' id: deploy @@ -181,7 +225,7 @@ jobs: org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} - - name: Update Status + - name: Update Status - Deployment Complete if: steps.determine_action.outputs.action == 'deploy' uses: actions/github-script@v7 with: From e96ac82bf866d91bdcb606c5efff57470c57c6c2 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 17:33:39 -1000 Subject: [PATCH 50/59] doc changes --- .controlplane/readme.md | 29 +++++++++++++++++++++++++++++ .controlplane/shakacode-team.md | 6 ++++++ .dockerignore | 6 ++++-- .gitignore | 2 +- CHANGELOG.md | 6 ++++++ 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 .controlplane/shakacode-team.md diff --git a/.controlplane/readme.md b/.controlplane/readme.md index cfab19a8..d3fe1850 100644 --- a/.controlplane/readme.md +++ b/.controlplane/readme.md @@ -123,3 +123,32 @@ cpflow build-image -a $APP_NAME --commit ABCD ### `entrypoint.sh` - waits for Postgres and Redis to be available - runs `rails db:prepare` to create/seed or migrate the database + +## CI Automation, Review Apps and Staging + +_Note, some of the URL references are internal for the ShakaCode team._ + + Review Apps (deployment of apps based on a PR) are done via Github Actions. + +The review apps work by creating isolated deployments for each branch through this automated process. When a branch is pushed, the action: + +1. Sets up the necessary environment and tools +2. Creates a unique deployment for that branch if it doesn't exist +3. Builds a Docker image tagged with the branch's commit SHA +4. Deploys this image to Control Plane with its own isolated environment + +This allows teams to: +- Preview changes in a production-like environment +- Test features independently +- Share working versions with stakeholders +- Validate changes before merging to main branches + +The system uses Control Plane's infrastructure to manage these deployments, with each branch getting its own resources as defined in the controlplane.yml configuration. + + +### Workflow for Developing Github Actions for Review Apps + +1. Create a PR with changes to the Github Actions workflow +2. Make edits to file such as `.github/actions/deploy-to-control-plane/action.yml` +3. Run a script like `ga .github && gc -m fixes && gp` to commit and push changes (ga = git add, gc = git commit, gp = git push) +4. Check the Github Actions tab in the PR to see the status of the workflow diff --git a/.controlplane/shakacode-team.md b/.controlplane/shakacode-team.md new file mode 100644 index 00000000..0a6273a0 --- /dev/null +++ b/.controlplane/shakacode-team.md @@ -0,0 +1,6 @@ +# Internal Notes to the Shakacode Team + +## Links + +- [Control Plane Org for Staging and Review Apps](https://console.cpln.io/console/org/shakacode-open-source-examples-staging/-info) +- [Control Plane Org for Deployed App](https://console.cpln.io/console/org/shakacode-open-source-examples/-info) diff --git a/.dockerignore b/.dockerignore index 8ee7cce9..4ddbcbc5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -19,7 +19,10 @@ dump.rdb .DS_Store # Ignore bundle dependencies -vendor/ruby +vendor/bundle + +# Ignore GitHub Actions and workflows +.github/ # RVM gemset .ruby-gemset @@ -45,6 +48,5 @@ yarn-debug.log* ################################################### # Specific to .dockerignore .git/ -.github/ spec/ scripts/ diff --git a/.gitignore b/.gitignore index 42b8d30f..7567a8b7 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ dump.rdb .DS_Store # Ignore bundle dependencies -vendor/ruby +vendor/bundle # RVM gemset .ruby-gemset diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ed23da7..75972ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. See: [merged pull requests](https://github.com/shakacode/react-webpack-rails-tutorial/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Amerged). + +## 2025-01-22 +Improvements to control-plane-flow implementation. + + + ## [2.1.0] - 2016-03-06 ### Updated From 2be9c2f66b78be5d41c44dbda7e5bbea32d65d7c Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 17:34:02 -1000 Subject: [PATCH 51/59] Changes made: Fixed the workflow URL to include the job ID by using context.job.id Improved the deployment timeout handling: Wrapped ps:wait in bash -c to ensure proper signal handling Added more detailed error output including the deployment output Fixed variable expansion for WAIT_TIMEOUT Added exit code to error message for better debugging Added deployment output to error messages to help diagnose issues The workflow URL will now correctly point to the specific job, and we should get better error messages if the deployment fails or times out. --- .../actions/deploy-to-control-plane/action.yml | 15 +++++++++++---- .github/workflows/deploy-to-control-plane.yml | 9 +++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 17b8377f..b7892013 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -53,18 +53,25 @@ runs: RAILS_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' | head -n1) if [ -z "$RAILS_URL" ]; then echo "āŒ Failed to get Rails URL from deployment output" + echo "Deployment output:" + echo "$DEPLOY_OUTPUT" exit 1 fi # Wait for all workloads to be ready - WAIT_TIMEOUT=${WAIT_TIMEOUT:-${inputs.wait_timeout}} + WAIT_TIMEOUT=${WAIT_TIMEOUT:-${{ inputs.wait_timeout }}} echo "ā³ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)..." - if ! timeout $WAIT_TIMEOUT cpflow ps:wait -a ${{ inputs.app_name }}; then - if [ $? -eq 124 ]; then + + # Use timeout command with ps:wait + if ! timeout $WAIT_TIMEOUT bash -c "cpflow ps:wait -a ${{ inputs.app_name }}"; 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" + echo "āŒ Workloads did not become ready for PR #$PR_NUMBER (exit code: $TIMEOUT_EXIT)" fi + echo "Last deployment output:" + echo "$DEPLOY_OUTPUT" exit 1 fi diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index e27ab9de..6bf31f65 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -24,7 +24,7 @@ jobs: if: | github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && - (github.event.comment.body == '/deploy-review-pp' || + (github.event.comment.body == '/deploy-review-app' || github.event.comment.body == '/delete-review-app') && github.event.issue.pull_request) runs-on: ubuntu-latest @@ -116,10 +116,11 @@ jobs: uses: actions/github-script@v7 with: script: | - const prNumber = process.env.PR_NUMBER; - const getWorkflowUrl = (runId) => - `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; + function getWorkflowUrl(runId) { + return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${context.job.id}`; + } + const prNumber = process.env.PR_NUMBER; const getJobUrl = (runId, jobId, prNumber) => `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}?pr=${prNumber}`; From 5f50639bf11d5f8d9b5dd2ab270651483b21c6eb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 18:02:52 -1000 Subject: [PATCH 52/59] fixes --- .../deploy-to-control-plane/action.yml | 28 +++++----- .github/workflows/deploy-to-control-plane.yml | 53 ++++++++++--------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index b7892013..71e46934 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -41,20 +41,22 @@ runs: id: deploy shell: bash run: | - echo "šŸš€ Deploying app for PR #$PR_NUMBER..." + echo "šŸš€ Deploying app for PR #${PR_NUMBER}..." # Deploy the application and capture the Rails URL - if ! DEPLOY_OUTPUT=$(cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{ inputs.org }}); then - echo "āŒ Deployment failed for PR #$PR_NUMBER" + if ! DEPLOY_OUTPUT=$(cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1); then + echo "āŒ Deployment failed for PR #${PR_NUMBER}" + echo "Error output:" + echo "${DEPLOY_OUTPUT}" exit 1 fi # Extract Rails URL from deployment output - RAILS_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' | head -n1) - if [ -z "$RAILS_URL" ]; then + RAILS_URL=$(echo "${DEPLOY_OUTPUT}" | grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' | head -n1) + if [ -z "${RAILS_URL}" ]; then echo "āŒ Failed to get Rails URL from deployment output" echo "Deployment output:" - echo "$DEPLOY_OUTPUT" + echo "${DEPLOY_OUTPUT}" exit 1 fi @@ -63,18 +65,18 @@ runs: echo "ā³ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)..." # Use timeout command with ps:wait - if ! timeout $WAIT_TIMEOUT bash -c "cpflow ps:wait -a ${{ inputs.app_name }}"; then + if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1; then TIMEOUT_EXIT=$? - if [ $TIMEOUT_EXIT -eq 124 ]; then + 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)" + echo "āŒ Workloads did not become ready for PR #${PR_NUMBER} (exit code: ${TIMEOUT_EXIT})" fi echo "Last deployment output:" - echo "$DEPLOY_OUTPUT" + echo "${DEPLOY_OUTPUT}" exit 1 fi - echo "āœ… Deployment successful for PR #$PR_NUMBER" - echo "🌐 Rails URL: $RAILS_URL" - echo "rails_url=$RAILS_URL" >> $GITHUB_OUTPUT + echo "āœ… Deployment successful for PR #${PR_NUMBER}" + echo "🌐 Rails URL: ${RAILS_URL}" + echo "rails_url=${RAILS_URL}" >> $GITHUB_OUTPUT diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 6bf31f65..20f399e3 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -116,46 +116,51 @@ jobs: uses: actions/github-script@v7 with: script: | - function getWorkflowUrl(runId) { - return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${context.job.id}`; + 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}`; } const prNumber = process.env.PR_NUMBER; - const getJobUrl = (runId, jobId, prNumber) => - `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}?pr=${prNumber}`; - // Create deployment - const deployment = await github.rest.repos.createDeployment({ + // Create initial deployment comment + const comment = await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, - ref: context.sha, - environment: 'review-' + prNumber, - auto_merge: false, - required_contexts: [] + issue_number: prNumber, + body: 'ā³ Initializing deployment...' }); - // Get job URL - const jobs = await github.rest.actions.listJobsForWorkflowRun({ + // Create GitHub deployment + const deployment = await github.rest.repos.createDeployment({ owner: context.repo.owner, repo: context.repo.repo, - run_id: context.runId + ref: context.sha, + environment: 'review', + auto_merge: false, + required_contexts: [] }); - const jobId = jobs.data.jobs.find(job => job.name === 'Process-Deployment-Command')?.id; - const jobUrl = getJobUrl(context.runId, jobId, prNumber); - - // Create initial comment - const comment = await github.rest.issues.createComment({ - issue_number: prNumber, - owner: context.repo.owner, - repo: context.repo.repo, - body: 'šŸš€ Deploying to Control Plane...\n\n[View Deployment Progress](' + jobUrl + ')' - }); + const workflowUrl = await getWorkflowUrl(context.runId); return { deploymentId: deployment.data.id, commentId: comment.data.id, - workflowUrl: getWorkflowUrl(context.runId) + workflowUrl }; - name: Set commit hash From e0cf883316cb3c4e26edd11d0ca530848eed1fbb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 18:23:56 -1000 Subject: [PATCH 53/59] fixes --- .github/actions/build-docker-image/action.yml | 8 ++-- .../deploy-to-control-plane/action.yml | 39 +++++++++++-------- .../scripts/get-commit-sha.sh | 8 ++-- .github/workflows/deploy-to-control-plane.yml | 37 +++++++++++------- 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml index ba5d7445..e1b5df73 100644 --- a/.github/actions/build-docker-image/action.yml +++ b/.github/actions/build-docker-image/action.yml @@ -22,11 +22,11 @@ runs: id: build shell: bash run: | - echo "šŸ—ļø Building Docker image for PR #$PR_NUMBER (commit ${{ inputs.commit }})..." + 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 - echo "āœ… Docker image build successful for PR #$PR_NUMBER (commit ${{ inputs.commit }})" + if cpflow build-image -a "${{ inputs.app_name }}" --commit="${{ inputs.commit }}" --org="${{ inputs.org }}"; then + 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 }})" + echo "āŒ Docker image build failed for PR #${PR_NUMBER} (commit ${{ inputs.commit }})" exit 1 fi diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 71e46934..7093ed94 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -19,9 +19,9 @@ inputs: default: 600 outputs: - rails_url: - description: 'URL of the deployed Rails application' - value: ${{ steps.deploy.outputs.rails_url }} + review_app_url: + description: 'URL of the deployed application' + value: ${{ steps.deploy.outputs.review_app_url }} runs: using: "composite" @@ -43,20 +43,24 @@ runs: run: | echo "šŸš€ Deploying app for PR #${PR_NUMBER}..." - # Deploy the application and capture the Rails URL - if ! DEPLOY_OUTPUT=$(cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1); then + # 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:" - echo "${DEPLOY_OUTPUT}" + cat "${TEMP_OUTPUT}" exit 1 fi - # Extract Rails URL from deployment output - RAILS_URL=$(echo "${DEPLOY_OUTPUT}" | grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' | head -n1) - if [ -z "${RAILS_URL}" ]; then - echo "āŒ Failed to get Rails URL from deployment output" + # 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:" - echo "${DEPLOY_OUTPUT}" + cat "${TEMP_OUTPUT}" exit 1 fi @@ -64,19 +68,20 @@ runs: 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 - if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1; then + # 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 "Last deployment output:" - echo "${DEPLOY_OUTPUT}" + echo "Full output:" + cat "${TEMP_OUTPUT}" exit 1 fi echo "āœ… Deployment successful for PR #${PR_NUMBER}" - echo "🌐 Rails URL: ${RAILS_URL}" - echo "rails_url=${RAILS_URL}" >> $GITHUB_OUTPUT + 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 index 12371f96..9dd32cd0 100755 --- a/.github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh +++ b/.github/actions/deploy-to-control-plane/scripts/get-commit-sha.sh @@ -13,13 +13,13 @@ set -e -if [ -n "$PR_NUMBER" ]; then +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 + 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=${PR_SHA}" >> "$GITHUB_OUTPUT" echo "sha_short=${PR_SHA:0:7}" >> "$GITHUB_OUTPUT" echo "Using PR head commit SHA: ${PR_SHA:0:7}" else @@ -28,7 +28,7 @@ else echo "Failed to get current SHA" >&2 exit 1 fi - echo "sha=$CURRENT_SHA" >> "$GITHUB_OUTPUT" + 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 20f399e3..5471fc26 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -231,18 +231,30 @@ jobs: org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} + - name: Update Status - Success + if: steps.determine_action.outputs.action == 'deploy' && success() + uses: actions/github-script@v7 + with: + script: | + const comment = await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: steps.init-deployment.outputs.commentId, + body: `šŸš€ Review App for PR #${process.env.PR_NUMBER}: [\`${process.env.REVIEW_APP_URL}\`](${process.env.REVIEW_APP_URL})` + }); + - name: Update Status - Deployment Complete if: steps.determine_action.outputs.action == 'deploy' uses: actions/github-script@v7 with: script: | + const prNumber = process.env.PR_NUMBER; + const appUrl = process.env.REVIEW_APP_URL; + const workflowUrl = steps.init-deployment.outputs.workflowUrl; const isSuccess = '${{ job.status }}' === 'success'; const result = ${{ steps.init-deployment.outputs.result }}; const deploymentId = result.deploymentId; const commentId = result.commentId; - const workflowUrl = result.workflowUrl; - const railsUrl = '${{ steps.deploy.outputs.rails_url }}'; - const prNumber = process.env.PR_NUMBER; // Update deployment status const deploymentStatus = { @@ -250,24 +262,20 @@ jobs: repo: context.repo.repo, deployment_id: deploymentId, state: isSuccess ? 'success' : 'failure', - description: isSuccess ? 'āœ… Deployment successful' : 'āŒ Deployment failed' + environment_url: isSuccess ? appUrl : undefined, + log_url: workflowUrl, + environment: 'review' }; - if (isSuccess) { - deploymentStatus.environment_url = railsUrl; - } - await github.rest.repos.createDeploymentStatus(deploymentStatus); - // Update the initial comment + // Define messages based on deployment status const successMessage = [ - 'āœ… Deployment successful for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', - '', - 'šŸš€ Rails App: [' + railsUrl + '](' + railsUrl + ')', + 'āœ… Deployment complete for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', '', - '⚔ [Control Plane Console](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/workload)', + 'šŸš€ Review App for PR #' + prNumber + ': [`' + appUrl + '`](' + appUrl + ')', '', - '[View Completed Action Build and Deploy Logs](' + workflowUrl + ')' + 'šŸ“‹ [View Completed Action Build and Deploy Logs](' + workflowUrl + ')' ].join('\n'); const failureMessage = [ @@ -276,6 +284,7 @@ jobs: '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); + // Update the comment with appropriate message await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, From b27783ec5d2e099cb6dfe82e81c541011f18956b Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 18:40:57 -1000 Subject: [PATCH 54/59] added promotion and other fixes --- .../deploy-to-control-plane-staging.yml | 2 +- .github/workflows/deploy-to-control-plane.yml | 55 ++++++------------ .../promote-staging-to-production.yml | 56 +++++++++++++++++++ 3 files changed, 73 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/promote-staging-to-production.yml diff --git a/.github/workflows/deploy-to-control-plane-staging.yml b/.github/workflows/deploy-to-control-plane-staging.yml index 2a6a5e80..095c635a 100644 --- a/.github/workflows/deploy-to-control-plane-staging.yml +++ b/.github/workflows/deploy-to-control-plane-staging.yml @@ -1,6 +1,6 @@ # Control Plane GitHub Action -name: Deploy-To-Control-Plane-Staging +name: Deploy Main Branch to Control Plane Staging # Controls when the workflow will run on: diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 5471fc26..b0f4f74b 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -1,4 +1,4 @@ -name: Deploy to Control Plane +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) }} @@ -116,32 +116,11 @@ jobs: uses: actions/github-script@v7 with: script: | - 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}`; - } - - const prNumber = process.env.PR_NUMBER; - // Create initial deployment comment const comment = await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: prNumber, + issue_number: process.env.PR_NUMBER, body: 'ā³ Initializing deployment...' }); @@ -155,14 +134,15 @@ jobs: required_contexts: [] }); - const workflowUrl = await getWorkflowUrl(context.runId); - return { deploymentId: deployment.data.id, - commentId: comment.data.id, - workflowUrl + commentId: comment.data.id }; + - name: Set comment ID + if: steps.determine_action.outputs.action == 'deploy' + run: echo "COMMENT_ID=${{ fromJSON(steps.init-deployment.outputs.result).commentId }}" >> $GITHUB_ENV + - name: Set commit hash if: steps.determine_action.outputs.action == 'deploy' run: | @@ -180,7 +160,7 @@ jobs: const buildingMessage = [ 'šŸ—ļø Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}', '', - '[View Build Logs](' + result.workflowUrl + ')' + '[View Build Logs](' + `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job.id}` + ')' ].join('\n'); await github.rest.issues.updateComment({ @@ -212,7 +192,7 @@ jobs: '', 'ā³ Waiting for deployment to be ready...', '', - '[View Deploy Logs](' + result.workflowUrl + ')' + '[View Deploy Logs](' + `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job.id}` + ')' ].join('\n'); await github.rest.issues.updateComment({ @@ -236,10 +216,10 @@ jobs: uses: actions/github-script@v7 with: script: | - const comment = await github.rest.issues.updateComment({ + await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, - comment_id: steps.init-deployment.outputs.commentId, + comment_id: process.env.COMMENT_ID, body: `šŸš€ Review App for PR #${process.env.PR_NUMBER}: [\`${process.env.REVIEW_APP_URL}\`](${process.env.REVIEW_APP_URL})` }); @@ -250,17 +230,14 @@ jobs: script: | const prNumber = process.env.PR_NUMBER; const appUrl = process.env.REVIEW_APP_URL; - const workflowUrl = steps.init-deployment.outputs.workflowUrl; + const workflowUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job.id}`; const isSuccess = '${{ job.status }}' === 'success'; - const result = ${{ steps.init-deployment.outputs.result }}; - const deploymentId = result.deploymentId; - const commentId = result.commentId; - // Update deployment status + // Create GitHub deployment status const deploymentStatus = { owner: context.repo.owner, repo: context.repo.repo, - deployment_id: deploymentId, + deployment_id: ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }}, state: isSuccess ? 'success' : 'failure', environment_url: isSuccess ? appUrl : undefined, log_url: workflowUrl, @@ -284,10 +261,10 @@ jobs: '[View Workflow Status](' + workflowUrl + ')' ].join('\n'); - // Update the comment with appropriate message + // Update the existing comment await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, - comment_id: commentId, + comment_id: process.env.COMMENT_ID, body: isSuccess ? successMessage : failureMessage }); diff --git a/.github/workflows/promote-staging-to-production.yml b/.github/workflows/promote-staging-to-production.yml new file mode 100644 index 00000000..04148067 --- /dev/null +++ b/.github/workflows/promote-staging-to-production.yml @@ -0,0 +1,56 @@ +name: Promote Staging to Production + +on: + workflow_dispatch: + inputs: + confirm_promotion: + description: 'Type "promote" to confirm promotion of staging to production' + required: true + type: string + +jobs: + promote-to-production: + runs-on: ubuntu-latest + if: github.event.inputs.confirm_promotion == 'promote' + + env: + APP_NAME: react-webpack-rails-tutorial + CPLN_ORG: ${{ secrets.CPLN_ORG }} + UPSTREAM_TOKEN: ${{ secrets.STAGING_TOKEN }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup-environment + env: + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} + + - name: Promote Staging to Production + id: promote + run: | + echo "šŸš€ Starting promotion from staging to production..." + + if ! cpflow promote-app-from-upstream -a "${APP_NAME}" -t "${UPSTREAM_TOKEN}" --org "${CPLN_ORG}"; then + echo "āŒ Failed to promote staging to production" + exit 1 + fi + + echo "āœ… Successfully promoted staging to production" + + - name: Create GitHub Release + if: success() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Get the current date in YYYY-MM-DD format + RELEASE_DATE=$(date '+%Y-%m-%d') + + # Create a release tag + RELEASE_TAG="production-${RELEASE_DATE}" + + # Create GitHub release + gh release create "${RELEASE_TAG}" \ + --title "Production Release ${RELEASE_DATE}" \ + --notes "šŸš€ Production deployment on ${RELEASE_DATE}" From 66a41145c26339fc936314add3e3a7f5fef08284 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 18:54:28 -1000 Subject: [PATCH 55/59] fixes --- .github/workflows/deploy-to-control-plane.yml | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index b0f4f74b..6b33e0ce 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -116,6 +116,25 @@ jobs: uses: actions/github-script@v7 with: script: | + 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, @@ -133,15 +152,20 @@ jobs: auto_merge: false, required_contexts: [] }); + + const workflowUrl = await getWorkflowUrl(context.runId); return { deploymentId: deployment.data.id, - commentId: comment.data.id + commentId: comment.data.id, + workflowUrl }; - - name: Set comment ID + - name: Set comment ID and workflow URL if: steps.determine_action.outputs.action == 'deploy' - run: echo "COMMENT_ID=${{ fromJSON(steps.init-deployment.outputs.result).commentId }}" >> $GITHUB_ENV + 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 if: steps.determine_action.outputs.action == 'deploy' @@ -154,19 +178,16 @@ jobs: uses: actions/github-script@v7 with: script: | - const result = ${{ steps.init-deployment.outputs.result }}; - const commentId = result.commentId; - const buildingMessage = [ 'šŸ—ļø Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}', '', - '[View Build Logs](' + `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job.id}` + ')' + '[View Build Logs](' + process.env.WORKFLOW_URL + ')' ].join('\n'); await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, - comment_id: commentId, + comment_id: process.env.COMMENT_ID, body: buildingMessage }); @@ -184,21 +205,18 @@ jobs: uses: actions/github-script@v7 with: script: | - const result = ${{ steps.init-deployment.outputs.result }}; - const commentId = result.commentId; - const deployingMessage = [ - 'šŸš€ Deploying to Control Plane for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}', + 'šŸš€ Deploying to Control Plane...', '', 'ā³ Waiting for deployment to be ready...', '', - '[View Deploy Logs](' + `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job.id}` + ')' + '[View Deploy Logs](' + process.env.WORKFLOW_URL + ')' ].join('\n'); await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, - comment_id: commentId, + comment_id: process.env.COMMENT_ID, body: deployingMessage }); @@ -230,7 +248,7 @@ jobs: script: | const prNumber = process.env.PR_NUMBER; const appUrl = process.env.REVIEW_APP_URL; - const workflowUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/job/${context.job.id}`; + const workflowUrl = process.env.WORKFLOW_URL; const isSuccess = '${{ job.status }}' === 'success'; // Create GitHub deployment status From 3426aca0422fac591df82a9b232db6d04277d8de Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 21:59:13 -1000 Subject: [PATCH 56/59] fix-for-delete --- .github/workflows/delete-review-app.yml | 85 +++++++++++++++++ .github/workflows/deploy-to-control-plane.yml | 94 ++----------------- .github/workflows/help-command.yml | 52 ++++++++++ 3 files changed, 145 insertions(+), 86 deletions(-) create mode 100644 .github/workflows/delete-review-app.yml create mode 100644 .github/workflows/help-command.yml diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml new file mode 100644 index 00000000..7c8b5b73 --- /dev/null +++ b/.github/workflows/delete-review-app.yml @@ -0,0 +1,85 @@ +name: Delete Review App + +on: + issue_comment: + types: [created] + +permissions: + contents: read + deployments: write + pull-requests: write + issues: write + +env: + CPLN_ORG: ${{ secrets.CPLN_ORG_STAGING }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} + +jobs: + Process-Delete-Command: + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.body == '/delete-review-app' + 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: Setup Environment + uses: ./.github/actions/setup-environment + + - name: Create Initial Delete Comment + id: init-delete + uses: actions/github-script@v7 + with: + script: | + 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...' + }); + return { commentId: comment.data.id }; + + - name: Delete Review App + uses: ./.github/actions/delete-control-plane-app + env: + APP_NAME: ${{ env.APP_NAME }} + CPLN_ORG: ${{ secrets.CPLN_ORG }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} + + - name: Update Delete Status + if: always() + uses: actions/github-script@v7 + with: + script: | + const success = '${{ job.status }}' === 'success'; + const prNumber = process.env.PR_NUMBER; + const cpConsoleUrl = `https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME}`; + + const message = success + ? 'āœ… Review app for PR #' + prNumber + ' was successfully deleted' + : [ + 'āŒ Review app for PR #' + prNumber + ' failed to be deleted', + '', + '[View in Control Plane Console](' + cpConsoleUrl + ')' + ].join('\n'); + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ fromJSON(steps.init-delete.outputs.result).commentId }}, + body: message + }); diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 6b33e0ce..0ce9f7c3 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -22,11 +22,10 @@ env: jobs: Process-Deployment-Command: if: | - github.event_name == 'pull_request' || + (github.event_name == 'pull_request') || (github.event_name == 'issue_comment' && - (github.event.comment.body == '/deploy-review-app' || - github.event.comment.body == '/delete-review-app') && - github.event.issue.pull_request) + github.event.issue.pull_request && + github.event.comment.body == '/deploy') runs-on: ubuntu-latest permissions: contents: read @@ -46,72 +45,15 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Determine Action - id: determine_action - run: | - if [[ "${{ github.event.comment.body }}" == "/delete-review-app" ]]; then - echo "action=delete" >> $GITHUB_OUTPUT - else - echo "action=deploy" >> $GITHUB_OUTPUT - fi - - uses: actions/checkout@v4 with: fetch-depth: 0 - # For PR events: use the head SHA - # For PR comments: use the PR head SHA - # For other events: use the push SHA - ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }} + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || steps.getRef.outputs.PR_REF || github.ref }} - name: Setup Environment uses: ./.github/actions/setup-environment - # Delete App Steps - - name: Create Initial Delete Comment - if: steps.determine_action.outputs.action == 'delete' - uses: actions/github-script@v7 - id: init-delete - with: - script: | - 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...' - }); - return { commentId: comment.data.id }; - - - name: Delete App - if: steps.determine_action.outputs.action == 'delete' - id: delete - run: | - echo "šŸ—‘ļø Deleting review app: $APP_NAME" - ${{ github.workspace }}/.github/actions/deploy-to-control-plane/scripts/delete-app.sh - - - name: Update Delete Status - if: steps.determine_action.outputs.action == 'delete' - uses: actions/github-script@v7 - with: - script: | - const success = '${{ steps.delete.outcome }}' === 'success'; - const message = success - ? [ - 'āœ… Review app successfully deleted', - '', - '⚔ [Control Plane Console](https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/workload)' - ].join('\n') - : 'āŒ Review app deletion failed'; - - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: ${{ fromJSON(steps.init-delete.outputs.result).commentId }}, - body: message - }); - - # Deploy Steps - name: Initialize Deployment - if: steps.determine_action.outputs.action == 'deploy' id: init-deployment uses: actions/github-script@v7 with: @@ -162,19 +104,16 @@ jobs: }; - name: Set comment ID and workflow URL - if: steps.determine_action.outputs.action == 'deploy' 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 - if: steps.determine_action.outputs.action == 'deploy' run: | FULL_COMMIT="${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }}" echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV - name: Update Status - Building - if: steps.determine_action.outputs.action == 'deploy' uses: actions/github-script@v7 with: script: | @@ -192,7 +131,6 @@ jobs: }); - name: Build Docker Image - if: steps.determine_action.outputs.action == 'deploy' uses: ./.github/actions/build-docker-image with: app_name: ${{ env.APP_NAME }} @@ -201,7 +139,6 @@ jobs: PR_NUMBER: ${{ env.PR_NUMBER }} - name: Update Status - Deploying - if: steps.determine_action.outputs.action == 'deploy' uses: actions/github-script@v7 with: script: | @@ -221,28 +158,13 @@ jobs: }); - name: Deploy to Control Plane - if: steps.determine_action.outputs.action == 'deploy' - id: deploy uses: ./.github/actions/deploy-to-control-plane with: app_name: ${{ env.APP_NAME }} org: ${{ env.CPLN_ORG }} github_token: ${{ secrets.GITHUB_TOKEN }} - - name: Update Status - Success - if: steps.determine_action.outputs.action == 'deploy' && success() - uses: actions/github-script@v7 - with: - script: | - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: process.env.COMMENT_ID, - body: `šŸš€ Review App for PR #${process.env.PR_NUMBER}: [\`${process.env.REVIEW_APP_URL}\`](${process.env.REVIEW_APP_URL})` - }); - - name: Update Status - Deployment Complete - if: steps.determine_action.outputs.action == 'deploy' uses: actions/github-script@v7 with: script: | @@ -268,15 +190,15 @@ jobs: const successMessage = [ 'āœ… Deployment complete for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', '', - 'šŸš€ Review App for PR #' + prNumber + ': [`' + appUrl + '`](' + appUrl + ')', + 'šŸš€ [Review App for PR #' + prNumber + '](' + appUrl + ')', '', 'šŸ“‹ [View Completed Action Build and Deploy Logs](' + workflowUrl + ')' ].join('\n'); const failureMessage = [ - 'āŒ Deployment failed for PR #' + prNumber, + 'āŒ Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', '', - '[View Workflow Status](' + workflowUrl + ')' + 'šŸ“‹ [View Deployment Logs with Errors](' + workflowUrl + ')' ].join('\n'); // Update the existing comment @@ -285,4 +207,4 @@ jobs: repo: context.repo.repo, comment_id: process.env.COMMENT_ID, body: isSuccess ? successMessage : failureMessage - }); + }); \ No newline at end of file diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml new file mode 100644 index 00000000..6e77bf69 --- /dev/null +++ b/.github/workflows/help-command.yml @@ -0,0 +1,52 @@ +name: Show Help for Commands + +on: + issue_comment: + types: [created] + +permissions: + issues: write + pull-requests: write + +jobs: + 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`', + '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`', + '', + '### `/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 + }); From 92ad3a7e115a9ef3b5a1d1f0947db41bb4e7409f Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 22:14:17 -1000 Subject: [PATCH 57/59] fix-for-delete --- .github/workflows/delete-review-app.yml | 35 ++++++++++++- .github/workflows/deploy-to-control-plane.yml | 50 +++++++++++++++++-- .github/workflows/help-command.yml | 13 +++++ 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index 7c8b5b73..37e7a447 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -23,6 +23,21 @@ jobs: runs-on: ubuntu-latest steps: + - name: Debug Trigger Conditions + env: + EVENT_NAME: ${{ github.event_name }} + IS_PR: ${{ github.event.issue.pull_request != '' }} + COMMENT: ${{ github.event.comment.body }} + PR_NUMBER: ${{ github.event.issue.number }} + run: | + echo "Debug information for delete-review-app command:" + echo "Event name: $EVENT_NAME" + echo "Is PR: $IS_PR" + echo "Comment body: $COMMENT" + echo "PR number: $PR_NUMBER" + echo "Raw event payload:" + echo '${{ toJSON(github.event) }}' + - name: Get PR number id: pr uses: actions/github-script@v7 @@ -37,6 +52,20 @@ jobs: - uses: actions/checkout@v4 + - name: Validate Required Secrets + run: | + missing_secrets=() + for secret in "CPLN_TOKEN_STAGING" "CPLN_ORG_STAGING"; 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 @@ -55,9 +84,11 @@ jobs: - name: Delete Review App uses: ./.github/actions/delete-control-plane-app + with: + app_name: ${{ env.APP_NAME }} + org: ${{ env.CPLN_ORG }} + github_token: ${{ secrets.GITHUB_TOKEN }} env: - APP_NAME: ${{ env.APP_NAME }} - CPLN_ORG: ${{ secrets.CPLN_ORG }} CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} - name: Update Delete Status diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 0ce9f7c3..56f6f931 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -50,14 +50,42 @@ jobs: 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_STAGING" "CPLN_ORG_STAGING"; 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({ @@ -117,10 +145,14 @@ jobs: 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 + ')' + 'šŸ“‹ [View Build Logs](' + process.env.WORKFLOW_URL + ')', + '', + getConsoleLink(process.env.PR_NUMBER) ].join('\n'); await github.rest.issues.updateComment({ @@ -142,12 +174,16 @@ jobs: 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 + ')' + 'šŸ“‹ [View Deploy Logs](' + process.env.WORKFLOW_URL + ')', + '', + getConsoleLink(process.env.PR_NUMBER) ].join('\n'); await github.rest.issues.updateComment({ @@ -168,6 +204,8 @@ jobs: 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; @@ -192,13 +230,17 @@ jobs: '', 'šŸš€ [Review App for PR #' + prNumber + '](' + appUrl + ')', '', - 'šŸ“‹ [View Completed Action Build and Deploy Logs](' + workflowUrl + ')' + 'šŸ“‹ [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 + ')' + 'šŸ“‹ [View Deployment Logs with Errors](' + workflowUrl + ')', + '', + getConsoleLink(prNumber) ].join('\n'); // Update the existing comment diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 6e77bf69..28582d4c 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -17,6 +17,19 @@ jobs: runs-on: ubuntu-latest steps: + - name: Debug Trigger Conditions + env: + EVENT_NAME: ${{ github.event_name }} + IS_PR: ${{ github.event.issue.pull_request != '' }} + COMMENT: ${{ github.event.comment.body }} + run: | + echo "Debug information for help command:" + echo "Event name: $EVENT_NAME" + echo "Is PR: $IS_PR" + echo "Comment body: $COMMENT" + echo "Raw event payload:" + echo '${{ toJSON(github.event) }}' + - name: Show Available Commands uses: actions/github-script@v7 with: From 7d75738cc7267c3e04b20ee17c61854b7b561669 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 22:24:03 -1000 Subject: [PATCH 58/59] fix-for-delete --- .github/workflows/delete-review-app.yml | 51 +++--- .github/workflows/deploy-to-control-plane.yml | 157 +++++++++++++++++- .github/workflows/help-command.yml | 23 ++- 3 files changed, 190 insertions(+), 41 deletions(-) diff --git a/.github/workflows/delete-review-app.yml b/.github/workflows/delete-review-app.yml index 37e7a447..074b7c7e 100644 --- a/.github/workflows/delete-review-app.yml +++ b/.github/workflows/delete-review-app.yml @@ -11,58 +11,51 @@ permissions: issues: write env: - CPLN_ORG: ${{ secrets.CPLN_ORG_STAGING }} - CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} + CPLN_ORG: ${{ secrets.CPLN_ORG }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} + APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.issue.number }} + PR_NUMBER: ${{ github.event.issue.number }} jobs: - Process-Delete-Command: - if: | - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/delete-review-app' + debug-trigger: + if: always() runs-on: ubuntu-latest - steps: - name: Debug Trigger Conditions env: EVENT_NAME: ${{ github.event_name }} - IS_PR: ${{ github.event.issue.pull_request != '' }} + IS_PR: ${{ toJSON(github.event.issue.pull_request) }} COMMENT: ${{ github.event.comment.body }} - PR_NUMBER: ${{ github.event.issue.number }} run: | echo "Debug information for delete-review-app command:" echo "Event name: $EVENT_NAME" - echo "Is PR: $IS_PR" + echo "Is PR (raw): $IS_PR" echo "Comment body: $COMMENT" - echo "PR number: $PR_NUMBER" echo "Raw event payload:" echo '${{ toJSON(github.event) }}' - - 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 + Process-Delete-Command: + needs: debug-trigger + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.body == '/delete-review-app' + runs-on: ubuntu-latest + steps: - uses: actions/checkout@v4 - name: Validate Required Secrets run: | missing_secrets=() - for secret in "CPLN_TOKEN_STAGING" "CPLN_ORG_STAGING"; do + 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[*]}" + echo " Required secrets are not set: ${missing_secrets[*]}" exit 1 fi @@ -78,7 +71,7 @@ jobs: issue_number: process.env.PR_NUMBER, owner: context.repo.owner, repo: context.repo.repo, - body: 'šŸ—‘ļø Starting app deletion...' + body: ' Starting app deletion...' }); return { commentId: comment.data.id }; @@ -101,11 +94,11 @@ jobs: const cpConsoleUrl = `https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME}`; const message = success - ? 'āœ… Review app for PR #' + prNumber + ' was successfully deleted' + ? ' Review app for PR #' + prNumber + ' was successfully deleted' : [ - 'āŒ Review app for PR #' + prNumber + ' failed to be deleted', + ' Review app for PR #' + prNumber + ' failed to be deleted', '', - '[View in Control Plane Console](' + cpConsoleUrl + ')' + '[Control Plane Console for Review App with PR #' + prNumber + '](' + cpConsoleUrl + ')' ].join('\n'); await github.rest.issues.updateComment({ diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 56f6f931..1077ff46 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -15,8 +15,8 @@ concurrency: env: APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number }} - CPLN_ORG: ${{ secrets.CPLN_ORG_STAGING }} - CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }} + CPLN_ORG: ${{ secrets.CPLN_ORG }} + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} jobs: @@ -53,7 +53,7 @@ jobs: - name: Validate Required Secrets run: | missing_secrets=() - for secret in "CPLN_TOKEN_STAGING" "CPLN_ORG_STAGING"; do + for secret in "CPLN_TOKEN" "CPLN_ORG"; do if [ -z "${!secret}" ]; then missing_secrets+=("$secret") fi @@ -249,4 +249,155 @@ jobs: repo: context.repo.repo, comment_id: process.env.COMMENT_ID, body: isSuccess ? successMessage : failureMessage + }); + + debug-help: + if: always() + runs-on: ubuntu-latest + steps: + - name: Debug Trigger Conditions + env: + EVENT_NAME: ${{ github.event_name }} + IS_PR: ${{ toJSON(github.event.issue.pull_request) }} + COMMENT: ${{ github.event.comment.body }} + run: | + echo "Debug information for help command:" + echo "Event name: $EVENT_NAME" + echo "Is PR (raw): $IS_PR" + echo "Comment body: $COMMENT" + echo "Raw event payload:" + echo '${{ toJSON(github.event) }}' + + show-help: + needs: debug-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`', + '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`', + '', + '### `/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 + }); + + debug-delete: + if: always() + runs-on: ubuntu-latest + steps: + - name: Debug Trigger Conditions + env: + EVENT_NAME: ${{ github.event_name }} + IS_PR: ${{ toJSON(github.event.issue.pull_request) }} + COMMENT: ${{ github.event.comment.body }} + run: | + echo "Debug information for delete-review-app command:" + echo "Event name: $EVENT_NAME" + echo "Is PR (raw): $IS_PR" + echo "Comment body: $COMMENT" + echo "Raw event payload:" + echo '${{ toJSON(github.event) }}' + + Process-Delete-Command: + needs: debug-delete + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.body == '/delete-review-app' + runs-on: ubuntu-latest + + steps: + - 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: Setup Environment + uses: ./.github/actions/setup-environment + + - name: Create Initial Delete Comment + id: init-delete + uses: actions/github-script@v7 + with: + script: | + 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...' + }); + return { commentId: comment.data.id }; + + - name: Delete Review App + uses: ./.github/actions/delete-control-plane-app + with: + app_name: ${{ env.APP_NAME }} + org: ${{ env.CPLN_ORG }} + github_token: ${{ secrets.GITHUB_TOKEN }} + env: + CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }} + + - name: Update Delete Status + if: always() + uses: actions/github-script@v7 + with: + script: | + const success = '${{ job.status }}' === 'success'; + const prNumber = process.env.PR_NUMBER; + const cpConsoleUrl = `https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME}`; + + const message = success + ? 'āœ… Review app for PR #' + prNumber + ' was successfully deleted' + : [ + 'āŒ Review app for PR #' + prNumber + ' failed to be deleted', + '', + 'šŸŽ® [Control Plane Console for Review App with PR #' + prNumber + '](' + cpConsoleUrl + ')' + ].join('\n'); + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ fromJSON(steps.init-delete.outputs.result).commentId }}, + body: message }); \ No newline at end of file diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 28582d4c..10a9e1b5 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -9,33 +9,38 @@ permissions: pull-requests: write jobs: - show-help: - if: | - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.comment.body == '/help' + debug-trigger: + if: always() runs-on: ubuntu-latest - steps: - name: Debug Trigger Conditions env: EVENT_NAME: ${{ github.event_name }} - IS_PR: ${{ github.event.issue.pull_request != '' }} + IS_PR: ${{ toJSON(github.event.issue.pull_request) }} COMMENT: ${{ github.event.comment.body }} run: | echo "Debug information for help command:" echo "Event name: $EVENT_NAME" - echo "Is PR: $IS_PR" + echo "Is PR (raw): $IS_PR" echo "Comment body: $COMMENT" echo "Raw event payload:" echo '${{ toJSON(github.event) }}' + show-help: + needs: debug-trigger + 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', + '## Available Commands', '', '### `/deploy`', 'Deploys your PR branch to a review environment on Control Plane.', From d5b8b7f2c4f4398a70d7a4dc176a29df31ff5c99 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 25 Jan 2025 22:36:11 -1000 Subject: [PATCH 59/59] fix-for-delete --- .../deploy-to-control-plane/action.yml | 8 +++- .../deploy-to-control-plane/scripts/deploy.sh | 18 ++++++--- .github/workflows/deploy-to-control-plane.yml | 39 ++++++++++--------- .github/workflows/help-command.yml | 26 +++++++++++-- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/.github/actions/deploy-to-control-plane/action.yml b/.github/actions/deploy-to-control-plane/action.yml index 7093ed94..1e5c9fa7 100644 --- a/.github/actions/deploy-to-control-plane/action.yml +++ b/.github/actions/deploy-to-control-plane/action.yml @@ -16,7 +16,7 @@ inputs: wait_timeout: description: 'Timeout in seconds for waiting for workloads to be ready' required: false - default: 600 + default: '900' outputs: review_app_url: @@ -66,7 +66,11 @@ runs: # 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)..." + 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 diff --git a/.github/actions/deploy-to-control-plane/scripts/deploy.sh b/.github/actions/deploy-to-control-plane/scripts/deploy.sh index 4f12a52f..9d070b64 100755 --- a/.github/actions/deploy-to-control-plane/scripts/deploy.sh +++ b/.github/actions/deploy-to-control-plane/scripts/deploy.sh @@ -6,6 +6,10 @@ # - APP_NAME: Name of the application to deploy # - CPLN_ORG: Control Plane organization # +# Optional environment variables: +# - WAIT_TIMEOUT: Timeout in seconds for deployment (default: 900) +# Must be a positive integer +# # Outputs: # - rails_url: URL of the deployed Rails application @@ -15,15 +19,19 @@ set -e : "${APP_NAME:?APP_NAME environment variable is required}" : "${CPLN_ORG:?CPLN_ORG environment variable is required}" -# Set deployment timeout (15 minutes) -TIMEOUT=900 +# Set and validate deployment timeout +WAIT_TIMEOUT=${WAIT_TIMEOUT:-900} +if ! [[ "${WAIT_TIMEOUT}" =~ ^[0-9]+$ ]]; then + echo "āŒ Invalid timeout value: ${WAIT_TIMEOUT}" + exit 1 +fi TEMP_OUTPUT=$(mktemp) trap 'rm -f "$TEMP_OUTPUT"' EXIT # Deploy the application -echo "šŸš€ Deploying to Control Plane..." -if timeout "$TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then +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 @@ -35,7 +43,7 @@ if timeout "$TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --o exit 1 fi elif [ $? -eq 124 ]; then - echo "āŒ Deployment timed out after $TIMEOUT seconds" + echo "āŒ Deployment timed out after $WAIT_TIMEOUT seconds" exit 1 else echo "āŒ Deployment to Control Plane failed" diff --git a/.github/workflows/deploy-to-control-plane.yml b/.github/workflows/deploy-to-control-plane.yml index 1077ff46..ad1dbb49 100644 --- a/.github/workflows/deploy-to-control-plane.yml +++ b/.github/workflows/deploy-to-control-plane.yml @@ -60,7 +60,7 @@ jobs: done if [ ${#missing_secrets[@]} -ne 0 ]; then - echo "āŒ Required secrets are not set: ${missing_secrets[*]}" + echo "Required secrets are not set: ${missing_secrets[*]}" exit 1 fi @@ -74,7 +74,7 @@ jobs: script: | core.exportVariable('GET_CONSOLE_LINK', ` function getConsoleLink(prNumber) { - return 'šŸŽ® [Control Plane Console for Review App with PR #' + 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 + ')'; } `); @@ -110,7 +110,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, issue_number: process.env.PR_NUMBER, - body: 'ā³ Initializing deployment...' + body: ' Initializing deployment...' }); // Create GitHub deployment @@ -148,9 +148,9 @@ jobs: eval(process.env.GET_CONSOLE_LINK); 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 ' + '${{ env.COMMIT_HASH }}', '', - 'šŸ“‹ [View Build Logs](' + process.env.WORKFLOW_URL + ')', + ' [View Build Logs](' + process.env.WORKFLOW_URL + ')', '', getConsoleLink(process.env.PR_NUMBER) ].join('\n'); @@ -177,11 +177,11 @@ jobs: eval(process.env.GET_CONSOLE_LINK); const deployingMessage = [ - 'šŸš€ Deploying to Control Plane...', + ' Deploying to Control Plane...', '', - 'ā³ Waiting for deployment to be ready...', + ' Waiting for deployment to be ready...', '', - 'šŸ“‹ [View Deploy Logs](' + process.env.WORKFLOW_URL + ')', + ' [View Deploy Logs](' + process.env.WORKFLOW_URL + ')', '', getConsoleLink(process.env.PR_NUMBER) ].join('\n'); @@ -199,6 +199,7 @@ jobs: app_name: ${{ env.APP_NAME }} 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 @@ -226,19 +227,19 @@ 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.COMMIT_HASH }}', '', - 'šŸš€ [Review App for PR #' + prNumber + '](' + appUrl + ')', + ' [Review App for PR #' + prNumber + '](' + appUrl + ')', '', - 'šŸ“‹ [View Completed Action Build and Deploy Logs](' + workflowUrl + ')', + ' [View Completed Action Build and Deploy Logs](' + workflowUrl + ')', '', getConsoleLink(prNumber) ].join('\n'); const failureMessage = [ - 'āŒ Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', + ' Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}', '', - 'šŸ“‹ [View Deployment Logs with Errors](' + workflowUrl + ')', + ' [View Deployment Logs with Errors](' + workflowUrl + ')', '', getConsoleLink(prNumber) ].join('\n'); @@ -282,7 +283,7 @@ jobs: with: script: | const helpMessage = [ - '## šŸ“š Available Commands', + '## Available Commands', '', '### `/deploy`', 'Deploys your PR branch to a review environment on Control Plane.', @@ -349,7 +350,7 @@ jobs: done if [ ${#missing_secrets[@]} -ne 0 ]; then - echo "āŒ Required secrets are not set: ${missing_secrets[*]}" + echo "Required secrets are not set: ${missing_secrets[*]}" exit 1 fi @@ -365,7 +366,7 @@ jobs: issue_number: process.env.PR_NUMBER, owner: context.repo.owner, repo: context.repo.repo, - body: 'šŸ—‘ļø Starting app deletion...' + body: ' Starting app deletion...' }); return { commentId: comment.data.id }; @@ -388,11 +389,11 @@ jobs: const cpConsoleUrl = `https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME}`; const message = success - ? 'āœ… Review app for PR #' + prNumber + ' was successfully deleted' + ? ' Review app for PR #' + prNumber + ' was successfully deleted' : [ - 'āŒ Review app for PR #' + prNumber + ' failed to be deleted', + ' Review app for PR #' + prNumber + ' failed to be deleted', '', - 'šŸŽ® [Control Plane Console for Review App with PR #' + prNumber + '](' + cpConsoleUrl + ')' + ' [Control Plane Console for Review App with PR #' + prNumber + '](' + cpConsoleUrl + ')' ].join('\n'); await github.rest.issues.updateComment({ diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 10a9e1b5..20a0e828 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -40,7 +40,7 @@ jobs: with: script: | const helpMessage = [ - '## Available Commands', + '## šŸ“š Available Commands', '', '### `/deploy`', 'Deploys your PR branch to a review environment on Control Plane.', @@ -49,17 +49,37 @@ jobs: '- Provides a unique URL to preview your changes', '- Shows build and deployment progress in real-time', '', + '**Required Environment Variables:**', + '- `CPLN_TOKEN`: Control Plane authentication token', + '- `CPLN_ORG`: Control Plane organization name', + '', + '**Optional Configuration:**', + '- `WAIT_TIMEOUT`: Deployment timeout in seconds (default: 900)', + ' - Must be a positive integer', + ' - Can be set in GitHub Actions variables', + ' - Applies to both deployment and workload readiness checks', + '', '### `/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`', '', + '**Required Environment Variables:**', + '- `CPLN_TOKEN`: Control Plane authentication token', + '- `CPLN_ORG`: Control Plane organization name', + '', '### `/help`', - 'Shows this help message explaining available commands.', + 'Shows this help message explaining available commands and configuration.', '', '---', - '_Note: These commands only work in pull request comments._' + '**Note:** These commands only work in pull request comments.', + '', + '**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' ].join('\n'); await github.rest.issues.createComment({