From 58dfb6da6458232158077515e55700d4a1761bb6 Mon Sep 17 00:00:00 2001 From: nuno maduro Date: Thu, 30 Apr 2026 22:12:53 +0100 Subject: [PATCH] wip --- src/Plugins/Tia.php | 23 +++++++ src/Plugins/Tia/Graph.php | 66 ++++++++++++++++++- src/Plugins/Tia/ResultCollector.php | 17 +++-- .../EnsureTiaResultsAreCollected.php | 2 +- 4 files changed, 100 insertions(+), 8 deletions(-) diff --git a/src/Plugins/Tia.php b/src/Plugins/Tia.php index 113fdf4f..edf5794f 100644 --- a/src/Plugins/Tia.php +++ b/src/Plugins/Tia.php @@ -768,6 +768,23 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable $affected = $changed === [] ? [] : $graph->affected($changed); + if ($this->filteredMode) { + if ($graph->hasUnlocatedFailuresOrErrors($this->branch)) { + $this->output->writeln([ + '', + ' TIA cached failures/errors exist but this baseline cannot map them to files — running full suite.', + '', + ]); + + return $arguments; + } + + $affected = array_values(array_unique([ + ...$affected, + ...$graph->failedOrErroredTestFiles($this->branch), + ])); + } + $affectedSet = array_fill_keys($affected, true); $canRefreshReplayEdges = $affected !== [] && $coverageAvailable; @@ -1032,6 +1049,10 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable 'time' => is_float($result['time'] ?? null) || is_int($result['time'] ?? null) ? (float) $result['time'] : 0.0, 'assertions' => is_int($result['assertions'] ?? null) ? $result['assertions'] : 0, ]; + + if (isset($result['file']) && is_string($result['file'])) { + $normalised[$testId]['file'] = $result['file']; + } } if ($normalised !== []) { @@ -1178,6 +1199,7 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable $result['message'], $result['time'], $result['assertions'], + $result['file'] ?? null, ); } @@ -1211,6 +1233,7 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable $result['message'], $result['time'], $result['assertions'], + $result['file'] ?? null, ); } diff --git a/src/Plugins/Tia/Graph.php b/src/Plugins/Tia/Graph.php index a7e15681..6d04c5a5 100644 --- a/src/Plugins/Tia/Graph.php +++ b/src/Plugins/Tia/Graph.php @@ -43,7 +43,7 @@ final class Graph * @var array, - * results: array + * results: array * }> */ private array $baselines = []; @@ -468,7 +468,7 @@ final class Graph $this->baselines[$branch]['sha'] = $sha; } - public function setResult(string $branch, string $testId, int $status, string $message, float $time, int $assertions = 0): void + public function setResult(string $branch, string $testId, int $status, string $message, float $time, int $assertions = 0, ?string $file = null): void { $this->ensureBaseline($branch); $this->baselines[$branch]['results'][$testId] = [ @@ -477,6 +477,14 @@ final class Graph 'time' => $time, 'assertions' => $assertions, ]; + + if ($file !== null) { + $rel = $this->relative($file); + + if ($rel !== null) { + $this->baselines[$branch]['results'][$testId]['file'] = $rel; + } + } } public function getAssertions(string $branch, string $testId, string $fallbackBranch = 'main'): ?int @@ -517,6 +525,58 @@ final class Graph }; } + /** + * @return array + */ + public function failedOrErroredTestFiles(string $branch, string $fallbackBranch = 'main'): array + { + $baseline = $this->baselineFor($branch, $fallbackBranch); + $files = []; + + foreach ($baseline['results'] as $result) { + $status = $result['status'] ?? null; + + if ($status !== 7 && $status !== 8) { + continue; + } + + $file = $result['file'] ?? null; + + if (! is_string($file) || $file === '') { + continue; + } + + $rel = $this->relative($file); + + if ($rel !== null) { + $files[$rel] = true; + } + } + + return array_keys($files); + } + + public function hasUnlocatedFailuresOrErrors(string $branch, string $fallbackBranch = 'main'): bool + { + $baseline = $this->baselineFor($branch, $fallbackBranch); + + foreach ($baseline['results'] as $result) { + $status = $result['status'] ?? null; + + if ($status !== 7 && $status !== 8) { + continue; + } + + $file = $result['file'] ?? null; + + if (! is_string($file) || $file === '' || $this->relative($file) === null) { + return true; + } + } + + return false; + } + /** * @param array $tree project-relative path → content hash */ @@ -542,7 +602,7 @@ final class Graph } /** - * @return array{sha: ?string, tree: array, results: array} + * @return array{sha: ?string, tree: array, results: array} */ private function baselineFor(string $branch, string $fallbackBranch): array { diff --git a/src/Plugins/Tia/ResultCollector.php b/src/Plugins/Tia/ResultCollector.php index 434b4220..79411b0e 100644 --- a/src/Plugins/Tia/ResultCollector.php +++ b/src/Plugins/Tia/ResultCollector.php @@ -14,17 +14,20 @@ namespace Pest\Plugins\Tia; final class ResultCollector { /** - * @var array + * @var array */ private array $results = []; private ?string $currentTestId = null; + private ?string $currentTestFile = null; + private ?float $startTime = null; - public function testPrepared(string $testId): void + public function testPrepared(string $testId, ?string $testFile = null): void { $this->currentTestId = $testId; + $this->currentTestFile = $testFile; $this->startTime = microtime(true); } @@ -83,7 +86,7 @@ final class ResultCollector } /** - * @return array + * @return array */ public function all(): array { @@ -102,7 +105,7 @@ final class ResultCollector * workers) into this collector so the parent can persist them in the same * snapshot pass as non-parallel runs. * - * @param array $results + * @param array $results */ public function merge(array $results): void { @@ -115,6 +118,7 @@ final class ResultCollector { $this->results = []; $this->currentTestId = null; + $this->currentTestFile = null; $this->startTime = null; } @@ -126,6 +130,7 @@ final class ResultCollector public function finishTest(): void { $this->currentTestId = null; + $this->currentTestFile = null; $this->startTime = null; } @@ -151,5 +156,9 @@ final class ResultCollector 'time' => $time, 'assertions' => $existing['assertions'] ?? 0, ]; + + if ($this->currentTestFile !== null) { + $this->results[$this->currentTestId]['file'] = $this->currentTestFile; + } } } diff --git a/src/Subscribers/EnsureTiaResultsAreCollected.php b/src/Subscribers/EnsureTiaResultsAreCollected.php index 7d432865..d0f6a772 100644 --- a/src/Subscribers/EnsureTiaResultsAreCollected.php +++ b/src/Subscribers/EnsureTiaResultsAreCollected.php @@ -29,7 +29,7 @@ final readonly class EnsureTiaResultsAreCollected implements PreparedSubscriber $test = $event->test(); if ($test instanceof TestMethod) { - $this->collector->testPrepared($test->className().'::'.$test->methodName()); + $this->collector->testPrepared($test->className().'::'.$test->methodName(), $test->file()); } } }