Skip to content

Commit ee23aee

Browse files
Re-implement --commit parameter
1 parent 9314402 commit ee23aee

File tree

1 file changed

+178
-70
lines changed

1 file changed

+178
-70
lines changed

src/Commands/Workflow/WaitCommand.php

Lines changed: 178 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
use Pantheon\Terminus\Site\SiteAwareInterface;
77
use Pantheon\Terminus\Site\SiteAwareTrait;
88
use Pantheon\Terminus\Exceptions\TerminusException;
9+
use Pantheon\Terminus\Request\RequestAwareInterface;
10+
use Pantheon\Terminus\Request\RequestAwareTrait;
911

1012
/**
1113
* Class AwaitCommand.
1214
*
1315
* @package Pantheon\Terminus\Commands\Workflow
1416
*/
15-
class WaitCommand extends TerminusCommand implements SiteAwareInterface
17+
class WaitCommand extends TerminusCommand implements SiteAwareInterface, RequestAwareInterface
1618
{
1719
use SiteAwareTrait;
20+
use RequestAwareTrait;
1821

1922
/**
2023
* Wait for a workflow to complete. Usually this will be used to wait
@@ -28,13 +31,15 @@ class WaitCommand extends TerminusCommand implements SiteAwareInterface
2831
* @param $site_env_id The pantheon site to wait for.
2932
* @param $description The workflow description to wait for. Optional; default is code sync.
3033
* @option start Ignore any workflows started prior to the start time (epoch)
34+
* @option commit Commit sha to wait for
3135
* @option max Maximum number of seconds to wait for the workflow to complete
3236
*/
3337
public function workflowWait(
3438
$site_env_id,
3539
$description = '',
3640
$options = [
3741
'start' => 0,
42+
'commit' => '',
3843
'max' => 180,
3944
]
4045
) {
@@ -65,10 +70,12 @@ public function workflowWait(
6570
if (!$startTime) {
6671
$startTime = time() - 60;
6772
}
68-
// if (!empty($options['commit'])) {
69-
// $this->waitForCommit($startTime, $site, $env_name, $options['commit'], $options['max']);
70-
// return;
71-
// }
73+
74+
if (!empty($options['commit'])) {
75+
$this->waitForCommit($startTime, $site, $env_name, $options['commit'], $options['max']);
76+
return;
77+
}
78+
7279
$this->waitForWorkflow($startTime, $site, $env_name, $description, $options['max']);
7380
}
7481

@@ -175,69 +182,170 @@ protected function waitForWorkflow(
175182
/**
176183
* Wait for a workflow with a given commit to complete.
177184
*/
178-
// public function waitForCommit(
179-
// $startTime,
180-
// $site,
181-
// $env_name,
182-
// $target_commit,
183-
// $maxWaitInSeconds = 180,
184-
// $maxNotFoundAttempts = null
185-
// ) {
186-
// $wfl = null;
187-
// $wflc = $site->getWorkflowLogs();
188-
// if (!$wflc instanceof WorkflowLogsCollection) {
189-
// throw new TerminusException(
190-
// 'Workflow logs could not be retrieved for site: {site}',
191-
// ['site' => $site->id,]
192-
// );
193-
// }
194-
195-
// // Remove workflows that are not for the environment $env_name.
196-
// $wflc->filterForEnvironment($env_name);
197-
198-
// // Find the latest workflow that matches the commit hash
199-
// $wfl = $wflc->findLatestFromOptionsArray([
200-
// 'target_commit' => $target_commit,
201-
// ]);
202-
203-
// $current_time = time();
204-
// if ($maxWaitInSeconds > 0) {
205-
// $end_time = $current_time + $maxWaitInSeconds;
206-
// } else {
207-
// $end_time = 0;
208-
// }
209-
210-
// // If we didn't find a workflow, then we need to wait for one to be created
211-
// if (!$wfl instanceof WorkflowLog) {
212-
// // sleep to give the workflow time to be created
213-
// sleep($this->getConfig()->get('refresh_workflow_delay', 30));
214-
// $wfl = $wflc->fetch()->findLatestFromOptionsArray([
215-
// 'target_commit' => $target_commit,
216-
// ]);
217-
// $current_time = time();
218-
// if ($end_time > 0 && $current_time >= $end_time) {
219-
// throw new TerminusException(
220-
// 'Exceeded maximum wait time of {max} seconds.',
221-
// ['max' => $maxWaitInSeconds]
222-
// );
223-
// }
224-
// }
225-
226-
// while (!$wfl->isFinished()) {
227-
// $current_time = time();
228-
// if ($end_time > 0 && $current_time >= $end_time) {
229-
// throw new TerminusException(
230-
// 'Exceeded maximum wait time of {max} seconds.',
231-
// ['max' => $maxWaitInSeconds]
232-
// );
233-
// }
234-
// $this->log()->notice('Waiting for workflow {id} to complete.', ['id' => $wfl->id,]);
235-
// sleep($this->getConfig()->get('refresh_workflow_delay', 30));
236-
// $wfl->fetch();
237-
// }
238-
// $this->log()->notice('Workflow {id} has completed with status {status}.', [
239-
// 'id' => $wfl->id,
240-
// 'status' => $wfl->get('status'),
241-
// ]);
242-
// }
185+
protected function waitForCommit(
186+
$startTime,
187+
$site,
188+
$env_name,
189+
$target_commit,
190+
$maxWaitInSeconds = 180
191+
) {
192+
$current_time = time();
193+
if ($maxWaitInSeconds > 0) {
194+
$end_time = $current_time + $maxWaitInSeconds;
195+
} else {
196+
$end_time = 0;
197+
}
198+
199+
// Validate commit SHA format
200+
if (!preg_match('/^[0-9a-f]{40}$/', $target_commit)) {
201+
throw new TerminusException(
202+
'Commit {commit} is not a valid commit SHA.',
203+
['commit' => $target_commit]
204+
);
205+
}
206+
207+
$this->log()->notice('Waiting for workflow with commit {commit} on environment {env}.', [
208+
'commit' => $target_commit,
209+
'env' => $env_name
210+
]);
211+
212+
213+
$workflow = null;
214+
$retry_count = 0;
215+
$max_retries = 10;
216+
217+
do {
218+
$current_time = time();
219+
220+
// Check timeout
221+
if ($end_time > 0 && $current_time >= $end_time) {
222+
throw new TerminusException(
223+
'Workflow with commit {commit} timed out after {timeout} seconds.',
224+
['commit' => $target_commit, 'timeout' => $maxWaitInSeconds]
225+
);
226+
}
227+
228+
// Fetch workflow logs using the logs/workflows endpoint
229+
$response = $this->request()->request("sites/{$site->id}/logs/workflows");
230+
$workflow_logs = $response['data'] ?? [];
231+
232+
$this->log()->debug('Found {count} total workflow logs', ['count' => count($workflow_logs)]);
233+
234+
// Filter for the target environment and commit
235+
$matching_workflows = [];
236+
237+
foreach ($workflow_logs as $log) {
238+
// Check if this workflow is for the target environment
239+
if (isset($log->workflow->environment) && $log->workflow->environment === $env_name) {
240+
// Check if this workflow has the target commit
241+
if (isset($log->workflow->target_commit) && $log->workflow->target_commit === $target_commit) {
242+
// Check if workflow started after our start time
243+
if (isset($log->workflow->started_at) && $log->workflow->started_at >= $startTime) {
244+
$matching_workflows[] = $log;
245+
}
246+
}
247+
}
248+
}
249+
250+
$this->log()->debug('Found {count} matching workflows for commit {commit} on env {env}', [
251+
'count' => count($matching_workflows),
252+
'commit' => $target_commit,
253+
'env' => $env_name
254+
]);
255+
256+
// Find the most recent matching workflow
257+
if (!empty($matching_workflows)) {
258+
// Sort by started_at descending to get the most recent
259+
usort($matching_workflows, function($a, $b) {
260+
return $b->workflow->started_at <=> $a->workflow->started_at;
261+
});
262+
263+
$workflow = $matching_workflows[0];
264+
$this->log()->notice('Found workflow {id} with description "{description}" for commit {commit}', [
265+
'id' => $workflow->workflow->id,
266+
'description' => $workflow->workflow->description ?? 'N/A',
267+
'commit' => $target_commit
268+
]);
269+
break;
270+
}
271+
272+
$retry_count++;
273+
if ($retry_count >= $max_retries) {
274+
throw new TerminusException(
275+
'Workflow with commit {commit} not found after {retries} attempts.',
276+
['commit' => $target_commit, 'retries' => $max_retries]
277+
);
278+
}
279+
280+
$this->log()->debug('Workflow not found, retrying... ({retry}/{max})', [
281+
'retry' => $retry_count,
282+
'max' => $max_retries
283+
]);
284+
sleep(5);
285+
286+
} while (!$workflow);
287+
288+
// Now wait for the workflow to complete
289+
$this->log()->notice('Waiting for workflow {id} to complete...', ['id' => $workflow->workflow->id]);
290+
291+
$retry_interval = $this->getConfig()->get('workflow_polling_delay_ms', 5000);
292+
if ($retry_interval < 1000) {
293+
$retry_interval = 1000;
294+
}
295+
296+
do {
297+
$current_time = time();
298+
if ($end_time > 0 && $current_time >= $end_time) {
299+
throw new TerminusException(
300+
'Workflow timed out after {timeout} seconds.',
301+
['timeout' => $maxWaitInSeconds]
302+
);
303+
}
304+
305+
// Re-fetch workflow logs to get updated status
306+
$response = $this->request()->request("sites/{$site->id}/logs/workflows");
307+
$workflow_logs = $response['data'] ?? [];
308+
309+
// Find our specific workflow
310+
$updated_workflow = null;
311+
foreach ($workflow_logs as $log) {
312+
if ($log->workflow->id === $workflow->workflow->id) {
313+
$updated_workflow = $log;
314+
break;
315+
}
316+
}
317+
318+
if (!$updated_workflow) {
319+
throw new TerminusException('Workflow {id} disappeared during execution.', ['id' => $workflow->workflow->id]);
320+
}
321+
322+
$workflow = $updated_workflow;
323+
324+
$this->log()->debug('Workflow {id} status: {status}', [
325+
'id' => $workflow->workflow->id,
326+
'status' => $workflow->workflow->status ?? 'unknown'
327+
]);
328+
329+
// Check if workflow is finished
330+
if (isset($workflow->workflow->status) && in_array($workflow->workflow->status, ['Success', 'Failed', 'Aborted'])) {
331+
break;
332+
}
333+
334+
usleep($retry_interval * 1000);
335+
336+
} while (true);
337+
338+
// Check if workflow succeeded
339+
if ($workflow->workflow->status !== 'Success') {
340+
throw new TerminusException(
341+
'Workflow {id} failed with status: {status}',
342+
['id' => $workflow->workflow->id, 'status' => $workflow->workflow->status]
343+
);
344+
}
345+
346+
$this->log()->notice('Workflow {id} completed successfully for commit {commit}', [
347+
'id' => $workflow->workflow->id,
348+
'commit' => $target_commit
349+
]);
350+
}
243351
}

0 commit comments

Comments
 (0)