Skip to content

Commit 098b886

Browse files
authored
Building on working for review apps (#620)
WIP for updating github actions
1 parent 151c527 commit 098b886

9 files changed

+264
-311
lines changed

.controlplane/controlplane.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ aliases:
3838
release_script: release_script.sh
3939

4040
apps:
41-
react-webpack-rails-tutorial:
41+
react-webpack-rails-tutorial-production:
4242
# Simulate Production Version
4343
<<: *common
4444
# Don't allow overriding the org and app by ENV vars b/c production is sensitive!

.github/actions/deploy-to-control-plane/action.yml

+51-197
Original file line numberDiff line numberDiff line change
@@ -44,205 +44,59 @@ runs:
4444
- name: Setup Environment
4545
uses: ./.github/actions/setup-environment
4646

47-
- name: Set shared functions
48-
id: shared-functions
49-
uses: actions/github-script@v7
50-
with:
51-
script: |
52-
core.exportVariable('GET_CONSOLE_LINK', `
53-
function getConsoleLink(prNumber) {
54-
return ' [Control Plane Console for Review App with PR #' + prNumber + '](' +
55-
'https://console.cpln.io/org/' + process.env.CPLN_ORG + '/workloads/' + process.env.APP_NAME + ')';
56-
}
57-
`);
58-
59-
- name: Initialize Deployment
60-
id: init-deployment
61-
uses: actions/github-script@v7
62-
with:
63-
script: |
64-
eval(process.env.GET_CONSOLE_LINK);
65-
66-
async function getWorkflowUrl(runId) {
67-
// Get the current job ID
68-
const jobs = await github.rest.actions.listJobsForWorkflowRun({
69-
owner: context.repo.owner,
70-
repo: context.repo.repo,
71-
run_id: runId
72-
});
73-
74-
const currentJob = jobs.data.jobs.find(job => job.status === 'in_progress');
75-
const jobId = currentJob?.id;
76-
77-
if (!jobId) {
78-
console.log('Warning: Could not find current job ID');
79-
return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`;
80-
}
81-
82-
return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}`;
83-
}
84-
85-
// Create initial deployment comment
86-
const comment = await github.rest.issues.createComment({
87-
owner: context.repo.owner,
88-
repo: context.repo.repo,
89-
issue_number: process.env.PR_NUMBER,
90-
body: ' Initializing deployment...'
91-
});
92-
93-
// Create GitHub deployment
94-
const deployment = await github.rest.repos.createDeployment({
95-
owner: context.repo.owner,
96-
repo: context.repo.repo,
97-
ref: context.sha,
98-
environment: 'review',
99-
auto_merge: false,
100-
required_contexts: []
101-
});
102-
103-
const workflowUrl = await getWorkflowUrl(context.runId);
104-
105-
core.exportVariable('WORKFLOW_URL', workflowUrl);
106-
core.exportVariable('COMMENT_ID', comment.data.id);
107-
core.exportVariable('DEPLOYMENT_ID', deployment.data.id);
108-
109-
- name: Set commit hash
110-
shell: bash
111-
run: |
112-
FULL_COMMIT=$(git rev-parse HEAD)
113-
echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV
114-
115-
- name: Update Status - Setting Up
116-
uses: actions/github-script@v7
117-
with:
118-
script: |
119-
eval(process.env.GET_CONSOLE_LINK);
120-
121-
const setupMessage = [
122-
'🔧 Setting up Control Plane app...',
123-
'',
124-
' [View Setup Logs](' + process.env.WORKFLOW_URL + ')',
125-
'',
126-
getConsoleLink(process.env.PR_NUMBER)
127-
].join('\n');
128-
129-
await github.rest.issues.updateComment({
130-
owner: context.repo.owner,
131-
repo: context.repo.repo,
132-
comment_id: process.env.COMMENT_ID,
133-
body: setupMessage
134-
});
135-
136-
- name: Setup Control Plane App
47+
- name: Get Commit SHA
48+
id: get_sha
13749
shell: bash
138-
run: |
139-
echo "🔧 Checking if app exists..."
140-
if ! cpflow exists -a ${{ inputs.app_name }} ; then
141-
echo "📦 Setting up new Control Plane app..."
142-
cpflow setup-app -a ${{ inputs.app_name }}
143-
fi
144-
145-
- name: Update Status - Building
146-
uses: actions/github-script@v7
147-
with:
148-
script: |
149-
eval(process.env.GET_CONSOLE_LINK);
150-
151-
const buildingMessage = [
152-
'🏗️ Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + process.env.COMMIT_HASH,
153-
'',
154-
' [View Build Logs](' + process.env.WORKFLOW_URL + ')',
155-
'',
156-
getConsoleLink(process.env.PR_NUMBER)
157-
].join('\n');
158-
159-
await github.rest.issues.updateComment({
160-
owner: context.repo.owner,
161-
repo: context.repo.repo,
162-
comment_id: process.env.COMMENT_ID,
163-
body: buildingMessage
164-
});
165-
166-
- name: Update Status - Deploying
167-
uses: actions/github-script@v7
168-
with:
169-
script: |
170-
eval(process.env.GET_CONSOLE_LINK);
171-
172-
const deployingMessage = [
173-
'🚀 Deploying to Control Plane...',
174-
'',
175-
'⏳ Waiting for deployment to be ready...',
176-
'',
177-
' [View Deploy Logs](' + process.env.WORKFLOW_URL + ')',
178-
'',
179-
getConsoleLink(process.env.PR_NUMBER)
180-
].join('\n');
181-
182-
await github.rest.issues.updateComment({
183-
owner: context.repo.owner,
184-
repo: context.repo.repo,
185-
comment_id: process.env.COMMENT_ID,
186-
body: deployingMessage
187-
});
50+
run: ${{ github.action_path }}/scripts/get-commit-sha.sh
51+
env:
52+
GITHUB_TOKEN: ${{ inputs.github_token }}
53+
PR_NUMBER: ${{ env.PR_NUMBER }}
18854

18955
- name: Deploy to Control Plane
19056
id: deploy
19157
shell: bash
192-
run: ${{ github.action_path }}/scripts/deploy.sh
193-
env:
194-
APP_NAME: ${{ inputs.app_name }}
195-
CPLN_ORG: ${{ inputs.org }}
196-
WAIT_TIMEOUT: ${{ inputs.wait_timeout }}
197-
198-
- name: Update Status - Deployment Complete
199-
if: always()
200-
uses: actions/github-script@v7
201-
with:
202-
script: |
203-
eval(process.env.GET_CONSOLE_LINK);
204-
205-
const prNumber = process.env.PR_NUMBER;
206-
const appUrl = process.env.REVIEW_APP_URL;
207-
const workflowUrl = process.env.WORKFLOW_URL;
208-
const isSuccess = '${{ job.status }}' === 'success';
209-
210-
// Create GitHub deployment status
211-
const deploymentStatus = {
212-
owner: context.repo.owner,
213-
repo: context.repo.repo,
214-
deployment_id: process.env.DEPLOYMENT_ID,
215-
state: isSuccess ? 'success' : 'failure',
216-
environment_url: isSuccess ? appUrl : undefined,
217-
log_url: workflowUrl,
218-
environment: 'review'
219-
};
220-
221-
await github.rest.repos.createDeploymentStatus(deploymentStatus);
222-
223-
// Define messages based on deployment status
224-
const successMessage = [
225-
'✅ Deployment complete for PR #' + prNumber + ', commit ' + process.env.COMMIT_HASH,
226-
'',
227-
'🌐 [Review App for PR #' + prNumber + '](' + appUrl + ')',
228-
'',
229-
' [View Completed Action Build and Deploy Logs](' + workflowUrl + ')',
230-
'',
231-
getConsoleLink(prNumber)
232-
].join('\n');
233-
234-
const failureMessage = [
235-
'❌ Deployment failed for PR #' + prNumber + ', commit ' + process.env.COMMIT_HASH,
236-
'',
237-
' [View Deployment Logs with Errors](' + workflowUrl + ')',
238-
'',
239-
getConsoleLink(prNumber)
240-
].join('\n');
241-
242-
// Update the existing comment
243-
await github.rest.issues.updateComment({
244-
owner: context.repo.owner,
245-
repo: context.repo.repo,
246-
comment_id: process.env.COMMENT_ID,
247-
body: isSuccess ? successMessage : failureMessage
248-
});
58+
run: |
59+
echo "🚀 Deploying app for PR #${PR_NUMBER}..."
60+
61+
# Create temp file for output
62+
TEMP_OUTPUT=$(mktemp)
63+
trap 'rm -f "${TEMP_OUTPUT}"' EXIT
64+
65+
# Deploy the application and show output in real-time while capturing it
66+
if ! cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1 | tee "${TEMP_OUTPUT}"; then
67+
echo "❌ Deployment failed for PR #${PR_NUMBER}"
68+
echo "Error output:"
69+
cat "${TEMP_OUTPUT}"
70+
exit 1
71+
fi
72+
73+
# Extract app URL from captured output
74+
REVIEW_APP_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "${TEMP_OUTPUT}" | head -n1)
75+
if [ -z "${REVIEW_APP_URL}" ]; then
76+
echo "❌ Failed to get app URL from deployment output"
77+
echo "Deployment output:"
78+
cat "${TEMP_OUTPUT}"
79+
exit 1
80+
fi
81+
82+
# Wait for all workloads to be ready
83+
WAIT_TIMEOUT=${WAIT_TIMEOUT:-${{ inputs.wait_timeout }}}
84+
echo "⏳ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)..."
85+
86+
# Use timeout command with ps:wait and show output in real-time
87+
if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1 | tee -a "${TEMP_OUTPUT}"; then
88+
TIMEOUT_EXIT=$?
89+
if [ ${TIMEOUT_EXIT} -eq 124 ]; then
90+
echo "❌ Timed out waiting for workloads after ${WAIT_TIMEOUT} seconds"
91+
else
92+
echo "❌ Workloads did not become ready for PR #${PR_NUMBER} (exit code: ${TIMEOUT_EXIT})"
93+
fi
94+
echo "Full output:"
95+
cat "${TEMP_OUTPUT}"
96+
exit 1
97+
fi
98+
99+
echo "✅ Deployment successful for PR #${PR_NUMBER}"
100+
echo "🌐 App URL: ${REVIEW_APP_URL}"
101+
echo "review_app_url=${REVIEW_APP_URL}" >> $GITHUB_OUTPUT
102+
echo "REVIEW_APP_URL=${REVIEW_APP_URL}" >> $GITHUB_ENV

.github/actions/setup-environment/action.yml

+18-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
name: 'Setup Environment'
44
description: 'Sets up Ruby, installs Control Plane CLI, cpflow gem, and sets up the default profile'
55

6+
inputs:
7+
token:
8+
description: 'Control Plane token'
9+
required: true
10+
org:
11+
description: 'Control Plane organization'
12+
required: true
13+
614
runs:
715
using: 'composite'
816
steps:
@@ -22,19 +30,22 @@ runs:
2230
- name: Setup Control Plane Profile
2331
shell: bash
2432
run: |
25-
if [ -z "$CPLN_TOKEN" ]; then
26-
echo " Error: CPLN_TOKEN environment variable is not set"
33+
TOKEN="${{ inputs.token }}"
34+
ORG="${{ inputs.org }}"
35+
36+
if [ -z "$TOKEN" ]; then
37+
echo " Error: Control Plane token not provided"
2738
exit 1
2839
fi
2940
30-
if [ -z "$CPLN_ORG" ]; then
31-
echo " Error: CPLN_ORG environment variable is not set"
41+
if [ -z "$ORG" ]; then
42+
echo " Error: Control Plane organization not provided"
3243
exit 1
3344
fi
3445
3546
echo "Setting up Control Plane profile..."
36-
echo "Organization: $CPLN_ORG"
37-
cpln profile update default --org "$CPLN_ORG" --token "$CPLN_TOKEN"
47+
echo "Organization: $ORG"
48+
cpln profile update default --org "$ORG" --token "$TOKEN"
3849
3950
echo "Setting up Docker login for Control Plane registry..."
40-
cpln image docker-login --org "$CPLN_ORG"
51+
cpln image docker-login --org "$ORG"

.github/workflows/delete-review-app.yml

+24-5
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ permissions:
1313
issues: write
1414

1515
env:
16-
CPLN_ORG: ${{ secrets.CPLN_ORG }}
17-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
16+
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
17+
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
1818
APP_NAME: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number || github.event.issue.number }}
1919
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
2020

@@ -29,6 +29,18 @@ jobs:
2929
runs-on: ubuntu-latest
3030

3131
steps:
32+
- name: Get PR number
33+
id: pr
34+
uses: actions/github-script@v7
35+
with:
36+
script: |
37+
const prNumber = context.payload.issue.number;
38+
core.setOutput('pr_number', prNumber);
39+
core.exportVariable('PR_NUMBER', prNumber);
40+
41+
- name: Set App Name
42+
run: echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" >> $GITHUB_ENV
43+
3244
- uses: actions/checkout@v4
3345

3446
- name: Validate Required Secrets
@@ -46,7 +58,10 @@ jobs:
4658
fi
4759
4860
- name: Setup Environment
49-
uses: ./.github/actions/setup-environment
61+
uses: ./.github/actions/setup-environment@justin808-working-for-deploys
62+
with:
63+
org: ${{ env.CPLN_ORG }}
64+
token: ${{ env.CPLN_TOKEN }}
5065

5166
- name: Set shared functions
5267
id: shared-functions
@@ -105,23 +120,26 @@ jobs:
105120
issue_number: process.env.PR_NUMBER,
106121
owner: context.repo.owner,
107122
repo: context.repo.repo,
123+
body: '🗑️ Starting app deletion...'
108124
body: [
109125
message,
110126
'',
111-
' [View Delete Logs](' + process.env.WORKFLOW_URL + ')',
127+
' 🗑️ [View Delete Logs](' + process.env.WORKFLOW_URL + ')',
112128
'',
113129
getConsoleLink(process.env.PR_NUMBER)
114130
].join('\n')
115131
});
116132
return { commentId: comment.data.id };
117133
118134
- name: Delete Review App
119-
uses: ./.github/actions/delete-control-plane-app
135+
uses: ./.github/actions/delete-control-plane-app@justin808-working-for-deploys
120136
with:
121137
app_name: ${{ env.APP_NAME }}
122138
org: ${{ env.CPLN_ORG }}
123139
github_token: ${{ secrets.GITHUB_TOKEN }}
124140
env:
141+
APP_NAME: ${{ env.APP_NAME }}
142+
CPLN_ORG: ${{ secrets.CPLN_ORG }}
125143
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
126144

127145
- name: Update Delete Status
@@ -133,6 +151,7 @@ jobs:
133151
134152
const success = '${{ job.status }}' === 'success';
135153
const prNumber = process.env.PR_NUMBER;
154+
const cpConsoleUrl = `https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME}`;
136155
137156
const successMessage = [
138157
'✅ Review app for PR #' + prNumber + ' was successfully deleted',

0 commit comments

Comments
 (0)