mirror of
https://github.com/pestphp/pest.git
synced 2026-06-05 10:52:14 +02:00
release: v4.7.0
This commit is contained in:
@ -1362,7 +1362,16 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
/** @var ResultCollector $collector */
|
||||
$collector = Container::getInstance()->get(ResultCollector::class);
|
||||
|
||||
foreach ($collector->all() as $testId => $result) {
|
||||
$results = $collector->all();
|
||||
$touchedFiles = [];
|
||||
|
||||
foreach ($results as $testId => $result) {
|
||||
$file = $result['file'] ?? null;
|
||||
|
||||
if (is_string($file) && $file !== '') {
|
||||
$touchedFiles[$file] = true;
|
||||
}
|
||||
|
||||
$graph->setResult(
|
||||
$this->branch,
|
||||
$testId,
|
||||
@ -1370,10 +1379,12 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
$result['message'],
|
||||
$result['time'],
|
||||
$result['assertions'],
|
||||
$result['file'] ?? null,
|
||||
$file,
|
||||
);
|
||||
}
|
||||
|
||||
$graph->pruneStaleResults($this->branch, array_keys($touchedFiles), array_keys($results));
|
||||
|
||||
$collector->reset();
|
||||
}
|
||||
|
||||
@ -1396,6 +1407,8 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
return;
|
||||
}
|
||||
|
||||
$touchedFiles = [];
|
||||
|
||||
foreach ($results as $testId => $result) {
|
||||
$file = $result['file'] ?? null;
|
||||
|
||||
@ -1403,6 +1416,10 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
$file = $this->resolveFailedTestFile($testId);
|
||||
}
|
||||
|
||||
if (is_string($file) && $file !== '') {
|
||||
$touchedFiles[$file] = true;
|
||||
}
|
||||
|
||||
$graph->setResult(
|
||||
$this->branch,
|
||||
$testId,
|
||||
@ -1414,6 +1431,8 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
);
|
||||
}
|
||||
|
||||
$graph->pruneStaleResults($this->branch, array_keys($touchedFiles), array_keys($results));
|
||||
|
||||
$this->saveGraph($graph);
|
||||
$collector->reset();
|
||||
}
|
||||
|
||||
@ -69,11 +69,6 @@ final readonly class BaselineSync
|
||||
$this->output->writeln(sprintf(' <fg=gray>─ %s</>', $text));
|
||||
}
|
||||
|
||||
private function renderChildContinuation(string $text): void
|
||||
{
|
||||
$this->output->writeln(sprintf(' <fg=gray> %s</>', $text));
|
||||
}
|
||||
|
||||
public function fetchIfAvailable(string $projectRoot, bool $force = false, bool $hasAnchor = false): bool
|
||||
{
|
||||
$repo = $this->detectGitHubRepo($projectRoot);
|
||||
|
||||
@ -195,49 +195,6 @@ final readonly class Fingerprint
|
||||
return $parts === [] ? null : hash('xxh128', implode("\n", $parts));
|
||||
}
|
||||
|
||||
private static function packageJsonHash(string $projectRoot): ?string
|
||||
{
|
||||
$path = $projectRoot.'/package.json';
|
||||
|
||||
if (! is_file($path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$raw = @file_get_contents($path);
|
||||
|
||||
if ($raw === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_decode($raw, true);
|
||||
|
||||
if (! is_array($data)) {
|
||||
$hash = @hash_file('xxh128', $path);
|
||||
|
||||
return $hash === false ? null : $hash;
|
||||
}
|
||||
|
||||
$relevant = [
|
||||
'type' => $data['type'] ?? null,
|
||||
'packageManager' => $data['packageManager'] ?? null,
|
||||
'dependencies' => $data['dependencies'] ?? null,
|
||||
'devDependencies' => $data['devDependencies'] ?? null,
|
||||
'optionalDependencies' => $data['optionalDependencies'] ?? null,
|
||||
'peerDependencies' => $data['peerDependencies'] ?? null,
|
||||
'overrides' => $data['overrides'] ?? null,
|
||||
'resolutions' => $data['resolutions'] ?? null,
|
||||
'imports' => $data['imports'] ?? null,
|
||||
'exports' => $data['exports'] ?? null,
|
||||
'browser' => $data['browser'] ?? null,
|
||||
];
|
||||
|
||||
self::sortRecursively($relevant);
|
||||
|
||||
$json = json_encode($relevant);
|
||||
|
||||
return $json === false ? null : hash('xxh128', $json);
|
||||
}
|
||||
|
||||
private static function composerLockHash(string $projectRoot): ?string
|
||||
{
|
||||
return self::trackedHash($projectRoot, 'composer.lock');
|
||||
@ -292,7 +249,7 @@ final readonly class Fingerprint
|
||||
return $cache[$key] = true;
|
||||
}
|
||||
|
||||
$finder = (new Finder())
|
||||
$finder = (new Finder)
|
||||
->in($projectRoot)
|
||||
->depth('== 0')
|
||||
->name($relativePath)
|
||||
@ -301,53 +258,6 @@ final readonly class Fingerprint
|
||||
return $cache[$key] = $finder->hasResults();
|
||||
}
|
||||
|
||||
private static function composerJsonHash(string $projectRoot): ?string
|
||||
{
|
||||
$path = $projectRoot.'/composer.json';
|
||||
|
||||
if (! is_file($path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$raw = @file_get_contents($path);
|
||||
|
||||
if ($raw === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_decode($raw, true);
|
||||
|
||||
if (! is_array($data)) {
|
||||
$hash = @hash_file('xxh128', $path);
|
||||
|
||||
return $hash === false ? null : $hash;
|
||||
}
|
||||
|
||||
$config = is_array($data['config'] ?? null) ? $data['config'] : [];
|
||||
$relevantConfig = array_intersect_key($config, [
|
||||
'platform' => true,
|
||||
'allow-plugins' => true,
|
||||
]);
|
||||
|
||||
$relevant = [
|
||||
'autoload' => $data['autoload'] ?? null,
|
||||
'autoload-dev' => $data['autoload-dev'] ?? null,
|
||||
'require' => $data['require'] ?? null,
|
||||
'require-dev' => $data['require-dev'] ?? null,
|
||||
'extra' => $data['extra'] ?? null,
|
||||
'repositories' => $data['repositories'] ?? null,
|
||||
'minimum-stability' => $data['minimum-stability'] ?? null,
|
||||
'prefer-stable' => $data['prefer-stable'] ?? null,
|
||||
'config' => $relevantConfig === [] ? null : $relevantConfig,
|
||||
];
|
||||
|
||||
self::sortRecursively($relevant);
|
||||
|
||||
$json = json_encode($relevant);
|
||||
|
||||
return $json === false ? null : hash('xxh128', $json);
|
||||
}
|
||||
|
||||
private static function sortRecursively(mixed &$value): void
|
||||
{
|
||||
if (! is_array($value)) {
|
||||
|
||||
@ -1321,6 +1321,49 @@ final class Graph
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune baseline result entries whose test files were just executed but whose
|
||||
* test IDs are no longer present (e.g. the test method was removed or renamed).
|
||||
*
|
||||
* @param array<int, string> $touchedFiles Absolute or project-relative paths.
|
||||
* @param array<int, string> $keepTestIds Test IDs that produced a result this run.
|
||||
*/
|
||||
public function pruneStaleResults(string $branch, array $touchedFiles, array $keepTestIds): void
|
||||
{
|
||||
if (! isset($this->baselines[$branch]['results'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$touched = [];
|
||||
foreach ($touchedFiles as $file) {
|
||||
$rel = $this->relative($file);
|
||||
|
||||
if ($rel !== null) {
|
||||
$touched[$rel] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($touched === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$keep = array_fill_keys($keepTestIds, true);
|
||||
|
||||
foreach ($this->baselines[$branch]['results'] as $testId => $result) {
|
||||
$file = $result['file'] ?? null;
|
||||
|
||||
if (! is_string($file) || ! isset($touched[$file])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($keep[$testId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($this->baselines[$branch]['results'][$testId]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function decode(string $json, string $projectRoot): ?self
|
||||
{
|
||||
$data = json_decode($json, true);
|
||||
|
||||
Reference in New Issue
Block a user