|
1 |
| -# Control Plane GitHub Action |
2 |
| - |
3 | 1 | name: Deploy Review App to Control Plane
|
4 | 2 |
|
5 |
| -# Controls when the workflow will run |
6 | 3 | on:
|
7 |
| - # Allows you to run this workflow manually from the Actions tab |
8 | 4 | workflow_dispatch:
|
9 |
| - |
10 |
| - # Uncomment these lines to trigger the workflow on pull request events |
11 |
| - # pull_request: |
12 |
| - # branches: |
13 |
| - # - master |
14 |
| - |
15 |
| - # deploy on comment "/deploy-review-app" |
| 5 | + pull_request: |
| 6 | + types: [opened, synchronize, reopened] |
| 7 | + branches: [master] |
16 | 8 | issue_comment:
|
17 |
| - types: [created, edited] |
| 9 | + types: [created] |
| 10 | + |
| 11 | +concurrency: |
| 12 | + group: review-app-${{ github.event.pull_request.number || github.event.issue.number }} |
| 13 | + cancel-in-progress: true |
18 | 14 |
|
19 |
| -# Convert the GitHub secret variables to environment variables for use by the Control Plane CLI |
20 | 15 | env:
|
21 | 16 | CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}}
|
22 | 17 | CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}}
|
23 |
| - # Uncomment this line to use the PR number from the pull requests trigger event (that trigger is commented) |
24 |
| - # PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} |
25 |
| - PR_NUMBER: ${{ github.event.issue.number }} |
| 18 | + PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} |
| 19 | + 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 }} |
26 | 20 |
|
27 | 21 | jobs:
|
| 22 | + check-concurrent: |
| 23 | + runs-on: ubuntu-latest |
| 24 | + outputs: |
| 25 | + cancelled: ${{ steps.check.outputs.cancelled }} |
| 26 | + steps: |
| 27 | + - name: Check for concurrent deployment |
| 28 | + id: check |
| 29 | + run: | |
| 30 | + if [ "${{ github.run_attempt }}" != "1" ]; then |
| 31 | + echo "⚠️ Cancelling previous deployment due to new code push..." |
| 32 | + echo "cancelled=true" >> $GITHUB_OUTPUT |
| 33 | + else |
| 34 | + echo "cancelled=false" >> $GITHUB_OUTPUT |
| 35 | + fi |
| 36 | +
|
28 | 37 | deploy-to-control-plane-review:
|
29 |
| - if: ${{ github.event_name != 'issue_comment' || (github.event.comment.body == '/deploy-review-app' && github.event.issue.pull_request) }} |
| 38 | + needs: check-concurrent |
| 39 | + if: | |
| 40 | + needs.check-concurrent.outputs.cancelled != 'true' && |
| 41 | + (github.event_name == 'workflow_dispatch' || |
| 42 | + github.event_name == 'pull_request' || |
| 43 | + (github.event_name == 'issue_comment' && |
| 44 | + github.event.comment.body == '/deploy-review-app' && |
| 45 | + github.event.issue.pull_request)) |
30 | 46 | runs-on: ubuntu-latest
|
31 | 47 |
|
| 48 | + permissions: |
| 49 | + contents: read |
| 50 | + deployments: write |
| 51 | + pull-requests: write |
| 52 | + |
| 53 | + outputs: |
| 54 | + app_url: ${{ steps.deploy.outputs.app_url }} |
| 55 | + deployment_id: ${{ steps.create-deployment.outputs.result }} |
| 56 | + |
32 | 57 | steps:
|
| 58 | + - name: Create comment |
| 59 | + id: create-comment |
| 60 | + uses: actions/github-script@v7 |
| 61 | + with: |
| 62 | + script: | |
| 63 | + async function createComment(message) { |
| 64 | + await github.rest.issues.createComment({ |
| 65 | + issue_number: context.issue.number || context.payload.pull_request.number, |
| 66 | + owner: context.repo.owner, |
| 67 | + repo: context.repo.repo, |
| 68 | + body: message |
| 69 | + }); |
| 70 | + } |
| 71 | + |
| 72 | + const message = `🚀 Starting new deployment for commit: ${context.sha.substring(0, 7)} |
| 73 | + ${context.payload.commits ? `\nChanges: ${context.payload.commits[0].message}` : ''} |
| 74 | + Status: ${{ env.STATUS_URL }}`; |
| 75 | + |
| 76 | + await createComment(message); |
| 77 | +
|
| 78 | + - name: Create GitHub Deployment |
| 79 | + id: create-deployment |
| 80 | + uses: actions/github-script@v7 |
| 81 | + with: |
| 82 | + script: | |
| 83 | + const deployment = await github.rest.repos.createDeployment({ |
| 84 | + owner: context.repo.owner, |
| 85 | + repo: context.repo.repo, |
| 86 | + ref: context.sha, |
| 87 | + environment: 'review-app', |
| 88 | + auto_merge: false, |
| 89 | + required_contexts: [] |
| 90 | + }); |
| 91 | + return deployment.data.id; |
| 92 | +
|
33 | 93 | - name: Get PR HEAD Ref
|
34 | 94 | if: ${{ github.event_name == 'issue_comment' }}
|
35 | 95 | id: getRef
|
36 |
| - run: echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT |
| 96 | + run: | |
| 97 | + echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT |
37 | 98 | env:
|
38 | 99 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
39 | 100 |
|
40 |
| - - name: Checkout source code from Github |
| 101 | + - name: Checkout source code |
41 | 102 | uses: actions/checkout@v4
|
42 | 103 | with:
|
43 | 104 | fetch-depth: 0
|
44 | 105 | ref: ${{ steps.getRef.outputs.PR_REF || github.ref }}
|
45 | 106 |
|
46 |
| - - name: Add GitHub Comment |
47 |
| - if: ${{ github.event_name == 'issue_comment' }} |
| 107 | + - name: Update deployment status (in_progress) |
48 | 108 | uses: actions/github-script@v7
|
49 | 109 | with:
|
50 | 110 | script: |
|
51 |
| - github.rest.issues.createComment({ |
52 |
| - issue_number: context.issue.number, |
| 111 | + await github.rest.repos.createDeploymentStatus({ |
53 | 112 | owner: context.repo.owner,
|
54 | 113 | repo: context.repo.repo,
|
55 |
| - 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." |
56 |
| - }) |
| 114 | + deployment_id: ${{ steps.create-deployment.outputs.result }}, |
| 115 | + state: 'in_progress', |
| 116 | + description: 'Deployment is in progress' |
| 117 | + }); |
57 | 118 |
|
58 |
| - - name: Get PR number |
59 |
| - if: ${{ github.event_name != 'issue_comment' }} |
60 |
| - run: | |
61 |
| - echo "GITHUB_REPOSITORY: \"$GITHUB_REPOSITORY\"" |
62 |
| - if [ -z "$PR_NUMBER" ]; then |
63 |
| - echo "PR_NUMBER is not in the trigger event. Fetching PR number from open PRs." |
64 |
| - REF="${{ github.ref }}" |
65 |
| - REF=${REF#refs/heads/} # Remove 'refs/heads/' prefix |
66 |
| - echo "REF: \"$REF\"" |
67 |
| - API_RESPONSE=$(curl --location --request GET "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls?state=open" \ |
68 |
| - --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}') |
69 |
| - PR_NUMBER=$(echo "$API_RESPONSE" | jq '.[] | select(.head.ref=="'$REF'") | .number') |
70 |
| - fi |
71 |
| - echo "PR_NUMBER: $PR_NUMBER" |
72 |
| - if [ -z "$PR_NUMBER" ]; then |
73 |
| - echo "PR_NUMBER is not set. Aborting." |
74 |
| - exit 1 |
75 |
| - fi |
76 |
| - echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV |
77 |
| - - name: Get App Name |
| 119 | + - name: Configure app name |
| 120 | + id: app-config |
78 | 121 | run: |
|
79 |
| - echo "PR_NUMBER: ${{ env.PR_NUMBER }}" |
80 |
| - echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" >> "$GITHUB_ENV" |
81 |
| - echo "App Name: ${{ env.APP_NAME }}" |
82 |
| - - uses: ./.github/actions/deploy-to-control-plane |
| 122 | + APP_NAME="qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" |
| 123 | + echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV |
| 124 | + echo "app_name=$APP_NAME" >> $GITHUB_OUTPUT |
| 125 | +
|
| 126 | + - name: Deploy to Control Plane |
| 127 | + id: deploy |
| 128 | + uses: ./.github/actions/deploy-to-control-plane |
83 | 129 | with:
|
84 | 130 | app_name: ${{ env.APP_NAME }}
|
85 | 131 | org: ${{ env.CPLN_ORG }}
|
| 132 | + |
| 133 | + - name: Update deployment status (success) |
| 134 | + if: success() |
| 135 | + uses: actions/github-script@v7 |
| 136 | + with: |
| 137 | + script: | |
| 138 | + const message = `✅ Deployment successful! |
| 139 | + Environment: review-app |
| 140 | + Commit: ${context.sha.substring(0, 7)} |
| 141 | + URL: ${{ steps.deploy.outputs.app_url }} |
| 142 | + Status: ${{ env.STATUS_URL }}`; |
| 143 | + |
| 144 | + await eval(process.env.createComment)(message); |
| 145 | + |
| 146 | + await github.rest.repos.createDeploymentStatus({ |
| 147 | + owner: context.repo.owner, |
| 148 | + repo: context.repo.repo, |
| 149 | + deployment_id: ${{ steps.create-deployment.outputs.result }}, |
| 150 | + state: 'success', |
| 151 | + environment_url: '${{ steps.deploy.outputs.app_url }}', |
| 152 | + description: 'Deployment successful' |
| 153 | + }); |
| 154 | +
|
| 155 | + - name: Update deployment status (failure) |
| 156 | + if: failure() |
| 157 | + uses: actions/github-script@v7 |
| 158 | + with: |
| 159 | + script: | |
| 160 | + const message = `❌ Deployment failed |
| 161 | + Commit: ${context.sha.substring(0, 7)} |
| 162 | + Status: ${{ env.STATUS_URL }}`; |
| 163 | + |
| 164 | + await eval(process.env.createComment)(message); |
| 165 | + |
| 166 | + await github.rest.repos.createDeploymentStatus({ |
| 167 | + owner: context.repo.owner, |
| 168 | + repo: context.repo.repo, |
| 169 | + deployment_id: ${{ steps.create-deployment.outputs.result }}, |
| 170 | + state: 'failure', |
| 171 | + description: 'Deployment failed' |
| 172 | + }); |
0 commit comments