Skip to content

Commit

Permalink
gh-18 fix(MultiProcessExecution) Improved error output when crashes s…
Browse files Browse the repository at this point in the history
…ome tool
  • Loading branch information
Wtyd committed Jan 11, 2025
1 parent e9b1bea commit 11d3f98
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 63 deletions.
32 changes: 24 additions & 8 deletions src/Tools/Process/Execution/MultiProcessesExecution.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Wtyd\GitHooks\Tools\Process\Execution;

use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Throwable;
use Wtyd\GitHooks\Tools\Errors;
use Wtyd\GitHooks\Tools\Process\Process;

Expand All @@ -29,19 +31,26 @@ public function runProcesses(): Errors
do {
try {
$this->addProcessToQueue();

foreach ($this->runningProcesses as $toolName => $process) {
if (!$process->isTerminated()) {
continue;
// $process->checkTimeout(); // timeout is null for now
// throw new \Exception('asdfasdf');
if ($process->isTerminated()) {
$this->numberOfRunnedProcesses = $this->finishExecution($process, $toolName);
}
$this->numberOfRunnedProcesses = $this->finishExecution($process, $toolName);
}
} catch (ProcessTimedOutException $th) {
$toolName = (string)array_search($th->getProcess(), $this->processes);
$this->numberOfRunnedProcesses = $this->finishExecution($th->getProcess(), $toolName, $th->getMessage());
} catch (ProcessFailedException $th) {
// dd($this->numberOfRunnedProcesses);
$toolName = (string)array_search($th->getProcess(), $this->processes);
$this->numberOfRunnedProcesses = $this->finishExecution($th->getProcess(), $toolName);
} catch (Throwable $th) {
$this->errors->setError('Tool crash', $th->getMessage());
}
} while ($totalProcesses > $this->numberOfRunnedProcesses);
} catch (\Throwable $th) {
// dd($th->getMessage(), get_class($th), $th->getFile(), $th->getLine());
$this->errors->setError('General', $th->getMessage());
}
$endCommandExecution = microtime(true);
Expand All @@ -50,6 +59,9 @@ public function runProcesses(): Errors
return $this->errors;
}

/**
* Add process to queue of running processes
*/
protected function addProcessToQueue(): void
{
foreach ($this->processes as $toolName => $process) {
Expand All @@ -65,7 +77,8 @@ protected function addProcessToQueue(): void

/**
* Finish process execution
*
* ¡¡¡Warning with egde case!!! Sometimes the process finishes with an error message in the normal output
* (sintaxys errors in Phpmd 2.9 or minus, for example) but the error output is empty.
* @param Process $process
* @param string $toolName Name of the process.
* @param string $exceptionMessage
Expand All @@ -75,16 +88,19 @@ protected function finishExecution(Process $process, string $toolName, string $e
{
$this->runnedProcesses[$toolName] = $process;
$executionTime = $this->executionTime($process->getLastOutputTime(), $process->getStartTime());

if ($process->isSuccessful()) {
$this->printer->resultSuccess($this->getSuccessString($toolName, $executionTime));
} else {
$errorMessage = $exceptionMessage ?? $process->getOutput();
$errorMessage = '';
// if ($process->isTerminated()) { // TODO: comprobar a fondo estas lineas
$errorMessage = $exceptionMessage ?? $process->getErrorOutput();
$errorMessage = empty($errorMessage) ? $process->getOutput() : $errorMessage; // Edge case
// }
if (!$this->tools[$toolName]->isIgnoreErrorsOnExit()) {
$this->errors->setError($toolName, $errorMessage);
}
$this->printer->resultError($this->getErrorString($toolName, $executionTime));

$this->printer->resultError($this->getErrorString($toolName, $executionTime));
$this->printer->line($errorMessage);
}
unset($this->runningProcesses[$toolName]);
Expand Down
3 changes: 3 additions & 0 deletions src/Tools/Process/Execution/ProcessExecution.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ class ProcessExecution extends ProcessExecutionAbstract
{
public function runProcesses(): Errors
{
if (empty($this->tools)) {
return $this->errors;
}
$toolName = array_keys($this->tools)[0];
$process = $this->processes[$toolName];

Expand Down
9 changes: 1 addition & 8 deletions src/Tools/Process/Execution/ProcessExecutionAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,8 @@ public function execute(array $tools, int $threads): Errors
{
$this->tools = $tools;
$this->threads = $threads;

$this->createProcesses();

try {
return $this->runProcesses();
} catch (\Throwable $th) {
$this->errors->setError('General', $th->getMessage());
return $this->errors;
}
return $this->runProcesses();
}

abstract protected function runProcesses(): Errors;
Expand Down
51 changes: 51 additions & 0 deletions src/Tools/Process/ExecutionFakeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ trait ExecutionFakeTrait
/** @var array<\Wtyd\GitHooks\Tools\Tool\ToolAbstact> */
protected $toolsThatMustFail = [];

/** @var array<\Wtyd\GitHooks\Tools\Tool\ToolAbstact> */
protected $failedToolsByException = [];

/** @var array<\Wtyd\GitHooks\Tools\Tool\ToolAbstact> */
protected $failedToolsByFoundedErrors = [];

/** @var array<\Wtyd\GitHooks\Tools\Tool\ToolAbstact> */
protected $setFailByFoundedErrorsInNormalOutput = [];

/** @var array<\Wtyd\GitHooks\Tools\Tool\ToolAbstact> */
protected $toolsWithTimeout = [];

Expand All @@ -26,18 +35,60 @@ protected function createProcesses(): void
foreach ($this->toolsThatMustFail as $tool) {
$this->processes[$tool]->setFail();
}

foreach ($this->failedToolsByException as $tool) {
$this->processes[$tool]->setFailByException();
}

foreach ($this->failedToolsByFoundedErrors as $tool) {
$this->processes[$tool]->setFailByFoundedErrors();
}

foreach ($this->setFailByFoundedErrorsInNormalOutput as $tool) {
$this->processes[$tool]->setFailByFoundedErrorsInNormalOutput();
}
foreach ($this->toolsWithTimeout as $tool) {
$this->processes[$tool]->triggerTimeout();
}
}

// // TODO deprecated?
public function setToolsThatMustFail(array $toolsThatMustFail): void
{
$this->toolsThatMustFail = $toolsThatMustFail;
}

public function failedToolsByException(array $failedToolsByException): void
{
$this->failedToolsByException = $failedToolsByException;
}

public function failedToolsByFoundedErrors(array $failedToolsByFoundedErrors): void
{
$this->failedToolsByFoundedErrors = $failedToolsByFoundedErrors;
}

public function setFailByFoundedErrorsInNormalOutput(array $setFailByFoundedErrorsInNormalOutput): void
{
$this->setFailByFoundedErrorsInNormalOutput = $setFailByFoundedErrorsInNormalOutput;
}

public function setToolsWithTimeout(array $toolsWithTimeout): void
{
$this->toolsWithTimeout = $toolsWithTimeout;
}

protected function addProcessToQueue(): void
{
foreach ($this->processes as $toolName => $process) {
if (count($this->runningProcesses) === $this->threads) {
break;
}
if (!in_array($process, $this->runningProcesses) && !in_array($process, $this->runnedProcesses)) {
$this->startProcess($process);
$this->runningProcesses[$toolName] = $process;
}
}
parent::addProcessToQueue();
}
}
82 changes: 70 additions & 12 deletions src/Tools/Process/ProcessFake.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Wtyd\GitHooks\Tools\Process;

use Symfony\Component\Process\Exception\ProcessFailedException;
use Wtyd\GitHooks\Tools\Tool\ToolAbstract;

class ProcessFake extends Process
Expand All @@ -18,9 +19,15 @@ class ProcessFake extends Process
private $isSuccessful = true;

/** @inheritDoc */
private $output;
protected $status;

/** @inheritDoc */
private $exitcode;

private $fakeTimeout = false;
private $outputFake;
private $errorOutputFake;
private $mustRaiseException = false;

/**
* Do nothing or invokes original method when we want to cause an error by timeout
Expand All @@ -34,6 +41,10 @@ public function start(callable $callback = null, array $env = [])
// Do nothing
$this->starttime = microtime(true);
}
$this->status = self::STATUS_STARTED;
if ($this->mustRaiseException) {
throw new ProcessFailedException($this);
}
}

/**
Expand Down Expand Up @@ -80,12 +91,26 @@ public function isSuccessful(): bool
}

/**
* Only in MultiProcessExecution when the execution fails
* @inheritDoc
*/
public function getOutput(): string
{
return $this->output;
// dd(! $this->isSuccessful, $this->outputFake);
if (! $this->isSuccessful) {
return $this->outputFake;
}
return '';
}

/**
* @inheritDoc
*/
public function getErrorOutput(): string
{
if (! $this->isSuccessful) {
return $this->errorOutputFake;
}
return '';
}

/**
Expand All @@ -97,17 +122,10 @@ public function wait(callable $callback = null): int
return $this->isSuccessful ? 0 : 1;
}

/**
* Mocks that the process fails.
*
* @return ProcessFake
*/
public function setFail(): ProcessFake
private function extractToolName(): string
{
$this->isSuccessful = false;
$ex = explode(' ', $this->getCommandLine());


$tools = array_keys(ToolAbstract::SUPPORTED_TOOLS);
$nameTool = '';
foreach ($tools as $tool) {
Expand All @@ -116,9 +134,49 @@ public function setFail(): ProcessFake
break;
}
}
return $nameTool;
}

/**
* Mocks that the process fails.
*
* @return ProcessFake
*/
public function setFail(): ProcessFake
{
$this->isSuccessful = false;
$nameTool = $this->extractToolName();

// getErrorOutput() o getOutput() o Exeception
$this->errorOutputFake = "\nThe tool $nameTool mocks an error\n";

return $this;
}

$this->output = "\nThe tool $nameTool mocks an error\n";
public function setFailByException(): ProcessFake
{
$this->isSuccessful = false;
$this->mustRaiseException = true;
$nameTool = $this->extractToolName();
$this->outputFake = $this->errorOutputFake = "$nameTool fakes an exception";
$this->exitcode = 1;
return $this;
}

public function setFailByFoundedErrors(): ProcessFake
{
$this->isSuccessful = false;
$nameTool = $this->extractToolName();
$this->errorOutputFake = "\n$nameTool fakes an error\n";
return $this;
}

public function setFailByFoundedErrorsInNormalOutput(): ProcessFake
{
$this->isSuccessful = false;
$nameTool = $this->extractToolName();
$this->outputFake = "\n$nameTool fakes an error in normal output\n";
$this->errorOutputFake = '';
return $this;
}

Expand Down
Loading

0 comments on commit 11d3f98

Please sign in to comment.