-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improvements to deployments #615
Changes from 10 commits
ee08d3a
c790151
8355030
f19d79f
e487791
25e9502
de55983
5240c9b
2a1b9a3
8918cd2
fe262cb
80d841b
084f0d0
cac41c4
745ca0e
f77a610
87662fa
4970fbe
e26cc72
29ade6f
8db0511
b7a7229
1cff976
6cbdb04
0b15816
ae8a473
e6d5025
444ec85
8041a01
b03b6d7
a12e0d4
98649f2
b2e710a
c54a544
c80ff43
40473cc
038cf8f
c25211f
304e642
4744c76
5c8b3ab
2a51c92
61213b9
e431bdf
895986c
3fe506e
585c02d
c46f595
65c64d1
e96ac82
2be9c2f
5f50639
e0cf883
b27783e
66a4114
3426aca
92ad3a7
7d75738
d5b8b7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,85 +1,178 @@ | ||||||||||||||||||
# 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 }} | ||||||||||||||||||
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: | ||||||||||||||||||
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: | ||||||||||||||||||
if: ${{ github.event_name != 'issue_comment' || (github.event.comment.body == '/deploy-review-app' && github.event.issue.pull_request) }} | ||||||||||||||||||
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)) | ||||||||||||||||||
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 }} | ||||||||||||||||||
|
||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix deployment_id output reference. The deployment ID should include the full path to the data property: outputs:
app_url: ${{ steps.deploy.outputs.app_url }}
- deployment_id: ${{ steps.create-deployment.outputs.result }}
+ deployment_id: ${{ fromJSON(steps.create-deployment.outputs.result).id }} 📝 Committable suggestion
Suggested change
🧰 Tools🪛 actionlint (1.7.4)54-54: property "app_url" is not defined in object type {} (expression) |
||||||||||||||||||
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: ${{ env.STATUS_URL }}`; | ||||||||||||||||||
|
||||||||||||||||||
await eval(process.env.createComment)(message); | ||||||||||||||||||
|
||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider security implications of using eval. The use of - await eval(process.env.createComment)(message);
+ 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
+ });
+ };
+ await createComment(message); Also applies to: 150-150, 170-170 |
||||||||||||||||||
- 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 }} | ||||||||||||||||||
|
||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix shell script quoting. Add double quotes around variables to prevent word splitting and globbing: - echo "PR_REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT
+ echo "PR_REF=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json headRefName | jq -r '.headRefName')" >> "$GITHUB_OUTPUT" 📝 Committable suggestion
Suggested change
🧰 Tools🪛 actionlint (1.7.4)53-53: shellcheck reported issue in this script: SC2086:info:1:27: Double quote to prevent globbing and word splitting (shellcheck) 53-53: shellcheck reported issue in this script: SC2086:info:1:117: Double quote to prevent globbing and word splitting (shellcheck) |
||||||||||||||||||
- 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.result }}, | ||||||||||||||||||
state: 'in_progress', | ||||||||||||||||||
description: 'Deployment is in progress' | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
- name: Get PR number | ||||||||||||||||||
if: ${{ github.event_name != 'issue_comment' }} | ||||||||||||||||||
- name: Configure app name | ||||||||||||||||||
id: app-config | ||||||||||||||||||
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 | ||||||||||||||||||
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 }} | ||||||||||||||||||
Status: ${{ env.STATUS_URL }}`; | ||||||||||||||||||
|
||||||||||||||||||
await eval(process.env.createComment)(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: '${{ steps.deploy.outputs.app_url }}', | ||||||||||||||||||
description: 'Deployment successful' | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
- 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 }}`; | ||||||||||||||||||
|
||||||||||||||||||
await eval(process.env.createComment)(message); | ||||||||||||||||||
|
||||||||||||||||||
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' | ||||||||||||||||||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix shell script quoting in concurrent check.
Add quotes around GITHUB_OUTPUT to prevent word splitting:
Also applies to: 34-34