@@ -26,66 +26,223 @@ outputs:
26
26
runs :
27
27
using : " composite"
28
28
steps :
29
+ - name : Validate Required Secrets
30
+ shell : bash
31
+ run : |
32
+ missing_secrets=()
33
+ for secret in "CPLN_TOKEN" "CPLN_ORG"; do
34
+ if [ -z "${!secret}" ]; then
35
+ missing_secrets+=("$secret")
36
+ fi
37
+ done
38
+
39
+ if [ ${#missing_secrets[@]} -ne 0 ]; then
40
+ echo "Required secrets are not set: ${missing_secrets[*]}"
41
+ exit 1
42
+ fi
43
+
29
44
- name : Setup Environment
30
45
uses : ./.github/actions/setup-environment
31
46
32
- - name : Get Commit SHA
33
- id : get_sha
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
34
110
shell : bash
35
- run : ${{ github.action_path }}/scripts/get-commit-sha.sh
36
- env :
37
- GITHUB_TOKEN : ${{ inputs.github_token }}
38
- PR_NUMBER : ${{ env.PR_NUMBER }}
111
+ run : |
112
+ FULL_COMMIT=$(git rev-parse HEAD)
113
+ echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV
39
114
40
- - name : Deploy to Control Plane
41
- id : deploy
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
42
137
shell : bash
43
138
run : |
44
- echo "🚀 Deploying app for PR #${PR_NUMBER}..."
45
-
46
- # Create temp file for output
47
- TEMP_OUTPUT=$(mktemp)
48
- trap 'rm -f "${TEMP_OUTPUT}"' EXIT
49
-
50
- # Deploy the application and show output in real-time while capturing it
51
- if ! cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1 | tee "${TEMP_OUTPUT}"; then
52
- echo "❌ Deployment failed for PR #${PR_NUMBER}"
53
- echo "Error output:"
54
- cat "${TEMP_OUTPUT}"
55
- exit 1
56
- fi
57
-
58
- # Extract app URL from captured output
59
- REVIEW_APP_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "${TEMP_OUTPUT}" | head -n1)
60
- if [ -z "${REVIEW_APP_URL}" ]; then
61
- echo "❌ Failed to get app URL from deployment output"
62
- echo "Deployment output:"
63
- cat "${TEMP_OUTPUT}"
64
- exit 1
65
- fi
66
-
67
- # Wait for all workloads to be ready
68
- WAIT_TIMEOUT=${WAIT_TIMEOUT:-${{ inputs.wait_timeout }}}
69
- if ! [[ "${WAIT_TIMEOUT}" =~ ^[0-9]+$ ]]; then
70
- echo "❌ Invalid timeout value: ${WAIT_TIMEOUT}"
71
- exit 1
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 }}
72
143
fi
73
- echo "⏳ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)"
74
-
75
- # Use timeout command with ps:wait and show output in real-time
76
- if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1 | tee -a "${TEMP_OUTPUT}"; then
77
- TIMEOUT_EXIT=$?
78
- if [ ${TIMEOUT_EXIT} -eq 124 ]; then
79
- echo "❌ Timed out waiting for workloads after ${WAIT_TIMEOUT} seconds"
80
- else
81
- echo "❌ Workloads did not become ready for PR #${PR_NUMBER} (exit code: ${TIMEOUT_EXIT})"
82
- fi
83
- echo "Full output:"
84
- cat "${TEMP_OUTPUT}"
85
- exit 1
86
- fi
87
-
88
- echo "✅ Deployment successful for PR #${PR_NUMBER}"
89
- echo "🌐 App URL: ${REVIEW_APP_URL}"
90
- echo "review_app_url=${REVIEW_APP_URL}" >> $GITHUB_OUTPUT
91
- echo "REVIEW_APP_URL=${REVIEW_APP_URL}" >> $GITHUB_ENV
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
+ });
188
+
189
+ - name : Deploy to Control Plane
190
+ id : deploy
191
+ 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
+ });
0 commit comments