From 4b8642b9725b9b3ede5f52b5379518cf815a7b5e Mon Sep 17 00:00:00 2001 From: nuno maduro Date: Fri, 1 May 2026 00:48:31 +0100 Subject: [PATCH] wip --- src/Plugins/Tia.php | 15 +++++++++++- src/Plugins/Tia/Storage.php | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Plugins/Tia.php b/src/Plugins/Tia.php index edfaef53..40368dae 100644 --- a/src/Plugins/Tia.php +++ b/src/Plugins/Tia.php @@ -17,6 +17,7 @@ use Pest\Plugins\Tia\Graph; use Pest\Plugins\Tia\JsModuleGraph; use Pest\Plugins\Tia\Recorder; use Pest\Plugins\Tia\ResultCollector; +use Pest\Plugins\Tia\Storage; use Pest\Plugins\Tia\TableExtractor; use Pest\Plugins\Tia\WatchPatterns; use Pest\Exceptions\NoAffectedTestsFound; @@ -558,6 +559,18 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable $fingerprint = Fingerprint::compute($projectRoot); + // `--fresh` is meant to be a clean slate: nuke the entire per-project + // state dir up front (graph, baseline, worker partials, fingerprint, + // JS module cache, coverage marker, etc.). Wiping per-key in code + // would leave room for stale entries we forgot about — most + // recently, status-7/8 result entries with no `file` that survived + // a rebuild and kept tripping `hasUnlocatedFailuresOrErrors()` on + // subsequent `--filtered` runs. Safe here because `handleParent` + // runs in the parent before any worker is spawned. + if ($forceRebuild) { + Storage::purge($projectRoot); + } + $graph = $forceRebuild ? null : $this->loadGraph($projectRoot); if ($graph instanceof Graph) { @@ -782,7 +795,7 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable if ($graph->hasUnlocatedFailuresOrErrors($this->branch)) { $this->output->writeln([ '', - ' TIA cached failures/errors exist but this baseline cannot map them to files — running full suite.', + ' TIA cached failures/errors exist but this baseline cannot map them to files — running full suite. Re-run with --fresh to rebuild the baseline.', '', ]); diff --git a/src/Plugins/Tia/Storage.php b/src/Plugins/Tia/Storage.php index d26e6fa4..54c02b34 100644 --- a/src/Plugins/Tia/Storage.php +++ b/src/Plugins/Tia/Storage.php @@ -51,6 +51,53 @@ final class Storage .DIRECTORY_SEPARATOR.self::projectKey($projectRoot); } + /** + * Wipes the on-disk state directory for `$projectRoot`. Called by + * `--fresh` so a rebuild starts from a truly empty cache: no stale + * baseline, no leftover worker partials, no fingerprint, no JS + * module cache. Subsequent writes recreate the directory on demand. + * + * Per-project (project key is part of the path) — sibling projects' + * caches under `~/.pest/tia/` are untouched. + */ + public static function purge(string $projectRoot): void + { + $dir = self::tempDir($projectRoot); + + if (! is_dir($dir)) { + return; + } + + self::removeRecursive($dir); + } + + private static function removeRecursive(string $dir): void + { + $entries = @scandir($dir); + + if ($entries === false) { + return; + } + + foreach ($entries as $entry) { + if ($entry === '.' || $entry === '..') { + continue; + } + + $path = $dir.DIRECTORY_SEPARATOR.$entry; + + if (is_dir($path) && ! is_link($path)) { + self::removeRecursive($path); + + continue; + } + + @unlink($path); + } + + @rmdir($dir); + } + /** * OS-neutral home directory — `HOME` on Unix, `USERPROFILE` on * Windows. Returns null if neither resolves to an existing