From c4d241e3efe917048d076893f5d336d7732a2668 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Mon, 5 Oct 2026 13:58:43 -0400 Subject: [PATCH 1/3] ci: Restore PHP 8.2 to the matrix and fix coding standards PR #150 merged with a failing 'Checking coding standards' job and had dropped PHP 8.2 from the CI matrix. - Re-add php 8.2 to the integration-test matrix and lower the documented floor back to 8.2, adding the canonical PHP 8.3-only-syntax guards (#[Override], json_validate(), typed class constants, dynamic class constant fetch) to tests/Security/PhpCompatibilityTest.php so the 8.2 floor is actually enforced. The plugin source is already 8.2-clean. - Run php-cs-fixer over tests/bin/check-i18n-pot.php (added by #150) so 'composer run-script phpcsfixer' passes. --- .github/workflows/plugin-ci-workflow.yml | 2 +- tests/Security/PhpCompatibilityTest.php | 47 ++++++++++++++++++++++-- tests/bin/check-i18n-pot.php | 10 ++--- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/.github/workflows/plugin-ci-workflow.yml b/.github/workflows/plugin-ci-workflow.yml index e9dd76c..3f75bde 100644 --- a/.github/workflows/plugin-ci-workflow.yml +++ b/.github/workflows/plugin-ci-workflow.yml @@ -43,7 +43,7 @@ jobs: strategy: fail-fast: false matrix: - php: ['8.3', '8.4'] + php: ['8.2', '8.3', '8.4'] os: [ubuntu-latest] services: diff --git a/tests/Security/PhpCompatibilityTest.php b/tests/Security/PhpCompatibilityTest.php index 8647ce0..7ded00e 100644 --- a/tests/Security/PhpCompatibilityTest.php +++ b/tests/Security/PhpCompatibilityTest.php @@ -23,10 +23,9 @@ */ /* - * Verify plugin source files do not use PHP 8.4-only syntax. - * This plugin's floor version is PHP 8.3, matching the shared CI test - * matrix (php: ['8.3', '8.4']) - this repo tracks Cacti's `develop` branch - * rather than `1.2.x`, which requires PHP 8.3+. + * Verify plugin source files do not use PHP 8.3+/8.4-only syntax. This plugin's + * floor version is PHP 8.2, matching the shared CI test matrix + * (php: ['8.2', '8.3', '8.4']). */ // Discovered recursively so new production PHP files are covered automatically. @@ -85,6 +84,16 @@ function plugin_test_read_source_file($relativeFile) { } }); +it('does not use the #[Override] attribute (PHP 8.3)', function () use ($files) { + foreach ($files as $relativeFile) { + $contents = plugin_test_read_source_file($relativeFile); + + expect(preg_match('/#\[\s*\\\\?Override\s*\]/i', $contents))->toBe(0, + "{$relativeFile} uses #[Override] which requires PHP 8.3" + ); + } +}); + it('does not use the #[Deprecated] attribute (PHP 8.4)', function () use ($files) { foreach ($files as $relativeFile) { $contents = plugin_test_read_source_file($relativeFile); @@ -95,6 +104,16 @@ function plugin_test_read_source_file($relativeFile) { } }); +it('does not use json_validate() (PHP 8.3)', function () use ($files) { + foreach ($files as $relativeFile) { + $contents = plugin_test_read_source_file($relativeFile); + + expect(preg_match('/\bjson_validate\s*\(/', $contents))->toBe(0, + "{$relativeFile} uses json_validate() which requires PHP 8.3" + ); + } +}); + it('does not use array_find()/array_any()/array_all() (PHP 8.4)', function () use ($files) { foreach ($files as $relativeFile) { $contents = plugin_test_read_source_file($relativeFile); @@ -105,6 +124,26 @@ function plugin_test_read_source_file($relativeFile) { } }); +it('does not use typed class constants (PHP 8.3)', function () use ($files) { + foreach ($files as $relativeFile) { + $contents = plugin_test_read_source_file($relativeFile); + + expect(preg_match('/\bconst\s+(?:\?\s*)?[A-Za-z_\\\\][A-Za-z0-9_\\\\]*(?:\s*\|\s*(?:\?\s*)?[A-Za-z_\\\\][A-Za-z0-9_\\\\]*)*\s+[A-Za-z_][A-Za-z0-9_]*\s*=/', $contents))->toBe(0, + "{$relativeFile} uses a typed class constant which requires PHP 8.3" + ); + } +}); + +it('does not use a dynamic class constant fetch (PHP 8.3)', function () use ($files) { + foreach ($files as $relativeFile) { + $contents = plugin_test_read_source_file($relativeFile); + + expect(preg_match('/::\s*\{\s*\$/', $contents))->toBe(0, + "{$relativeFile} uses a dynamic class constant fetch (Foo::" . '{$bar}' . ') which requires PHP 8.3' + ); + } +}); + it('does not use each() (removed in PHP 8.0)', function () use ($files) { foreach ($files as $relativeFile) { $contents = plugin_test_read_source_file($relativeFile); diff --git a/tests/bin/check-i18n-pot.php b/tests/bin/check-i18n-pot.php index 1e45fb6..cddc4ef 100644 --- a/tests/bin/check-i18n-pot.php +++ b/tests/bin/check-i18n-pot.php @@ -65,13 +65,13 @@ '__date' => [1], ]; -/* Repository-relative path of the template the plugin must keep in sync. */ +// Repository-relative path of the template the plugin must keep in sync. $pot_path = 'locales/po/cacti.pot'; $base_ref = isset($argv[1]) ? trim($argv[1]) : ''; if ($base_ref === '') { - $env = getenv('GITHUB_BASE_REF'); + $env = getenv('GITHUB_BASE_REF'); $base_ref = ($env !== false) ? trim($env) : ''; } @@ -85,12 +85,12 @@ * Make sure the base commit is present. With fetch-depth: 0 it already is, but * a branch-name ref may still need fetching on a shallow checkout. */ -$probe = []; +$probe = []; $probe_status = 0; exec('git rev-parse --verify --quiet ' . escapeshellarg($base_ref . '^{commit}'), $probe, $probe_status); if ($probe_status !== 0) { - $ignore = []; + $ignore = []; $ignore_status = 0; exec('git fetch --quiet --no-tags --depth=200 origin ' . escapeshellarg($base_ref), $ignore, $ignore_status); } @@ -202,7 +202,7 @@ function template_files($ref) { exec('git ls-tree -r --name-only ' . escapeshellarg($ref), $output, $status); if ($status !== 0) { - fwrite(STDERR, "git ls-tree failed for " . $ref . "\n"); + fwrite(STDERR, 'git ls-tree failed for ' . $ref . "\n"); exit(2); } From 7ad86fc59998f2a9114c4c40360d5d45e393c412 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Mon, 5 Oct 2026 14:08:33 -0400 Subject: [PATCH 2/3] Declare PHP 8.2 minimum in composer.json Add a plugin-local composer.json documenting the supported PHP floor (>=8.2) to match the CI matrix. This is declarative metadata; CI runs Composer against the Cacti core tree, so this file is inert for the test harness. --- composer.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..3c7930f --- /dev/null +++ b/composer.json @@ -0,0 +1,16 @@ +{ + "name": "cacti/plugin_reportit", + "description": "Reporting tool for Cacti", + "homepage": "https://github.com/Cacti/plugin_reportit", + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "The Cacti Group", + "email": "reportit@outlook.com", + "homepage": "https://www.cacti.net" + } + ], + "require": { + "php": ">=8.2" + } +} From 6d4b115116ca782dfb2b604311ddb6180e539adf Mon Sep 17 00:00:00 2001 From: TheWitness Date: Mon, 5 Oct 2026 14:38:26 -0400 Subject: [PATCH 3/3] ci: Drop PHP 8.2, add PHP 8.5 to the matrix Cacti develop requires PHP ^8.3, so 8.2 can never install its Composer dependencies (platform_check enforces >= 8.3.0). Remove 8.2 and add 8.5 instead; 8.5 satisfies the >= 8.3.0 floor and no locked dependency caps below it. Restore the documented 8.3 floor and bump composer.json to >=8.3. --- .github/workflows/plugin-ci-workflow.yml | 2 +- composer.json | 2 +- tests/Security/PhpCompatibilityTest.php | 47 ++---------------------- 3 files changed, 6 insertions(+), 45 deletions(-) diff --git a/.github/workflows/plugin-ci-workflow.yml b/.github/workflows/plugin-ci-workflow.yml index 3f75bde..0b1b657 100644 --- a/.github/workflows/plugin-ci-workflow.yml +++ b/.github/workflows/plugin-ci-workflow.yml @@ -43,7 +43,7 @@ jobs: strategy: fail-fast: false matrix: - php: ['8.2', '8.3', '8.4'] + php: ['8.3', '8.4', '8.5'] os: [ubuntu-latest] services: diff --git a/composer.json b/composer.json index 3c7930f..6baef75 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,6 @@ } ], "require": { - "php": ">=8.2" + "php": ">=8.3" } } diff --git a/tests/Security/PhpCompatibilityTest.php b/tests/Security/PhpCompatibilityTest.php index 7ded00e..333ecc6 100644 --- a/tests/Security/PhpCompatibilityTest.php +++ b/tests/Security/PhpCompatibilityTest.php @@ -23,9 +23,10 @@ */ /* - * Verify plugin source files do not use PHP 8.3+/8.4-only syntax. This plugin's - * floor version is PHP 8.2, matching the shared CI test matrix - * (php: ['8.2', '8.3', '8.4']). + * Verify plugin source files do not use PHP 8.4+/8.5-only syntax. + * This plugin's floor version is PHP 8.3, matching the shared CI test + * matrix (php: ['8.3', '8.4', '8.5']) - this repo tracks Cacti's `develop` branch + * rather than `1.2.x`, which requires PHP 8.3+. */ // Discovered recursively so new production PHP files are covered automatically. @@ -84,16 +85,6 @@ function plugin_test_read_source_file($relativeFile) { } }); -it('does not use the #[Override] attribute (PHP 8.3)', function () use ($files) { - foreach ($files as $relativeFile) { - $contents = plugin_test_read_source_file($relativeFile); - - expect(preg_match('/#\[\s*\\\\?Override\s*\]/i', $contents))->toBe(0, - "{$relativeFile} uses #[Override] which requires PHP 8.3" - ); - } -}); - it('does not use the #[Deprecated] attribute (PHP 8.4)', function () use ($files) { foreach ($files as $relativeFile) { $contents = plugin_test_read_source_file($relativeFile); @@ -104,16 +95,6 @@ function plugin_test_read_source_file($relativeFile) { } }); -it('does not use json_validate() (PHP 8.3)', function () use ($files) { - foreach ($files as $relativeFile) { - $contents = plugin_test_read_source_file($relativeFile); - - expect(preg_match('/\bjson_validate\s*\(/', $contents))->toBe(0, - "{$relativeFile} uses json_validate() which requires PHP 8.3" - ); - } -}); - it('does not use array_find()/array_any()/array_all() (PHP 8.4)', function () use ($files) { foreach ($files as $relativeFile) { $contents = plugin_test_read_source_file($relativeFile); @@ -124,26 +105,6 @@ function plugin_test_read_source_file($relativeFile) { } }); -it('does not use typed class constants (PHP 8.3)', function () use ($files) { - foreach ($files as $relativeFile) { - $contents = plugin_test_read_source_file($relativeFile); - - expect(preg_match('/\bconst\s+(?:\?\s*)?[A-Za-z_\\\\][A-Za-z0-9_\\\\]*(?:\s*\|\s*(?:\?\s*)?[A-Za-z_\\\\][A-Za-z0-9_\\\\]*)*\s+[A-Za-z_][A-Za-z0-9_]*\s*=/', $contents))->toBe(0, - "{$relativeFile} uses a typed class constant which requires PHP 8.3" - ); - } -}); - -it('does not use a dynamic class constant fetch (PHP 8.3)', function () use ($files) { - foreach ($files as $relativeFile) { - $contents = plugin_test_read_source_file($relativeFile); - - expect(preg_match('/::\s*\{\s*\$/', $contents))->toBe(0, - "{$relativeFile} uses a dynamic class constant fetch (Foo::" . '{$bar}' . ') which requires PHP 8.3' - ); - } -}); - it('does not use each() (removed in PHP 8.0)', function () use ($files) { foreach ($files as $relativeFile) { $contents = plugin_test_read_source_file($relativeFile);