@@ -34,17 +34,21 @@ jobs:
34
34
issues : write
35
35
36
36
steps :
37
- - uses : actions/checkout@v4
38
-
39
37
- name : Get PR HEAD Ref
40
38
if : github.event_name == 'issue_comment'
41
39
id : getRef
42
40
run : |
43
- PR_URL=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
44
- -H "Accept: application/vnd.github.v3+json" \
45
- "${{ github.event.issue.pull_request.url }}")
46
- HEAD_REF=$(echo "$PR_URL" | jq -r .head.ref)
47
- echo "ref=$HEAD_REF" >> "$GITHUB_OUTPUT"
41
+ # For PR comments, get the actual PR head commit
42
+ PR_DATA=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName,headRefOid)
43
+ echo "PR_REF=$(echo "$PR_DATA" | jq -r '.headRefName')" >> $GITHUB_OUTPUT
44
+ echo "PR_SHA=$(echo "$PR_DATA" | jq -r '.headRefOid')" >> $GITHUB_OUTPUT
45
+ env :
46
+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
47
+
48
+ - uses : actions/checkout@v4
49
+ with :
50
+ fetch-depth : 0
51
+ ref : ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || steps.getRef.outputs.PR_REF || github.ref }}
48
52
49
53
- name : Validate Required Secrets
50
54
run : |
@@ -63,78 +67,229 @@ jobs:
63
67
- name : Setup Environment
64
68
uses : ./.github/actions/setup-environment
65
69
66
- - name : Create Initial Status Comment
67
- id : init-status
70
+ - name : Set shared functions
71
+ id : shared-functions
72
+ uses : actions/github-script@v7
73
+ with :
74
+ script : |
75
+ core.exportVariable('GET_CONSOLE_LINK', `
76
+ function getConsoleLink(prNumber) {
77
+ return ' [Control Plane Console for Review App with PR #' + prNumber + '](' +
78
+ 'https://console.cpln.io/org/' + process.env.CPLN_ORG + '/workloads/' + process.env.APP_NAME + ')';
79
+ }
80
+ `);
81
+
82
+ - name : Initialize Deployment
83
+ id : init-deployment
68
84
uses : actions/github-script@v7
69
85
with :
70
86
script : |
87
+ eval(process.env.GET_CONSOLE_LINK);
88
+
89
+ async function getWorkflowUrl(runId) {
90
+ // Get the current job ID
91
+ const jobs = await github.rest.actions.listJobsForWorkflowRun({
92
+ owner: context.repo.owner,
93
+ repo: context.repo.repo,
94
+ run_id: runId
95
+ });
96
+
97
+ const currentJob = jobs.data.jobs.find(job => job.status === 'in_progress');
98
+ const jobId = currentJob?.id;
99
+
100
+ if (!jobId) {
101
+ console.log('Warning: Could not find current job ID');
102
+ return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`;
103
+ }
104
+
105
+ return `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/job/${jobId}`;
106
+ }
107
+
108
+ // Create initial deployment comment
71
109
const comment = await github.rest.issues.createComment({
110
+ owner: context.repo.owner,
111
+ repo: context.repo.repo,
72
112
issue_number: process.env.PR_NUMBER,
113
+ body: ' Initializing deployment...'
114
+ });
115
+
116
+ // Create GitHub deployment
117
+ const deployment = await github.rest.repos.createDeployment({
73
118
owner: context.repo.owner,
74
119
repo: context.repo.repo,
75
- body: '🚀 Starting deployment...'
120
+ ref: context.sha,
121
+ environment: 'review',
122
+ auto_merge: false,
123
+ required_contexts: []
76
124
});
77
- return { commentId: comment.data.id };
125
+
126
+ const workflowUrl = await getWorkflowUrl(context.runId);
127
+
128
+ return {
129
+ deploymentId: deployment.data.id,
130
+ commentId: comment.data.id,
131
+ workflowUrl
132
+ };
133
+
134
+ - name : Set comment ID and workflow URL
135
+ run : |
136
+ echo "COMMENT_ID=${{ fromJSON(steps.init-deployment.outputs.result).commentId }}" >> $GITHUB_ENV
137
+ echo "WORKFLOW_URL=${{ fromJSON(steps.init-deployment.outputs.result).workflowUrl }}" >> $GITHUB_ENV
138
+
139
+ - name : Set commit hash
140
+ run : |
141
+ FULL_COMMIT="${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || steps.getRef.outputs.PR_SHA || github.sha }}"
142
+ echo "COMMIT_HASH=${FULL_COMMIT:0:7}" >> $GITHUB_ENV
78
143
79
144
- name : Update Status - Building
80
145
uses : actions/github-script@v7
81
146
with :
82
147
script : |
83
- function getConsoleLink(prNumber) {
84
- return `[Control Plane Console](https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME})`;
85
- }
148
+ eval(process.env.GET_CONSOLE_LINK);
149
+
150
+ const buildingMessage = [
151
+ ' Building Docker image for PR #' + process.env.PR_NUMBER + ', commit ' + '${{ env.COMMIT_HASH }}',
152
+ '',
153
+ ' [View Build Logs](' + process.env.WORKFLOW_URL + ')',
154
+ '',
155
+ getConsoleLink(process.env.PR_NUMBER)
156
+ ].join('\n');
86
157
87
158
await github.rest.issues.updateComment({
88
159
owner: context.repo.owner,
89
160
repo: context.repo.repo,
90
- comment_id: ${{ fromJSON(steps.init-status.outputs.result).commentId }},
91
- body: [
92
- '🏗️ Building review app...',
93
- '',
94
- getConsoleLink(process.env.PR_NUMBER)
95
- ].join('\n')
161
+ comment_id: process.env.COMMENT_ID,
162
+ body: buildingMessage
96
163
});
97
164
98
- - name : Deploy Review App
99
- id : deploy
165
+ - name : Build Docker Image
166
+ uses : ./.github/actions/build-docker-image
167
+ with :
168
+ app_name : ${{ env.APP_NAME }}
169
+ org : ${{ env.CPLN_ORG }}
170
+ commit : ${{ env.COMMIT_HASH }}
171
+ PR_NUMBER : ${{ env.PR_NUMBER }}
172
+
173
+ - name : Update Status - Deploying
174
+ uses : actions/github-script@v7
175
+ with :
176
+ script : |
177
+ eval(process.env.GET_CONSOLE_LINK);
178
+
179
+ const deployingMessage = [
180
+ ' Deploying to Control Plane...',
181
+ '',
182
+ ' Waiting for deployment to be ready...',
183
+ '',
184
+ ' [View Deploy Logs](' + process.env.WORKFLOW_URL + ')',
185
+ '',
186
+ getConsoleLink(process.env.PR_NUMBER)
187
+ ].join('\n');
188
+
189
+ await github.rest.issues.updateComment({
190
+ owner: context.repo.owner,
191
+ repo: context.repo.repo,
192
+ comment_id: process.env.COMMENT_ID,
193
+ body: deployingMessage
194
+ });
195
+
196
+ - name : Deploy to Control Plane
100
197
uses : ./.github/actions/deploy-to-control-plane
101
198
with :
102
199
app_name : ${{ env.APP_NAME }}
103
200
org : ${{ env.CPLN_ORG }}
104
- wait_timeout : 900
105
201
github_token : ${{ secrets.GITHUB_TOKEN }}
106
- env :
107
- CPLN_TOKEN : ${{ secrets.CPLN_TOKEN }}
202
+ wait_timeout : ${{ vars.WAIT_TIMEOUT || 900 }}
108
203
109
- - name : Update Status - Complete
110
- if : always()
204
+ - name : Update Status - Deployment Complete
111
205
uses : actions/github-script@v7
112
206
with :
113
207
script : |
114
- function getConsoleLink(prNumber) {
115
- return `[Control Plane Console](https://console.cpln.io/org/${process.env.CPLN_ORG}/workloads/${process.env.APP_NAME})`;
116
- }
117
-
208
+ eval(process.env.GET_CONSOLE_LINK);
209
+
210
+ const prNumber = process.env.PR_NUMBER;
211
+ const appUrl = process.env.REVIEW_APP_URL;
212
+ const workflowUrl = process.env.WORKFLOW_URL;
118
213
const isSuccess = '${{ job.status }}' === 'success';
119
- const railsUrl = '${{ steps.deploy.outputs.rails_url }}';
120
214
215
+ // Create GitHub deployment status
216
+ const deploymentStatus = {
217
+ owner: context.repo.owner,
218
+ repo: context.repo.repo,
219
+ deployment_id: ${{ fromJSON(steps.init-deployment.outputs.result).deploymentId }},
220
+ state: isSuccess ? 'success' : 'failure',
221
+ environment_url: isSuccess ? appUrl : undefined,
222
+ log_url: workflowUrl,
223
+ environment: 'review'
224
+ };
225
+
226
+ await github.rest.repos.createDeploymentStatus(deploymentStatus);
227
+
228
+ // Define messages based on deployment status
121
229
const successMessage = [
122
- '✅ Review app deployed successfully! ',
230
+ ' Deployment complete for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }} ',
123
231
'',
124
- '🌐 [Rails App](' + railsUrl + ')',
232
+ ' [Review App for PR #' + prNumber + ' ](' + appUrl + ')',
125
233
'',
126
- getConsoleLink(process.env.PR_NUMBER)
234
+ ' [View Completed Action Build and Deploy Logs](' + workflowUrl + ')',
235
+ '',
236
+ getConsoleLink(prNumber)
127
237
].join('\n');
128
238
129
239
const failureMessage = [
130
- '❌ Review app deployment failed ',
240
+ ' Deployment failed for PR #' + prNumber + ', commit ' + '${{ env.COMMIT_HASH }} ',
131
241
'',
132
- getConsoleLink(process.env.PR_NUMBER)
242
+ ' [View Deployment Logs with Errors](' + workflowUrl + ')',
243
+ '',
244
+ getConsoleLink(prNumber)
133
245
].join('\n');
134
246
247
+ // Update the existing comment
135
248
await github.rest.issues.updateComment({
136
249
owner: context.repo.owner,
137
250
repo: context.repo.repo,
138
- comment_id: ${{ fromJSON(steps.init-status.outputs.result).commentId }} ,
251
+ comment_id: process.env.COMMENT_ID ,
139
252
body: isSuccess ? successMessage : failureMessage
253
+ });
254
+
255
+ show-help :
256
+ if : |
257
+ github.event_name == 'issue_comment' &&
258
+ github.event.issue.pull_request &&
259
+ github.event.comment.body == '/help'
260
+ runs-on : ubuntu-latest
261
+
262
+ steps :
263
+ - name : Show Available Commands
264
+ uses : actions/github-script@v7
265
+ with :
266
+ script : |
267
+ const helpMessage = [
268
+ '## Available Commands',
269
+ '',
270
+ '### `/deploy-review-app`',
271
+ 'Deploys your PR branch to a review environment on Control Plane.',
272
+ '- Creates a new review app if one doesn\'t exist',
273
+ '- Updates the existing review app if it already exists',
274
+ '- Provides a unique URL to preview your changes',
275
+ '- Shows build and deployment progress in real-time',
276
+ '',
277
+ '### `/delete-review-app`',
278
+ 'Deletes the review app associated with this PR.',
279
+ '- Removes all resources from Control Plane',
280
+ '- Helpful for cleaning up when you\'re done testing',
281
+ '- Can be re-deployed later using `/deploy-review-app`',
282
+ '',
283
+ '### `/help`',
284
+ 'Shows this help message explaining available commands.',
285
+ '',
286
+ '---',
287
+ '_Note: These commands only work in pull request comments._'
288
+ ].join('\n');
289
+
290
+ await github.rest.issues.createComment({
291
+ owner: context.repo.owner,
292
+ repo: context.repo.repo,
293
+ issue_number: context.payload.issue.number,
294
+ body: helpMessage
140
295
});
0 commit comments