Skip to content

Improvements to deployments #32

Improvements to deployments

Improvements to deployments #32

name: Deploy Review or Staging App
on:
pull_request:
types: [opened, synchronize, reopened]
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_STAGING }}
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
jobs:
deploy:
if: |
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
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: Setup Environment
uses: ./.github/actions/setup-environment
- name: Initialize Deployment
id: init-deployment
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,
repo: context.repo.repo,
ref: context.sha,
environment: 'review-app',
auto_merge: false,
required_contexts: []
});
// Get the job ID
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;
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](' + 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'
});
return {
deploymentId: deployment.data.id,
commentId: comment.data.id,
workflowUrl: getWorkflowUrl(context.runId)
};
- 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
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()
uses: actions/github-script@v7
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 railsUrl = '${{ steps.deploy.outputs.rails_url }}';
const prNumber = process.env.PR_NUMBER;
// Update deployment status
const deploymentStatus = {
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deploymentId,
state: isSuccess ? 'success' : 'failure',
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
? [
'✅ 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,
repo: context.repo.repo,
comment_id: commentId,
body: message
});