@@ -26,66 +26,223 @@ outputs:
2626runs :
2727  using : " composite" 
2828  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+ 
2944name : Setup Environment 
3045      uses : ./.github/actions/setup-environment 
3146
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 
34110      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 
39114
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 
42137      shell : bash 
43138      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 }} 
72143        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