Skip to content

Commit b63cedf

Browse files
authored
Merge pull request #1005 from PHPCSStandards/phpcs-4.0/feature/sq-2395-2597-2602-ruleset-config-arg-processing
Ruleset: (CLI) `<arg>` settings in higher level ruleset(s) overrule args set in included ruleset(s)
2 parents b6abb91 + 3d2c0a5 commit b63cedf

File tree

8 files changed

+424
-24
lines changed

8 files changed

+424
-24
lines changed

src/Config.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,23 @@ class Config
104104
*/
105105
const DEFAULT_REPORT_WIDTH = 80;
106106

107+
/**
108+
* Translation table for config settings which can be changed via multiple CLI flags.
109+
*
110+
* If the flag name matches the setting name, there is no need to add it to this translation table.
111+
* Similarly, if there is only one flag which can change a setting, there is no need to include
112+
* it in this table, even if the flag name and the setting name don't match.
113+
*
114+
* @var array<string, string> Key is the CLI flag name, value the corresponding config setting name.
115+
*/
116+
public const CLI_FLAGS_TO_SETTING_NAME = [
117+
'n' => 'warningSeverity',
118+
'w' => 'warningSeverity',
119+
'warning-severity' => 'warningSeverity',
120+
'no-colors' => 'colors',
121+
'no-cache' => 'cache',
122+
];
123+
107124
/**
108125
* An array of settings that PHPCS and PHPCBF accept.
109126
*

src/Ruleset.php

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ class Ruleset
131131
*/
132132
private $configDirectivesApplied = [];
133133

134+
/**
135+
* The `<arg>` directives which have been applied.
136+
*
137+
* @var array<string, int> Key is the name of the setting. Value is the ruleset depth
138+
* at which this setting was applied (if not overruled from the CLI).
139+
*/
140+
private $cliSettingsApplied = [];
141+
134142
/**
135143
* An array of the names of sniffs which have been marked as deprecated.
136144
*
@@ -613,6 +621,92 @@ public function processRuleset($rulesetPath, $depth=0)
613621
}
614622
}//end foreach
615623

624+
// Process custom command line arguments.
625+
// Processing rules:
626+
// - Highest level ruleset take precedence.
627+
// - If the same CLI flag is being set from two rulesets at the same level, *first* one "wins".
628+
$cliArgs = [];
629+
foreach ($ruleset->{'arg'} as $arg) {
630+
if ($this->shouldProcessElement($arg) === false) {
631+
continue;
632+
}
633+
634+
// "Long" CLI argument. Arg is in the format `<arg name="name" [value="value"]/>`.
635+
if (isset($arg['name']) === true) {
636+
$name = (string) $arg['name'];
637+
$cliSettingName = $name;
638+
if (isset($this->config::CLI_FLAGS_TO_SETTING_NAME[$name]) === true) {
639+
$cliSettingName = $this->config::CLI_FLAGS_TO_SETTING_NAME[$name];
640+
}
641+
642+
if (isset($this->cliSettingsApplied[$cliSettingName]) === true
643+
&& $this->cliSettingsApplied[$cliSettingName] < $depth
644+
) {
645+
// Ignore this CLI flag. A higher level ruleset has already set a value for this setting.
646+
if (PHP_CODESNIFFER_VERBOSITY > 1) {
647+
$statusMessage = str_repeat("\t", $depth);
648+
$statusMessage .= "\t=> ignoring command line arg --".$name;
649+
if (isset($arg['value']) === true) {
650+
$statusMessage .= '='.(string) $arg['value'];
651+
}
652+
653+
echo $statusMessage.' => already changed by a higher level ruleset '.PHP_EOL;
654+
}
655+
656+
continue;
657+
}
658+
659+
// Remember which settings we've seen.
660+
$this->cliSettingsApplied[$cliSettingName] = $depth;
661+
662+
$argString = '--'.$name;
663+
if (isset($arg['value']) === true) {
664+
$argString .= '='.(string) $arg['value'];
665+
}
666+
} else {
667+
// "Short" CLI flag. Arg is in the format `<arg value="value"/>` and
668+
// value can contain multiple flags, like `<arg value="ps"/>`.
669+
$cleanedValue = '';
670+
$cliFlagsAsArray = str_split((string) $arg['value']);
671+
foreach ($cliFlagsAsArray as $flag) {
672+
$cliSettingName = $flag;
673+
if (isset($this->config::CLI_FLAGS_TO_SETTING_NAME[$flag]) === true) {
674+
$cliSettingName = $this->config::CLI_FLAGS_TO_SETTING_NAME[$flag];
675+
}
676+
677+
if (isset($this->cliSettingsApplied[$cliSettingName]) === true
678+
&& $this->cliSettingsApplied[$cliSettingName] < $depth
679+
) {
680+
// Ignore this CLI flag. A higher level ruleset has already set a value for this setting.
681+
if (PHP_CODESNIFFER_VERBOSITY > 1) {
682+
echo str_repeat("\t", $depth);
683+
echo "\t=> ignoring command line flag -".$flag.' => already changed by a higher level ruleset '.PHP_EOL;
684+
}
685+
686+
continue;
687+
}
688+
689+
// Remember which settings we've seen.
690+
$cleanedValue .= $flag;
691+
$this->cliSettingsApplied[$cliSettingName] = $depth;
692+
}//end foreach
693+
694+
if ($cleanedValue === '') {
695+
// No flags found which should be applied.
696+
continue;
697+
}
698+
699+
$argString = '-'.$cleanedValue;
700+
}//end if
701+
702+
$cliArgs[] = $argString;
703+
704+
if (PHP_CODESNIFFER_VERBOSITY > 1) {
705+
echo str_repeat("\t", $depth);
706+
echo "\t=> set command line value $argString".PHP_EOL;
707+
}
708+
}//end foreach
709+
616710
foreach ($ruleset->rule as $rule) {
617711
if (isset($rule['ref']) === false
618712
|| $this->shouldProcessElement($rule) === false
@@ -706,30 +800,6 @@ public function processRuleset($rulesetPath, $depth=0)
706800
$this->processRule($rule, $newSniffs, $depth);
707801
}//end foreach
708802

709-
// Process custom command line arguments.
710-
$cliArgs = [];
711-
foreach ($ruleset->{'arg'} as $arg) {
712-
if ($this->shouldProcessElement($arg) === false) {
713-
continue;
714-
}
715-
716-
if (isset($arg['name']) === true) {
717-
$argString = '--'.(string) $arg['name'];
718-
if (isset($arg['value']) === true) {
719-
$argString .= '='.(string) $arg['value'];
720-
}
721-
} else {
722-
$argString = '-'.(string) $arg['value'];
723-
}
724-
725-
$cliArgs[] = $argString;
726-
727-
if (PHP_CODESNIFFER_VERBOSITY > 1) {
728-
echo str_repeat("\t", $depth);
729-
echo "\t=> set command line value $argString".PHP_EOL;
730-
}
731-
}//end foreach
732-
733803
// Set custom php ini values as CLI args.
734804
foreach ($ruleset->{'ini'} as $arg) {
735805
if ($this->shouldProcessElement($arg) === false) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetCliArgsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<!-- Issues squizlabs/PHP_CodeSniffer#2597 + squizlabs/PHP_CodeSniffer#2602: allow overruling CLI args when they have a single CLI flag names.
5+
One value is set before the includes, one after to safeguard that the order in the file does not influence the results.
6+
-->
7+
<arg name="extensions" value="inc,install,module,php,profile,test,theme"/>
8+
9+
<!-- Issue squizlabs/PHP_CodeSniffer#2395: allow overruling CLI args when they have different CLI flag names. -->
10+
<arg name="no-colors"/>
11+
12+
<!-- Miscellaneous other settings. -->
13+
<arg name="report" value="full,summary,source"/>
14+
15+
<!-- Include the overrides. -->
16+
<rule ref="./phpcs.xml.dist"/>
17+
<rule ref="./config/phpcs/include-overrules.xml"/>
18+
19+
<!-- Issues squizlabs/PHP_CodeSniffer#2597 + squizlabs/PHP_CodeSniffer#2602: second test. -->
20+
<arg name="tab-width" value="3"/>
21+
22+
<!-- Issue squizlabs/PHP_CodeSniffer#2395: second test. -->
23+
<arg value="w"/>
24+
25+
<!-- Prevent a "no sniffs were registered" error. -->
26+
<rule ref="Generic.PHP.BacktickOperator"/>
27+
</ruleset>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetCliArgsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<!-- Issues squizlabs/PHP_CodeSniffer#2597 + squizlabs/PHP_CodeSniffer#2602: allow overruling CLI args when they have the CLI flag names.
5+
The value from the parent ruleset should be applied, not the one from the child.
6+
-->
7+
<arg name="tab-width" value="5"/>
8+
9+
<!-- Paths must be resolved based on the ruleset location which included the directive. -->
10+
<arg name="report-file" value="./report.txt"/>
11+
12+
<!-- Miscellaneous other settings. -->
13+
<arg name="report-width" value="60"/>
14+
15+
</ruleset>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetCliArgsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<!-- Issue squizlabs/PHP_CodeSniffer#2395: allow overruling CLI args when they have different CLI flag names.
5+
The values from the parent ruleset should be applied, not those from the child.
6+
-->
7+
<arg name="colors"/>
8+
<arg value="qn"/>
9+
10+
<!-- Paths must be resolved based on the ruleset location which included the directive. -->
11+
<arg name="basepath" value="./"/>
12+
13+
<!-- Miscellaneous other settings. -->
14+
<arg name="parallel" value="10"/>
15+
16+
<!-- Include the overrides. -->
17+
<rule ref="./vendor/OrgName/ExtStandard/ruleset.xml"/>
18+
19+
<!-- Issues squizlabs/PHP_CodeSniffer#2597 + squizlabs/PHP_CodeSniffer#2602: allow overruling CLI args when they have the CLI flag names.
20+
The values from the parent ruleset should be applied, not those from the child.
21+
-->
22+
<arg name="extensions" value="inc,php"/>
23+
<arg name="tab-width" value="4"/>
24+
25+
<!-- Miscellaneous other settings. -->
26+
<arg name="report-width" value="120"/>
27+
28+
</ruleset>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
// Do nothing. This is just a placeholder file for the "bootstrap" CLI flag test.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="ProcessRulesetCliArgsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<!-- Issue squizlabs/PHP_CodeSniffer#2395. -->
5+
<arg name="warning-severity" value="3"/>
6+
<arg value="p"/>
7+
8+
<!-- Paths must be resolved based on the ruleset location which included the directive. -->
9+
<arg name="bootstrap" value="./bootstrap.php"/>
10+
11+
<!-- Miscellaneous other settings. -->
12+
<arg name="parallel" value="2"/>
13+
<arg name="report" value="code,summary"/>
14+
15+
</ruleset>

0 commit comments

Comments
 (0)