Skip to content

Commit

Permalink
Improve activity log formatting (#1291)
Browse files Browse the repository at this point in the history
- Prioritize displaying the log if there is one non-integration activity
- Add a newline before waiting
- Standardize how activity descriptions are displayed
  • Loading branch information
pjcdawkins authored Jul 24, 2023
1 parent 88d07aa commit 94fc4ef
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 30 deletions.
6 changes: 1 addition & 5 deletions src/Command/Activity/ActivityCancelCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$activity = $byId[$id];
}

$this->stdErr->writeln(sprintf(
'Cancelling the activity <info>%s</info> (%s)...',
$activity->id,
ActivityMonitor::getFormattedDescription($activity)
));
$this->stdErr->writeln('Cancelling the activity ' . ActivityMonitor::getFormattedDescription($activity, true, true, 'cyan'));

try {
$activity->cancel();
Expand Down
1 change: 0 additions & 1 deletion src/Command/Environment/EnvironmentResumeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
if (!$questionHelper->confirm('Are you sure you want to resume the paused environment <comment>' . $environment->id . '</comment>?')) {
return 1;
}
$this->stdErr->writeln('');

$result = $environment->runOperation('resume');
$this->api()->clearEnvironmentsCache($environment->project);
Expand Down
74 changes: 50 additions & 24 deletions src/Service/ActivityMonitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,8 @@ public function waitAndLog(Activity $activity, $pollInterval = 3, $timestamps =
$logOutput = $logOutput ?: $stdErr;

if ($context) {
$stdErr->writeln(sprintf(
'Waiting for the activity <info>%s</info> (%s):',
$activity->id,
self::getFormattedDescription($activity)
));
$stdErr->writeln('');
$stdErr->writeln('Waiting for the activity: ' . self::getFormattedDescription($activity, true, true, 'cyan'));
$stdErr->writeln('');
}

Expand Down Expand Up @@ -205,23 +202,24 @@ public function waitAndLog(Activity $activity, $pollInterval = 3, $timestamps =
}
$bar->finish();
$stdErr->writeln('');
$stdErr->writeln('');

// Display the success or failure messages.
switch ($activity->result) {
case Activity::RESULT_SUCCESS:
$stdErr->writeln("Activity <info>{$activity->id}</info> succeeded");
$stdErr->writeln('The activity succeeded: ' . self::getFormattedDescription($activity, true, true, 'green'));
return true;

case Activity::RESULT_FAILURE:
if ($activity->state === Activity::STATE_CANCELLED) {
$stdErr->writeln("The activity <error>{$activity->id}</error> was cancelled");
$stdErr->writeln('The activity was cancelled: ' . self::getFormattedDescription($activity, true, true, 'yellow'));
} else {
$stdErr->writeln("Activity <error>{$activity->id}</error> failed");
$stdErr->writeln('The activity failed: ' . self::getFormattedDescription($activity, true, true, 'red'));
}
return false;
}

$stdErr->writeln("The log for activity <info>{$activity->id}</info> finished with an unknown result");
$stdErr->writeln('The activity finished with an unknown result: ' . self::getFormattedDescription($activity, true, true, 'yellow'));

return false;
}
Expand Down Expand Up @@ -290,16 +288,33 @@ public function waitMultiple(array $activities, Project $project)
{
$stdErr = $this->getStdErr();

// If there is 1 activity then display its log.
$count = count($activities);
if ($count == 0) {
return true;
} elseif ($count === 1) {
return $this->waitAndLog(reset($activities));
}

// If there is 1 non-integration activity, then display its log, and
// wait for the integration activities separately.
$nonIntegrationActivities = array_filter($activities, function (Activity $a) {
return strpos($a->type, 'integration.') !== 0;
});
if (count($nonIntegrationActivities) === 1) {
$nonIntegrationActivity = reset($nonIntegrationActivities);
$integrationActivities = array_filter($activities, function (Activity $a) {
return strpos($a->type, 'integration.') === 0;
});
$nonIntegrationSuccess = $this->waitAndLog($nonIntegrationActivity);
$integrationSuccess = $this->waitMultiple($integrationActivities, $project);
return $nonIntegrationSuccess && $integrationSuccess;
}

// For more than one activity, display a progress bar with the status of each.
$stdErr->writeln(sprintf('Waiting for %d activities...', $count));
foreach ($activities as $activity) {
$stdErr->writeln(sprintf(' <info>%s</info>: %s', $activity->id, self::getFormattedDescription($activity)));
$stdErr->writeln(' ', self::getFormattedDescription($activity, true, true, 'cyan'));
}

// The progress bar will show elapsed time and all of the activities'
Expand Down Expand Up @@ -366,19 +381,18 @@ public function waitMultiple(array $activities, Project $project)
// Display success or failure messages for each activity.
$success = true;
foreach ($activities as $activity) {
$description = self::getFormattedDescription($activity);
switch ($activity['result']) {
case Activity::RESULT_SUCCESS:
$stdErr->writeln(sprintf('Activity <info>%s</info> succeeded: %s', $activity->id, $description));
$stdErr->writeln('Activity succeeded: ' . self::getFormattedDescription($activity, true, true, 'green'));
break;

case Activity::RESULT_FAILURE:
$success = false;
$stdErr->writeln(sprintf('Activity <error>%s</error> failed', $activity->id));
$stdErr->writeln(sprintf('Activity failed: <error>%s</error>', $activity->id));

// If the activity failed, show the complete log.
$stdErr->writeln(' Description: ' . $description);
$stdErr->writeln(' Log:');
$stdErr->writeln(' <error>Description:</error> ' . self::getFormattedDescription($activity));
$stdErr->writeln(' <error>Log:</error>');
$stdErr->writeln($this->indent($this->formatLog($activity->readLog())));
break;
}
Expand Down Expand Up @@ -435,31 +449,43 @@ protected function newProgressBar(OutputInterface $output)
/**
* Get the formatted description of an activity.
*
* @param \Platformsh\Client\Model\Activity $activity
* @param bool $withDecoration
* @param \Platformsh\Client\Model\Activity $activity The activity.
* @param bool $withDecoration Add decoration to activity tags.
* @param bool $withId Add the activity ID.
* @param string $fgColor Define a foreground color e.g. 'green', 'red', 'cyan'.
*
* @return string
*/
public static function getFormattedDescription(Activity $activity, $withDecoration = true)
public static function getFormattedDescription(Activity $activity, $withDecoration = true, $withId = false, $fgColor = '')
{
if (!$withDecoration) {
if ($withId) {
return '[' . $activity->id . '] ' . $activity->getDescription(false);
}
return $activity->getDescription(false);
}
$value = $activity->getDescription(true);
$descr = $activity->getDescription(true);

// Replace description HTML elements with Symfony Console decoration
// tags.
$value = preg_replace('@<[^/][^>]+>@', '<options=underscore>', $value);
$value = preg_replace('@</[^>]+>@', '</>', $value);
$descr = preg_replace('@<[^/][^>]+>@', '<options=underscore>', $descr);
$descr = preg_replace('@</[^>]+>@', '</>', $descr);

// Replace literal tags like "&lt;info&;gt;" with escaped tags like
// "\<info>".
$value = preg_replace('@&lt;(/?[a-z][a-z0-9,_=;-]*+)&gt;@i', '\\\<$1>', $value);
$descr = preg_replace('@&lt;(/?[a-z][a-z0-9,_=;-]*+)&gt;@i', '\\\<$1>', $descr);

// Decode other HTML entities.
$value = html_entity_decode($value, ENT_QUOTES, 'utf-8');
$descr = html_entity_decode($descr, ENT_QUOTES, 'utf-8');

if ($withId) {
if ($fgColor) {
return sprintf('<fg=%s>[%s]</> %s', $fgColor, $activity->id, $descr);
}
return sprintf('[%s] %s', $activity->id, $descr);
}

return $value;
return $descr;
}

/**
Expand Down

0 comments on commit 94fc4ef

Please sign in to comment.