1111use PhpcsChanged \JunitReporter ;
1212use PhpcsChanged \CheckstyleReporter ;
1313use PhpcsChanged \PhpcsMessages ;
14+ use PhpcsChanged \ScanPlan ;
15+ use PhpcsChanged \BatchScanResult ;
1416use PhpcsChanged \ShellException ;
1517use PhpcsChanged \ShellOperator ;
1618use 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
372409function 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
602672function runGitWorkflowForFile (string $ gitFile , CliOptions $ options , ShellOperator $ shell , CacheManager $ cache , callable $ debug ): PhpcsMessages {
0 commit comments