Skip to content

Deploying Review App #141

Deploying Review App

Deploying Review App #141

name: Deploy Review App to Control Plane
run-name: ${{ github.event_name == 'issue_comment' && 'Deploying Review App' || format('Updating Review App for {0}', github.ref_name) }}
on:
pull_request:
types: [opened, synchronize, reopened]
issue_comment:
types: [created]
# Use concurrency to cancel in-progress runs
concurrency:
group: deploy-pr-${{ 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_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
jobs:
Process-Deployment-Command:
if: |
(github.event_name == 'pull_request') ||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app')
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
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@justin808-working-for-deploys
with:
token: ${{ env.CPLN_TOKEN }}
org: ${{ env.CPLN_ORG }}
- name: Get PR HEAD Ref
if: github.event_name == 'issue_comment'
run: |
echo "PR_NUMBER=${{ github.event.issue.number }}" >> $GITHUB_ENV
echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ github.event.issue.number }}" >> $GITHUB_ENV
# 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 }}
- name: Check if Review App Exists
id: check-app
if: github.event_name == 'push'
env:
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
run: |
if ! cpflow exists -a ${{ env.APP_NAME }}; then
echo "No review app exists for this PR"
exit 0
fi
echo "app_exists=true" >> $GITHUB_OUTPUT
- name: Set Workflow URL
id: workflow-url
uses: actions/github-script@v7
with:
script: |
async function getWorkflowUrl(runId) {
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) {
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 workflowUrl = await getWorkflowUrl(context.runId);
core.exportVariable('WORKFLOW_URL', workflowUrl);
core.exportVariable('GET_CONSOLE_LINK', `
function getConsoleLink(prNumber) {
return '🎮 [Control Plane Console](' +
'https://console.cpln.io/console/org/' + process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)';
}
`);
- name: Create Initial Comment
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app') ||
( steps.check-app.outputs.app_exists == 'true')
id: create-comment
uses: actions/github-script@v7
with:
script: |
const result = await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: process.env.PR_NUMBER,
body: '🚀 Starting deployment process...'
});
console.log('Created comment:', result.data.id);
return { commentId: result.data.id };
- name: Set Comment ID
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app') ||
(steps.check-app.outputs.app_exists == 'true')
run: echo "COMMENT_ID=${{ fromJSON(steps.create-comment.outputs.result).commentId }}" >> $GITHUB_ENV
- name: Initialize Deployment
id: init-deployment
uses: actions/github-script@v7
with:
script: |
async function getWorkflowUrl(runId) {
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,
repo: context.repo.repo,
issue_number: process.env.PR_NUMBER,
body: '⏳ Initializing deployment...'
});
// Create GitHub deployment
const deployment = await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
environment: 'review',
auto_merge: false,
required_contexts: []
});
const workflowUrl = await getWorkflowUrl(context.runId);
return {
deploymentId: deployment.data.id,
commentId: comment.data.id,
workflowUrl
};
- name: Set comment ID and workflow URL
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
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: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app') ||
(steps.check-app.outputs.app_exists == 'true')
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 }}',
'🏗️ Building Docker image...',
'',
'📝 [View Build Logs](' + process.env.WORKFLOW_URL + ')',
'',
getConsoleLink(process.env.PR_NUMBER)
].join('\n');
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: process.env.COMMENT_ID,
body: buildingMessage
});
- name: Checkout PR Branch
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app') ||
(steps.check-app.outputs.app_exists == 'true')
run: git checkout ${{ steps.getRef.outputs.PR_REF }}
- name: Build Docker Image
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app') ||
(steps.check-app.outputs.app_exists == 'true')
uses: ./.github/actions/build-docker-image@justin808-working-for-deploys
with:
app_name: ${{ env.APP_NAME }}
org: ${{ env.CPLN_ORG }}
commit: ${{ env.COMMIT_HASH }}
PR_NUMBER: ${{ env.PR_NUMBER }}
- name: Update Status - Deploying
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app') ||
(steps.check-app.outputs.app_exists == 'true')
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 + ')',
'',
getConsoleLink(process.env.PR_NUMBER)
].join('\n');
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: process.env.COMMENT_ID,
body: deployingMessage
});
- name: Deploy to Control Plane
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/deploy-review-app') ||
(steps.check-app.outputs.app_exists == 'true')
uses: ./.github/actions/deploy-to-control-plane@justin808-working-for-deploys
with:
app_name: ${{ env.APP_NAME }}
org: ${{ env.CPLN_ORG }}
github_token: ${{ secrets.GITHUB_TOKEN }}
wait_timeout: ${{ vars.WAIT_TIMEOUT || 900 }}
env:
CPLN_TOKEN: ${{ env.CPLN_TOKEN }}
PR_NUMBER: ${{ env.PR_NUMBER }}
- name: Update Status - Deployment Complete
uses: actions/github-script@v7
with:
script: |
const prNumber = process.env.PR_NUMBER;
const appUrl = process.env.REVIEW_APP_URL;
const workflowUrl = process.env.WORKFLOW_URL;
const isSuccess = '${{ job.status }}' === 'success';
const consoleLink = '🎮 [Control Plane Console](https://console.cpln.io/console/org/' +
process.env.CPLN_ORG + '/gvc/' + process.env.APP_NAME + '/-info)';
// Create GitHub deployment status
const deploymentStatus = {
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }},
state: isSuccess ? 'success' : 'failure',
environment_url: isSuccess ? appUrl : undefined,
log_url: workflowUrl,
environment: 'review'
};
await github.rest.repos.createDeploymentStatus(deploymentStatus);
// Define messages based on deployment status
const successMessage = [
'✅ Deployment complete for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}',
'',
'🚀 [Review App for PR #' + prNumber + '](' + appUrl + ')',
consoleLink,
'',
'📋 [View Completed Action Build and Deploy Logs](' + workflowUrl + ')'
].join('\n');
const failureMessage = [
'❌ Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }}',
'',
consoleLink,
'',
'📋 [View Deployment Logs with Errors](' + workflowUrl + ')'
].join('\n');
// Update the existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: process.env.COMMENT_ID,
body: isSuccess ? successMessage : failureMessage
});