From 2e8371601185ef3fe2fbbf2f20d460bc1a3b8cca Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Mon, 10 Aug 2026 09:01:23 -0400 Subject: [PATCH 1/3] chore(sonar): add XOOPS-convention exclusions to the baseline template Ship the sonar.issue.ignore.multicriteria block in the DevOps baseline so every module that adopts it inherits the suppression for the SonarPHP rules that clash with mandated XOOPS conventions and with test doubles: S115 (constants start with '_'), S100 (snake_case lifecycle hooks), S1172/S1186 (a stub matches a signature it does not use), and S1142 (guard-clause early returns). Binds only under the CI scanner; SonarCloud Automatic Analysis must be off for it to take effect. --- sonar-project.properties | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sonar-project.properties b/sonar-project.properties index faa5853..7fcdaa5 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -20,3 +20,35 @@ sonar.test.inclusions=tests/**/*Test.php sonar.php.coverage.reportPaths=.build/coverage/clover.xml sonar.sourceEncoding=UTF-8 + +# --- XOOPS-convention false positives: permanently ignored --- +# SonarPHP's default naming/quality rules clash with mandated XOOPS conventions and with +# the shape of test doubles. Ignored here (in-repo, versioned) rather than per-issue in the +# UI, so the suppression is reviewable and survives every scan. +# +# NOTE: these properties are honoured ONLY by the CI scanner. SonarCloud's server-side +# Automatic Analysis ignores this file entirely -- disable Automatic Analysis +# (project -> Administration -> Analysis Method) so the CI scanner + this file take effect. +sonar.issue.ignore.multicriteria=x1,x2,x3,x4,x5 + +# S115: constant names must match ^[A-Z]..., but every XOOPS _MI_/_MA_/_AM_ constant +# begins with an underscore -- the rule can never pass for XOOPS language constants. +sonar.issue.ignore.multicriteria.x1.ruleKey=php:S115 +sonar.issue.ignore.multicriteria.x1.resourceKey=**/*.php + +# S100: function names must be camelCase, but XOOPS mandates snake_case lifecycle hooks +# (xoops_module_install_, xoops_module_update_, ...). +sonar.issue.ignore.multicriteria.x2.ruleKey=php:S100 +sonar.issue.ignore.multicriteria.x2.resourceKey=**/*.php + +# S1172 + S1186: a test double must match the real signature it stands in for, so its +# parameters are "unused" and its bodies are empty by design. +sonar.issue.ignore.multicriteria.x3.ruleKey=php:S1172 +sonar.issue.ignore.multicriteria.x3.resourceKey=tests/** +sonar.issue.ignore.multicriteria.x4.ruleKey=php:S1186 +sonar.issue.ignore.multicriteria.x4.resourceKey=tests/** + +# S1142: guard-clause early returns are the intentional style in the provider/install +# hooks; "too many return statements" is noise against that shape. +sonar.issue.ignore.multicriteria.x5.ruleKey=php:S1142 +sonar.issue.ignore.multicriteria.x5.resourceKey=**/*.php From b27e711e645d06e2a67d23a8cb57ef0566541f50 Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Mon, 10 Aug 2026 09:44:01 -0400 Subject: [PATCH 2/3] chore(packaging): ship user docs, anchor ignores, drop tests from sonar sources Bring the DevOps baseline template in line with the xtracy PR-review fixes so modules that adopt it inherit the corrected scaffolding: - .gitattributes: do not export-ignore CHANGELOG.md (docs already ship), so release archives keep the user-facing changelog. - .gitignore: anchor phpstan.neon / phpunit.xml / psalm.xml with a leading slash, so only the root local-override copies are ignored. - sonar-project.properties: add tests/** to sonar.exclusions so tests are not indexed as analysis sources; sonar.tests still exposes them for test analysis. --- .gitattributes | 1 - .gitignore | 6 +++--- sonar-project.properties | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.gitattributes b/.gitattributes index 5a2629e..b1e6e43 100644 --- a/.gitattributes +++ b/.gitattributes @@ -29,4 +29,3 @@ /sonar-project.properties export-ignore /.git-blame-ignore-revs export-ignore /composer.lock export-ignore -/CHANGELOG.md export-ignore diff --git a/.gitignore b/.gitignore index 43abb23..71210db 100644 --- a/.gitignore +++ b/.gitignore @@ -67,9 +67,9 @@ package-lock.json # --- Local overrides of committed *.dist configs --- /.php-cs-fixer.php -phpstan.neon -phpunit.xml -psalm.xml +/phpstan.neon +/phpunit.xml +/psalm.xml # --- Environment, logs & secrets --- .env diff --git a/sonar-project.properties b/sonar-project.properties index 7fcdaa5..ca126b6 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -12,7 +12,7 @@ sonar.projectName=module-devops # Analyse PHP sources; keep vendored code, tooling, generated dirs, and tests out of "sources". sonar.sources=. -sonar.exclusions=vendor/**,.build/**,node_modules/**,language/**,templates/**,templates_c/**,assets/**,docs/**,rector.php,.php-cs-fixer.dist.php,phpstan-bootstrap.php,stubs/** +sonar.exclusions=vendor/**,.build/**,node_modules/**,language/**,templates/**,templates_c/**,assets/**,docs/**,tests/**,rector.php,.php-cs-fixer.dist.php,phpstan-bootstrap.php,stubs/** sonar.tests=tests sonar.test.inclusions=tests/**/*Test.php From ace0b7718b00e1bdbe864b4981a4976be494e1f0 Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Mon, 10 Aug 2026 10:17:15 -0400 Subject: [PATCH 3/3] chore(sonar): scope naming ignores to their conventional homes Answer PR #12 review on the ignore scopes: - S115: narrowed to language/**/*.php -- the mandated home of _MI_/_MA_/_AM_ constants; every other PHP file keeps the rule. - S100: narrowed to include/**/*.php and blocks/**/*.php, where XOOPS mandates snake_case entry points (lifecycle hooks, block callbacks); class code stays camelCase-checked. Split into two entries since a multicriteria item takes a single resourceKey. - S1172/S1186 stay on tests/**: after tests were source-excluded, only tests/**/*Test.php is indexed at all, so a dedicated doubles directory would be invisible to the analyzer; doubles reach it as inline classes in *Test.php files, which path patterns cannot separate from the tests beside them. Documented in the comment instead. - S1142 stays repo-wide: guard-clause early returns are the house style across module entry points, not a per-file exception; the comment now says so instead of implying a narrower scope. --- sonar-project.properties | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index ca126b6..7da6485 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -29,26 +29,35 @@ sonar.sourceEncoding=UTF-8 # NOTE: these properties are honoured ONLY by the CI scanner. SonarCloud's server-side # Automatic Analysis ignores this file entirely -- disable Automatic Analysis # (project -> Administration -> Analysis Method) so the CI scanner + this file take effect. -sonar.issue.ignore.multicriteria=x1,x2,x3,x4,x5 +sonar.issue.ignore.multicriteria=x1,x2a,x2b,x3,x4,x5 # S115: constant names must match ^[A-Z]..., but every XOOPS _MI_/_MA_/_AM_ constant # begins with an underscore -- the rule can never pass for XOOPS language constants. +# Scoped to language/, the mandated home of those constants; all other PHP keeps S115. sonar.issue.ignore.multicriteria.x1.ruleKey=php:S115 -sonar.issue.ignore.multicriteria.x1.resourceKey=**/*.php +sonar.issue.ignore.multicriteria.x1.resourceKey=language/**/*.php -# S100: function names must be camelCase, but XOOPS mandates snake_case lifecycle hooks -# (xoops_module_install_, xoops_module_update_, ...). -sonar.issue.ignore.multicriteria.x2.ruleKey=php:S100 -sonar.issue.ignore.multicriteria.x2.resourceKey=**/*.php +# S100: function names must be camelCase, but XOOPS mandates snake_case entry points: +# lifecycle hooks in include/ (xoops_module_install_, ...) and block callbacks +# in blocks/ (b___show/edit). Class code elsewhere stays camelCase-checked. +sonar.issue.ignore.multicriteria.x2a.ruleKey=php:S100 +sonar.issue.ignore.multicriteria.x2a.resourceKey=include/**/*.php +sonar.issue.ignore.multicriteria.x2b.ruleKey=php:S100 +sonar.issue.ignore.multicriteria.x2b.resourceKey=blocks/**/*.php # S1172 + S1186: a test double must match the real signature it stands in for, so its -# parameters are "unused" and its bodies are empty by design. +# parameters are "unused" and its bodies are empty by design. Only tests/**/*Test.php is +# indexed (tests/** is source-excluded above; sonar.test.inclusions selects *Test.php), +# and doubles reach the analyzer as inline classes in those files -- path patterns cannot +# separate them from the tests beside them, so the ignore stays on tests/**. sonar.issue.ignore.multicriteria.x3.ruleKey=php:S1172 sonar.issue.ignore.multicriteria.x3.resourceKey=tests/** sonar.issue.ignore.multicriteria.x4.ruleKey=php:S1186 sonar.issue.ignore.multicriteria.x4.resourceKey=tests/** -# S1142: guard-clause early returns are the intentional style in the provider/install -# hooks; "too many return statements" is noise against that shape. +# S1142: guard-clause early returns are the intentional house style across XOOPS module +# entry points (install/update hooks, preload handlers, providers, permission checks), +# not a per-file exception -- "too many return statements" is noise against that idiom, +# so this ignore is deliberately repo-wide. sonar.issue.ignore.multicriteria.x5.ruleKey=php:S1142 sonar.issue.ignore.multicriteria.x5.resourceKey=**/*.php