Skip to content

Commit 4f976a5

Browse files
committed
Refactor to simplify runXWorkflow functions
1 parent 74ce1eb commit 4f976a5

4 files changed

Lines changed: 254 additions & 29 deletions

File tree

PhpcsChanged/BatchScanResult.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace PhpcsChanged;
5+
6+
/**
7+
* The phpcs output for a set of files after the batch scan phase, combining
8+
* results served from the cache with those produced by the batched phpcs
9+
* invocation. Consumed by the filter phase of a workflow.
10+
*/
11+
class BatchScanResult {
12+
/**
13+
* @var array<string, string> phpcs output for the modified version, keyed by file
14+
*/
15+
private $modifiedOutputs;
16+
17+
/**
18+
* @var array<string, string> phpcs output for the unmodified version, keyed by file
19+
*/
20+
private $unmodifiedOutputs;
21+
22+
/**
23+
* @var float Wall-clock time attributed to each scanned file
24+
*/
25+
private $timePerFile;
26+
27+
/**
28+
* @param array<string, string> $modifiedOutputs
29+
* @param array<string, string> $unmodifiedOutputs
30+
*/
31+
public function __construct(array $modifiedOutputs, array $unmodifiedOutputs, float $timePerFile) {
32+
$this->modifiedOutputs = $modifiedOutputs;
33+
$this->unmodifiedOutputs = $unmodifiedOutputs;
34+
$this->timePerFile = $timePerFile;
35+
}
36+
37+
public function getModifiedOutput(string $file): string {
38+
return $this->modifiedOutputs[$file] ?? '';
39+
}
40+
41+
public function getUnmodifiedOutput(string $file): string {
42+
return $this->unmodifiedOutputs[$file] ?? '';
43+
}
44+
45+
public function getTimePerFile(): float {
46+
return $this->timePerFile;
47+
}
48+
}

PhpcsChanged/Cli.php

Lines changed: 99 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use PhpcsChanged\JunitReporter;
1212
use PhpcsChanged\CheckstyleReporter;
1313
use PhpcsChanged\PhpcsMessages;
14+
use PhpcsChanged\ScanPlan;
15+
use PhpcsChanged\BatchScanResult;
1416
use PhpcsChanged\ShellException;
1517
use PhpcsChanged\ShellOperator;
1618
use PhpcsChanged\XmlReporter;
@@ -229,11 +231,25 @@ function runSvnWorkflow(array $svnFiles, CliOptions $options, ShellOperator $she
229231

230232
loadCache($cache, $shell, $options->toArray());
231233

234+
$plan = prepareSvnScanPlan($svnFiles, $options, $shell, $cache, $debug);
235+
$outputs = runSvnBatchScan($plan, $options, $shell, $cache);
236+
$phpcsMessages = getNewSvnMessagesForFiles($svnFiles, $plan, $outputs, $shell, $debug);
237+
238+
saveCache($cache, $shell, $options->toArray());
239+
$shell->clearCaches();
240+
return PhpcsMessages::merge($phpcsMessages);
241+
}
242+
243+
/**
244+
* Determine which files need fresh phpcs scans and which can be served from the cache.
245+
*
246+
* @param string[] $svnFiles
247+
*/
248+
function prepareSvnScanPlan(array $svnFiles, CliOptions $options, ShellOperator $shell, CacheManager $cache, callable $debug): ScanPlan {
232249
$phpcsStandard = $options->phpcsStandard;
233250
$warningSeverity = $options->warningSeverity;
234251
$errorSeverity = $options->errorSeverity;
235252

236-
// Pre-batch phase: determine which files need phpcs scans
237253
$needsModifiedPhpcs = [];
238254
$needsUnmodifiedPhpcs = [];
239255
$modifiedOutputs = [];
@@ -291,7 +307,23 @@ function runSvnWorkflow(array $svnFiles, CliOptions $options, ShellOperator $she
291307
}
292308
}
293309

294-
// Batch phase: single phpcs invocation for all uncached files
310+
return new ScanPlan($needsModifiedPhpcs, $needsUnmodifiedPhpcs, $modifiedOutputs, $unmodifiedOutputs, $isNewFileMap, $modifiedHashMap, $revisionIdMap);
311+
}
312+
313+
/**
314+
* Run a single phpcs invocation for all uncached files in the plan and merge the
315+
* results with the outputs already served from the cache.
316+
*/
317+
function runSvnBatchScan(ScanPlan $plan, CliOptions $options, ShellOperator $shell, CacheManager $cache): BatchScanResult {
318+
$phpcsStandard = $options->phpcsStandard;
319+
$warningSeverity = $options->warningSeverity;
320+
$errorSeverity = $options->errorSeverity;
321+
322+
$needsModifiedPhpcs = $plan->getNeedsModifiedPhpcs();
323+
$needsUnmodifiedPhpcs = $plan->getNeedsUnmodifiedPhpcs();
324+
$modifiedOutputs = $plan->getModifiedOutputs();
325+
$unmodifiedOutputs = $plan->getUnmodifiedOutputs();
326+
295327
$batchTime = 0.0;
296328
$batchSize = count($needsModifiedPhpcs) + count($needsUnmodifiedPhpcs);
297329
if ($batchSize > 0) {
@@ -308,44 +340,52 @@ function runSvnWorkflow(array $svnFiles, CliOptions $options, ShellOperator $she
308340
foreach ($needsModifiedPhpcs as $svnFile) {
309341
$modifiedOutputs[$svnFile] = $batchResults['new'][$svnFile] ?? '';
310342
if (isCachingEnabled($options->toArray())) {
311-
$cache->setCacheForFile($svnFile, 'new', $modifiedHashMap[$svnFile], $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $modifiedOutputs[$svnFile]);
343+
$cache->setCacheForFile($svnFile, 'new', $plan->getModifiedCacheKey($svnFile), $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $modifiedOutputs[$svnFile]);
312344
}
313345
}
314346

315347
foreach ($needsUnmodifiedPhpcs as $svnFile) {
316348
$unmodifiedOutputs[$svnFile] = $batchResults['old'][$svnFile] ?? '';
317349
if (isCachingEnabled($options->toArray())) {
318-
$cache->setCacheForFile($svnFile, 'old', $revisionIdMap[$svnFile], $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $unmodifiedOutputs[$svnFile]);
350+
$cache->setCacheForFile($svnFile, 'old', $plan->getUnmodifiedCacheKey($svnFile), $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $unmodifiedOutputs[$svnFile]);
319351
}
320352
}
321353
}
322354

323-
$timePerFile = $batchSize > 0 ? $batchTime / $batchSize : 0.0;
355+
return new BatchScanResult($modifiedOutputs, $unmodifiedOutputs, $batchSize > 0 ? $batchTime / $batchSize : 0.0);
356+
}
324357

325-
// Filter phase: compute new messages per file
358+
/**
359+
* Compute the new phpcs messages for each file from its modified/unmodified phpcs output.
360+
*
361+
* @param string[] $svnFiles
362+
*
363+
* @return PhpcsMessages[]
364+
*/
365+
function getNewSvnMessagesForFiles(array $svnFiles, ScanPlan $plan, BatchScanResult $outputs, ShellOperator $shell, callable $debug): array {
326366
$phpcsMessages = [];
327367
foreach ($svnFiles as $svnFile) {
328368
$fileName = $shell->getFileNameFromPath($svnFile);
329369
try {
330-
$modifiedOutput = $modifiedOutputs[$svnFile] ?? '';
370+
$modifiedOutput = $outputs->getModifiedOutput($svnFile);
331371
$modifiedFilePhpcsMessages = PhpcsMessages::fromPhpcsJson($modifiedOutput, $fileName);
332-
$modifiedFilePhpcsMessages->setTiming($fileName, $timePerFile);
372+
$modifiedFilePhpcsMessages->setTiming($fileName, $outputs->getTimePerFile());
333373
$hasNewPhpcsMessages = count($modifiedFilePhpcsMessages->getMessages()) > 0;
334374

335375
if (! $hasNewPhpcsMessages) {
336376
throw new NoChangesException("Modified file '{$svnFile}' has no PHPCS messages; skipping");
337377
}
338378

339379
$unifiedDiff = $shell->getSvnUnifiedDiff($svnFile);
340-
$isNewFile = $isNewFileMap[$svnFile] ?? false;
380+
$isNewFile = $plan->isNewFile($svnFile);
341381

342382
if ($isNewFile) {
343383
$debug('Skipping the linting of the unmodified file as it is a new file.');
344384
$phpcsMessages[] = getNewPhpcsMessages($unifiedDiff, PhpcsMessages::fromPhpcsJson('', $fileName), $modifiedFilePhpcsMessages);
345385
continue;
346386
}
347387

348-
$unmodifiedOutput = $unmodifiedOutputs[$svnFile] ?? '';
388+
$unmodifiedOutput = $outputs->getUnmodifiedOutput($svnFile);
349389
$phpcsMessages[] = getNewPhpcsMessages($unifiedDiff, PhpcsMessages::fromPhpcsJson($unmodifiedOutput, $fileName), $modifiedFilePhpcsMessages);
350390
} catch( NoChangesException $err ) {
351391
$debug($err->getMessage());
@@ -363,10 +403,7 @@ function runSvnWorkflow(array $svnFiles, CliOptions $options, ShellOperator $she
363403
throw $err; // Just in case we do not actually exit, like in tests
364404
}
365405
}
366-
367-
saveCache($cache, $shell, $options->toArray());
368-
$shell->clearCaches();
369-
return PhpcsMessages::merge($phpcsMessages);
406+
return $phpcsMessages;
370407
}
371408

372409
function runSvnWorkflowForFile(string $svnFile, CliOptions $options, ShellOperator $shell, CacheManager $cache, callable $debug): PhpcsMessages {
@@ -466,11 +503,23 @@ function runGitWorkflow(CliOptions $options, ShellOperator $shell, CacheManager
466503

467504
loadCache($cache, $shell, $options->toArray());
468505

506+
$plan = prepareGitScanPlan($options, $shell, $cache, $debug);
507+
$outputs = runGitBatchScan($plan, $options, $shell, $cache);
508+
$phpcsMessages = getNewGitMessagesForFiles($options->files, $plan, $outputs, $shell, $debug);
509+
510+
saveCache($cache, $shell, $options->toArray());
511+
$shell->clearCaches();
512+
return PhpcsMessages::merge($phpcsMessages);
513+
}
514+
515+
/**
516+
* Determine which files need fresh phpcs scans and which can be served from the cache.
517+
*/
518+
function prepareGitScanPlan(CliOptions $options, ShellOperator $shell, CacheManager $cache, callable $debug): ScanPlan {
469519
$phpcsStandard = $options->phpcsStandard;
470520
$warningSeverity = $options->warningSeverity;
471521
$errorSeverity = $options->errorSeverity;
472522

473-
// Pre-batch phase: determine which files need phpcs scans
474523
$needsModifiedPhpcs = [];
475524
$needsUnmodifiedPhpcs = [];
476525
$modifiedOutputs = [];
@@ -529,7 +578,23 @@ function runGitWorkflow(CliOptions $options, ShellOperator $shell, CacheManager
529578
}
530579
}
531580

532-
// Batch phase: single phpcs invocation for all uncached files
581+
return new ScanPlan($needsModifiedPhpcs, $needsUnmodifiedPhpcs, $modifiedOutputs, $unmodifiedOutputs, $isNewFileMap, $modifiedHashMap, $unmodifiedHashMap);
582+
}
583+
584+
/**
585+
* Run a single phpcs invocation for all uncached files in the plan and merge the
586+
* results with the outputs already served from the cache.
587+
*/
588+
function runGitBatchScan(ScanPlan $plan, CliOptions $options, ShellOperator $shell, CacheManager $cache): BatchScanResult {
589+
$phpcsStandard = $options->phpcsStandard;
590+
$warningSeverity = $options->warningSeverity;
591+
$errorSeverity = $options->errorSeverity;
592+
593+
$needsModifiedPhpcs = $plan->getNeedsModifiedPhpcs();
594+
$needsUnmodifiedPhpcs = $plan->getNeedsUnmodifiedPhpcs();
595+
$modifiedOutputs = $plan->getModifiedOutputs();
596+
$unmodifiedOutputs = $plan->getUnmodifiedOutputs();
597+
533598
$batchTime = 0.0;
534599
$batchSize = count($needsModifiedPhpcs) + count($needsUnmodifiedPhpcs);
535600
if ($batchSize > 0) {
@@ -546,39 +611,47 @@ function runGitWorkflow(CliOptions $options, ShellOperator $shell, CacheManager
546611
foreach ($needsModifiedPhpcs as $gitFile) {
547612
$modifiedOutputs[$gitFile] = $batchResults['new'][$gitFile] ?? '';
548613
if (isCachingEnabled($options->toArray())) {
549-
$cache->setCacheForFile($gitFile, 'new', $modifiedHashMap[$gitFile], $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $modifiedOutputs[$gitFile]);
614+
$cache->setCacheForFile($gitFile, 'new', $plan->getModifiedCacheKey($gitFile), $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $modifiedOutputs[$gitFile]);
550615
}
551616
}
552617

553618
foreach ($needsUnmodifiedPhpcs as $gitFile) {
554619
$unmodifiedOutputs[$gitFile] = $batchResults['old'][$gitFile] ?? '';
555620
if (isCachingEnabled($options->toArray())) {
556-
$cache->setCacheForFile($gitFile, 'old', $unmodifiedHashMap[$gitFile], $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $unmodifiedOutputs[$gitFile]);
621+
$cache->setCacheForFile($gitFile, 'old', $plan->getUnmodifiedCacheKey($gitFile), $phpcsStandard ?? '', $warningSeverity ?? '', $errorSeverity ?? '', $unmodifiedOutputs[$gitFile]);
557622
}
558623
}
559624
}
560625

561-
$timePerFile = $batchSize > 0 ? $batchTime / $batchSize : 0.0;
626+
return new BatchScanResult($modifiedOutputs, $unmodifiedOutputs, $batchSize > 0 ? $batchTime / $batchSize : 0.0);
627+
}
562628

563-
// Filter phase: compute new messages per file
629+
/**
630+
* Compute the new phpcs messages for each file from its modified/unmodified phpcs output.
631+
*
632+
* @param string[] $gitFiles
633+
*
634+
* @return PhpcsMessages[]
635+
*/
636+
function getNewGitMessagesForFiles(array $gitFiles, ScanPlan $plan, BatchScanResult $outputs, ShellOperator $shell, callable $debug): array {
564637
$phpcsMessages = [];
565-
foreach ($options->files as $gitFile) {
638+
foreach ($gitFiles as $gitFile) {
566639
try {
567-
$modifiedOutput = $modifiedOutputs[$gitFile] ?? '';
640+
$modifiedOutput = $outputs->getModifiedOutput($gitFile);
568641
$modifiedFilePhpcsMessages = PhpcsMessages::fromPhpcsJson($modifiedOutput, $gitFile);
569-
$modifiedFilePhpcsMessages->setTiming($gitFile, $timePerFile);
642+
$modifiedFilePhpcsMessages->setTiming($gitFile, $outputs->getTimePerFile());
570643

571644
$unifiedDiff = '';
572645
$unmodifiedFilePhpcsOutput = '';
573646
if (count($modifiedFilePhpcsMessages->getMessages()) === 0) {
574647
throw new NoChangesException("Modified file '{$gitFile}' has no PHPCS messages; skipping");
575648
}
576649

577-
$isNewFile = $isNewFileMap[$gitFile] ?? false;
650+
$isNewFile = $plan->isNewFile($gitFile);
578651
if (! $isNewFile) {
579652
$debug('Checking the unmodified file with PHPCS since the file is not new and contains some messages.');
580653
$unifiedDiff = $shell->getGitUnifiedDiff($gitFile);
581-
$unmodifiedFilePhpcsOutput = $unmodifiedOutputs[$gitFile] ?? '';
654+
$unmodifiedFilePhpcsOutput = $outputs->getUnmodifiedOutput($gitFile);
582655
} else {
583656
$debug('Skipping the linting of the unmodified file as it is a new file.');
584657
}
@@ -593,10 +666,7 @@ function runGitWorkflow(CliOptions $options, ShellOperator $shell, CacheManager
593666
throw $err; // Just in case we do not actually exit
594667
}
595668
}
596-
597-
saveCache($cache, $shell, $options->toArray());
598-
$shell->clearCaches();
599-
return PhpcsMessages::merge($phpcsMessages);
669+
return $phpcsMessages;
600670
}
601671

602672
function runGitWorkflowForFile(string $gitFile, CliOptions $options, ShellOperator $shell, CacheManager $cache, callable $debug): PhpcsMessages {

0 commit comments

Comments
 (0)