Skip to content

Commit c1db8c8

Browse files
committed
Ruleset: wire in MessageCollector
This commit adds a mechanism to handle errors encountered while loading a ruleset in a more user-friendly manner. * Errors and notices aimed at end-users and ruleset maintainers will be collected while processing the ruleset. * Only once the complete processing of the ruleset is finished, will all errors/notices be displayed. This prevents "one error hiding behind another". * If there are only notices (deprecations/notices/warnings), these will not display when running `-e` (explain), `-q` (quiet mode) or `--generator=...` (documentation). * Errors will always display and will hard exit out of the run with a non-zero exit code. This implementation should be seen as an interim - "good enough for now" - solution, which can be iterated on in the future. I can imagine a more code-base wide solution at some later point in time, but that should not block this initial improvement. As the current implementation doesn't change the public API (the only new methods are `private`), it should be feasible to transform the current solution to whatever form a future solution will take without breaking changes. Includes tests covering the new functionality.
1 parent 581eef9 commit c1db8c8

File tree

2 files changed

+358
-5
lines changed

2 files changed

+358
-5
lines changed

src/Ruleset.php

+52-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHP_CodeSniffer\Exceptions\RuntimeException;
1515
use PHP_CodeSniffer\Sniffs\DeprecatedSniff;
1616
use PHP_CodeSniffer\Util\Common;
17+
use PHP_CodeSniffer\Util\MessageCollector;
1718
use PHP_CodeSniffer\Util\Standards;
1819
use RecursiveDirectoryIterator;
1920
use RecursiveIteratorIterator;
@@ -131,21 +132,36 @@ class Ruleset
131132
*/
132133
private $deprecatedSniffs = [];
133134

135+
/**
136+
* Message collector object.
137+
*
138+
* User-facing messages should be collected via this object for display once the ruleset processing has finished.
139+
*
140+
* The following type of errors should *NOT* be collected, but should still throw their own `RuntimeException`:
141+
* - Errors which could cause other (uncollectable) errors further into the ruleset processing, like a missing autoload file.
142+
* - Errors which are directly aimed at and only intended for sniff developers or integrators
143+
* (in contrast to ruleset maintainers or end-users).
144+
*
145+
* @var \PHP_CodeSniffer\Util\MessageCollector
146+
*/
147+
private $msgCache;
148+
134149

135150
/**
136151
* Initialise the ruleset that the run will use.
137152
*
138153
* @param \PHP_CodeSniffer\Config $config The config data for the run.
139154
*
140155
* @return void
141-
* @throws \PHP_CodeSniffer\Exceptions\RuntimeException If no sniffs were registered.
156+
* @throws \PHP_CodeSniffer\Exceptions\RuntimeException If blocking errors were encountered when processing the ruleset.
142157
*/
143158
public function __construct(Config $config)
144159
{
145-
$this->config = $config;
146-
$restrictions = $config->sniffs;
147-
$exclusions = $config->exclude;
148-
$sniffs = [];
160+
$this->config = $config;
161+
$restrictions = $config->sniffs;
162+
$exclusions = $config->exclude;
163+
$sniffs = [];
164+
$this->msgCache = new MessageCollector();
149165

150166
$standardPaths = [];
151167
foreach ($config->standards as $standard) {
@@ -242,6 +258,8 @@ public function __construct(Config $config)
242258
throw new RuntimeException('ERROR: No sniffs were registered');
243259
}
244260

261+
$this->displayCachedMessages();
262+
245263
}//end __construct()
246264

247265

@@ -461,6 +479,35 @@ public function showSniffDeprecations()
461479
}//end showSniffDeprecations()
462480

463481

482+
/**
483+
* Print any notices encountered while processing the ruleset(s).
484+
*
485+
* Note: these messages aren't shown at the time they are encountered to avoid "one error hiding behind another".
486+
* This way the (end-)user gets to see all of them in one go.
487+
*
488+
* @return void
489+
*
490+
* @throws \PHP_CodeSniffer\Exceptions\RuntimeException If blocking errors were encountered.
491+
*/
492+
private function displayCachedMessages()
493+
{
494+
// Don't show deprecations/notices/warnings in quiet mode, in explain mode
495+
// or when the documentation is being shown.
496+
// Documentation and explain will call the Ruleset multiple times which
497+
// would lead to duplicate display of the messages.
498+
if ($this->msgCache->containsBlockingErrors() === false
499+
&& ($this->config->quiet === true
500+
|| $this->config->explain === true
501+
|| $this->config->generator !== null)
502+
) {
503+
return;
504+
}
505+
506+
$this->msgCache->display();
507+
508+
}//end displayCachedMessages()
509+
510+
464511
/**
465512
* Processes a single ruleset and returns a list of the sniffs it represents.
466513
*

0 commit comments

Comments
 (0)