Skip to content

Ruleset: configs in higher level ruleset(s) overrule configs set in included ruleset(s) #1003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

jrfnl
Copy link
Member

@jrfnl jrfnl commented Apr 15, 2025

Description

This is a completely different solution to issue squizlabs/PHP_CodeSniffer#2197, compared to the original solution which was previously committed to the old 4.0 branch.

The "old' solution was to process rulesets "top to bottom", i.e. every directive is processed when "read" while recursing through the rulesets. I've evaluated that solution carefully and found it counter-intuitive, which means that I expect that it would raise lots of support questions. I also expect that solution to break way more rulesets than is justified to solve issue squizlabs/PHP_CodeSniffer#2197.

The original solution would require ruleset maintainers to have a high awareness of what configs are being set in included rulesets. Included rulesets are often PHPCS native standards or external standards, which are both subject to change in every new release. With ruleset processing being top-to-bottom, any "must have" config directives would have to be set before any include which could possibly also have that config directive set. This also means that an external standard adding a config directive to one of their rulesets, would become a potentially breaking change, as a "consumer" ruleset may not realize they were relying on a default value for a "must have" config and that value being changed in an included ruleset could now break their CS scans.

So... having said that, this commit contains an alternative, far more specific, and far less invasive, solution for the originally posed problem.


This commit changes the processing of config directives to be based on the inclusion depth, with the highest level ruleset setting a config value overruling the value for that config as set in lower level (included) rulesets.

When two rulesets at the same "level" both set the same config directive, the last one included "wins".

To illustrate:

File: phpcs.xml.dist
Sets config `testVersion` to `7.2-`
Includes CompanyRulesetA

File CompanyRulesetA/ruleset.xml
Sets config `testVersion` to `8.1-`

In 3.x: testVersion would be set to 8.1-
In 4.x: testVersion will be set to 7.2- (higher level ruleset wins)

File: phpcs.xml.dist
Includes CompanyRulesetA and AnotherRuleset

File CompanyRulesetA/ruleset.xml
Sets config `testVersion` to `8.2-`

File AnotherRuleset/ruleset.xml
Sets config `testVersion` to `5.6-`

In 3.x: testVersion would be set to 5.6-
In 4.x: testVersion will be set to 5.6- (CompanyRulesetA and AnotherRuleset are at the same inclusion depth, last one wins)

Includes ample tests.
Includes minor tweak to improve the debug information and only display that something was set when it actually has been set.

Suggested changelog entry

Changed:

  • When processing rulesets, <config> directives will be applied based on the nesting level of the ruleset.
    • Previously, it was not possible to overrule a <config> directive set in an included ruleset from the "root" ruleset.
    • Now, <config> directives set in the "root" ruleset will always "win" over directives in included rulesets.
    • When two included rulesets at the same nesting level both set the same directive, the value from the last included ruleset "wins" (= same as before).

Related issues/external references

Related to squizlabs/PHP_CodeSniffer#1821 - point 2
Fixes squizlabs/PHP_CodeSniffer#2197

…ncluded ruleset(s)

This is a completely different solution to issue squizlabs/PHP_CodeSniffer 2197, compared to the original solution which was previously committed to the old 4.0 branch.

The "old' solution was to process rulesets "top to bottom", i.e. every directive is processed when "read" while recursing through the rulesets.
I've evaluated that solution carefully and found it counter-intuitive, which means that I expect that it would raise lots of support questions. I also expect that solution to break way more rulesets than is justified to solve issue 2197.

The original solution would require ruleset maintainers to have a high awareness of what configs are being set in included rulesets. Included rulesets are often PHPCS native standards or external standards, which are both subject to change in every new release.
With ruleset processing being top-to-bottom, any "must have" config directives would have to be set _before_ any include which could possibly also have that config directive set. This also means that an external standard _adding_ a config directive to one of their rulesets, would become a potentially breaking change, as a "consumer" ruleset may not realize they were relying on a default value for a "must have" config and that value being changed in an included ruleset could now break their CS scans.

So... having said that, this commit contains an alternative, far more specific, and far less invasive, solution for the originally posed problem.

---

This commit changes the processing of `config` directives to be based on the inclusion depth, with the highest level ruleset setting a config value overruling the value for that config as set in lower level (included) rulesets.

When two rulesets at the same "level" both set the same `config` directive, the last one included "wins".

To illustrate:
```
File: phpcs.xml.dist
Sets config `testVersion` to `7.2-`
Includes CompanyRulesetA

File CompanyRulesetA/ruleset.xml
Sets config `testVersion` to `8.1-`
```

In 3.x: `testVersion` would be set to `8.1-`
In 4.x: `testVersion` will be set to `7.2-` (higher level ruleset wins)

```
File: phpcs.xml.dist
Includes CompanyRulesetA and AnotherRuleset

File CompanyRulesetA/ruleset.xml
Sets config `testVersion` to `8.2-`

File AnotherRuleset/ruleset.xml
Sets config `testVersion` to `5.6-`
```

In 3.x: `testVersion` would be set to `5.6-`
In 4.x: `testVersion` will be set to `5.6-` (CompanyRulesetA and AnotherRuleset are at the same inclusion depth, last one wins)

Includes ample tests.
Includes minor tweak to improve the debug information and only display that something was set when it actually has been set.

Related to squizlabs/PHP_CodeSniffer 1821 - point 2
Fixes squizlabs/PHP_CodeSniffer 2197
@jrfnl jrfnl merged commit 22607ab into 4.x Apr 15, 2025
54 checks passed
@jrfnl jrfnl deleted the phpcs-4.0/feature/sq-2197-ruleset-config-directive-processing branch April 15, 2025 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants