From 0c2ffe21b42c6088f2a6a833dc08585beb0b8ea9 Mon Sep 17 00:00:00 2001 From: Lennart Van Vaerenbergh Date: Fri, 11 Sep 2026 16:12:52 +0200 Subject: [PATCH] Add phpunit 12 support and drop phpunit 9 and 10 --- .github/workflows/ci.yml | 44 +++++++++++++ .gitignore | 3 + .travis.yml | 12 ---- CHANGELOG.md | 17 +++++ README.md | 12 +++- composer.json | 66 +++++++++++-------- configs/phpstan.neon | 1 + configs/phpunit-11.xml | 27 ++++++++ configs/phpunit.xml | 13 ++-- .../EventListener/TaskEventListener.php | 36 +++++++--- src/GrumPHP/PhpunitConfigResolver.php | 30 +++++++++ stubs/GrumPHP/Event/TaskEvent.stub.php | 16 +++++ stubs/GrumPHP/Task/PhpMd.stub.php | 9 +++ stubs/GrumPHP/Task/PhpStan.stub.php | 9 +++ stubs/GrumPHP/Task/Phpcs.stub.php | 9 +++ stubs/GrumPHP/Task/Phpunit.stub.php | 9 +++ stubs/GrumPHP/Task/TaskInterface.stub.php | 9 +++ tests/GrumPHP/PhpunitConfigResolverTest.php | 48 ++++++++++++++ 18 files changed, 312 insertions(+), 58 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml create mode 100644 configs/phpunit-11.xml create mode 100644 src/GrumPHP/PhpunitConfigResolver.php create mode 100644 stubs/GrumPHP/Event/TaskEvent.stub.php create mode 100644 stubs/GrumPHP/Task/PhpMd.stub.php create mode 100644 stubs/GrumPHP/Task/PhpStan.stub.php create mode 100644 stubs/GrumPHP/Task/Phpcs.stub.php create mode 100644 stubs/GrumPHP/Task/Phpunit.stub.php create mode 100644 stubs/GrumPHP/Task/TaskInterface.stub.php create mode 100644 tests/GrumPHP/PhpunitConfigResolverTest.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..15a4c95 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: Run CI test + +on: + pull_request: + push: + branches: + - main + - develop + - release/** + - hotfix/** + tags: + workflow_dispatch: + +jobs: + qa: + name: Full QA / PHP 8.3 / PHPUnit 12 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + coverage: xdebug + - run: composer update --prefer-dist --no-interaction + - run: composer validate --strict + - run: composer normalize --dry-run + - run: vendor/bin/grumphp run --no-interaction --tasks="" + + phpunit: + name: PHPUnit ${{ matrix.phpunit }} / PHP ${{ matrix.php }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['8.3', '8.4', '8.5'] + phpunit: ['11.5', '12.5'] + steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: xdebug + - run: composer update --prefer-dist --no-interaction --with-all-dependencies --with="phpunit/phpunit:^${{ matrix.phpunit }}" + - run: vendor/bin/grumphp run --no-interaction --tasks=phpunit diff --git a/.gitignore b/.gitignore index fec57ba..ddefb22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /vendor/ /composer.lock +/build/ +/.phpunit.result.cache +/*.qa-php.* /configs/behat.merged.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ec11b8b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -dist: jammy - -language: php -php: - - 8.1 - - 8.2 - - 8.3 - -sudo: false - -script: - - composer install -n diff --git a/CHANGELOG.md b/CHANGELOG.md index 4455092..e04d37f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All Notable changes to the **Quality Assurance - PHP** package. +## [3.0.0] + +### Changed + +- Require PHP 8.3 or later. +- Support PHPUnit 11.5 and 12.5 only. +- Refresh the bundled QA tool dependencies and replace Travis CI with GitHub + Actions. PHPCompatibility 9 requires PHPCS 3, which in turn limits Slevomat + to 8.22. PHPCPD 8 and 9 are supported so Composer can select the compatible + `phpunit/php-timer` dependency for PHPUnit 11 or 12. + +### Fixed + +- Generate a PHPUnit-version-specific `phpunit.qa-php.xml` configuration with + a current XML schema and code-coverage filter. + ## [2.2.1] ### Added @@ -75,6 +91,7 @@ Initial setup of the qa-php package: - Add support for PHP 7.3+ - Add support for PHP 8.0+ +[3.0.0]: https://github.com/district09/php_package_qa-php/compare/2.2.1...3.0.0 [2.2.1]: https://github.com/district09/php_package_qa-php/compare/2.2.0...2.2.1 [2.2.0]: https://github.com/district09/php_package_qa-php/compare/2.1.0...2.2.0 [2.1.0]: https://github.com/district09/php_package_qa-php/compare/2.0.0...2.1.0 diff --git a/README.md b/README.md index 933fac4..e6772e7 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,11 @@ Add the `grumphp` entry to the `extra` section of your `composer.json`. Add the qa-php package as dev requirement: ```bash -composer require --dev district09/qa-php:^2.0 +composer require --dev district09/qa-php:^3.0 ``` +QA PHP 3 requires PHP 8.3 or later and supports PHPUnit 11.5 and 12.5. + ## Configuration ### General @@ -98,7 +100,11 @@ file: Running PHPUnit with coverage report is time consuming. You can locally speed up PHPUnit by copying the generated `phpunit.qa-php.xml` file to -`phpunit.local.xml` and remove the `` section from it. +`phpunit.local.xml` and removing the `` section from it. + +The generated configuration automatically uses the appropriate XML schema for +PHPUnit 11.5 or 12.5. Do not add a project-level `phpunit.xml` only to update +the PHPUnit schema; remove such overrides when upgrading to QA PHP 3. ## Run GrumPHP @@ -143,5 +149,5 @@ Configure the paths to these files in PHPStorm: In order to check php compatibility you can use the phpcs `PHPCompatibility` sniff: ```bash -php vendor/bin/phpcs -p --ignore="*/vendor/*" --extensions=php,inc,module,install,theme --runtime-set testVersion 8.1 --standard=PHPCompatibility ./ +php vendor/bin/phpcs -p --ignore="*/vendor/*" --extensions=php,inc,module,install,theme --runtime-set testVersion 8.3 --standard=PHPCompatibility ./ ``` diff --git a/composer.json b/composer.json index 46be153..0a49eac 100644 --- a/composer.json +++ b/composer.json @@ -1,14 +1,13 @@ { "name": "district09/qa-php", "description": "Quality Assurance tools and configuration for PHP projects and packages.", + "license": "MIT", + "type": "library", "keywords": [ "district09", "qa", "php" ], - "type": "library", - "homepage": "https://github.com/digipolisgent/php_package_qa-php", - "license": "MIT", "authors": [ { "name": "Matthijs Van Assche", @@ -26,37 +25,48 @@ "role": "developer" } ], + "homepage": "https://github.com/digipolisgent/php_package_qa-php", + "require": { + "php": "^8.3", + "enlightn/security-checker": "^2.0", + "ergebnis/composer-normalize": "^2.53", + "nette/neon": "^3.4", + "phpcompatibility/php-compatibility": "^9.3.5", + "phpmd/phpmd": "^2.15", + "phpro/grumphp-shim": "^2.23", + "phpspec/prophecy": "^1.26", + "phpspec/prophecy-phpunit": "^2.5", + "phpstan/phpstan": "^2.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpunit/phpunit": "^11.5 || ^12.5", + "slevomat/coding-standard": "^8.22", + "squizlabs/php_codesniffer": "^3.13.6", + "symfony/filesystem": "^6.4 || ^7.0", + "systemsdk/phpcpd": "^8.0 || ^9.0" + }, "minimum-stability": "dev", "prefer-stable": true, - "config": { - "sort-packages": true, - "allow-plugins": { - "ergebnis/composer-normalize": true, - "phpro/grumphp-shim": true, - "dealerdirect/phpcodesniffer-composer-installer": true - } - }, "autoload": { "psr-4": { "District09\\QA\\PHP\\": "src/" } }, - "require": { - "php": "^8.1", - "enlightn/security-checker": "^1.4|^2.0", - "ergebnis/composer-normalize": "^2.8", - "nette/neon": "^3.2", - "phpcompatibility/php-compatibility": "^9.3", - "phpmd/phpmd": "^2.11", - "phpro/grumphp-shim": "^2.0", - "phpspec/prophecy": "^1.10", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/phpstan": "^1.0 || ^2.0", - "phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0", - "phpunit/phpunit": "^9 || ^10 || ^11 || ^12", - "slevomat/coding-standard": "^8.15", - "squizlabs/php_codesniffer": "^3.5.6", - "symfony/filesystem": "^5.2|^6.0|^7.0", - "systemsdk/phpcpd": "^7.0 || ^8.0" + "autoload-dev": { + "psr-4": { + "District09\\QA\\PHP\\Tests\\": "tests/" + } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "ergebnis/composer-normalize": true, + "phpro/grumphp-shim": true + }, + "sort-packages": true + }, + "extra": { + "grumphp": { + "config-default-path": "configs/grumphp.yml" + } } } diff --git a/configs/phpstan.neon b/configs/phpstan.neon index 6b8cde1..9bb9ed1 100644 --- a/configs/phpstan.neon +++ b/configs/phpstan.neon @@ -8,3 +8,4 @@ parameters: scanDirectories: - %currentWorkingDirectory%/src - %currentWorkingDirectory%/tests + - %currentWorkingDirectory%/stubs diff --git a/configs/phpunit-11.xml b/configs/phpunit-11.xml new file mode 100644 index 0000000..70850c1 --- /dev/null +++ b/configs/phpunit-11.xml @@ -0,0 +1,27 @@ + + + + + src + + + src + + + + + + + + + + + tests + + + diff --git a/configs/phpunit.xml b/configs/phpunit.xml index e483141..85d9ca5 100644 --- a/configs/phpunit.xml +++ b/configs/phpunit.xml @@ -3,16 +3,17 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" colors="true" - verbose="true" - xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.5/phpunit.xsd" > - + - src/ + src - src/ + src + + @@ -20,7 +21,7 @@ - + tests diff --git a/src/GrumPHP/EventListener/TaskEventListener.php b/src/GrumPHP/EventListener/TaskEventListener.php index 7f38846..8f82bfe 100644 --- a/src/GrumPHP/EventListener/TaskEventListener.php +++ b/src/GrumPHP/EventListener/TaskEventListener.php @@ -4,6 +4,7 @@ namespace District09\QA\PHP\GrumPHP\EventListener; +use District09\QA\PHP\GrumPHP\PhpunitConfigResolver; use GrumPHP\Event\TaskEvent; use GrumPHP\Task\Phpcs; use GrumPHP\Task\PhpMd; @@ -11,6 +12,7 @@ use GrumPHP\Task\Phpunit; use GrumPHP\Task\TaskInterface; use Nette\Neon\Neon; +use PHPUnit\Runner\Version; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Yaml\Yaml; @@ -65,6 +67,8 @@ final class TaskEventListener * * @param TaskEvent $event * The GrumPHP task event. + * + * @SuppressWarnings("PHPMD.Superglobals") */ public function createTaskConfig(TaskEvent $event): void { @@ -98,21 +102,16 @@ public function createTaskConfig(TaskEvent $event): void $info['filename'], $info['extension'] ), - $keyPrefix . 'GLOBAL' => sprintf( - '%s%s.%s', - $packagePath, - $info['filename'], - $info['extension'] - ), + $keyPrefix . 'GLOBAL' => $this->getGlobalConfigFile($info, $packagePath), ]; // Search for the candidates and merge or copy them. $filesystem = new Filesystem(); $dataMerged = []; - foreach ($candidates as $env_var => $file) { + foreach ($candidates as $envVar => $file) { // Ignore if configured to skip or if the file is missing. - if (!empty($_SERVER[$env_var]) || !$filesystem->exists($file)) { + if (!empty($GLOBALS['_SERVER'][$envVar]) || !$filesystem->exists($file)) { continue; } @@ -159,6 +158,25 @@ private function getTaskConfigFileInfo(TaskInterface $task): ?array return $info; } + /** + * Gets the global configuration file for a GrumPHP task. + * + * @param array $info + * The task configuration information. + * @param string $packagePath + * The bundled configuration directory. + */ + private function getGlobalConfigFile(array $info, string $packagePath): string + { + if ($info['filename'] === 'phpunit') { + $filename = PhpunitConfigResolver::resolve(Version::majorVersionNumber()); + + return $packagePath . $filename; + } + + return sprintf('%s%s.%s', $packagePath, $info['filename'], $info['extension']); + } + /** * Read and parse a task configuration file. * @@ -190,7 +208,7 @@ private function readTaskConfigFile(string $type, string $file): array|bool * The file type. * @param string $file * Path to the file. - * @param array|null $data + * @param array $data * The configuration data. */ private function writeTaskConfigFile(string $type, string $file, array $data): void diff --git a/src/GrumPHP/PhpunitConfigResolver.php b/src/GrumPHP/PhpunitConfigResolver.php new file mode 100644 index 0000000..7e7c169 --- /dev/null +++ b/src/GrumPHP/PhpunitConfigResolver.php @@ -0,0 +1,30 @@ + 'phpunit-11.xml', + 12 => 'phpunit.xml', + default => throw new LogicException(sprintf( + 'Unsupported PHPUnit major version %d. Supported versions are 11 and 12.', + $majorVersion, + )), + }; + } +} diff --git a/stubs/GrumPHP/Event/TaskEvent.stub.php b/stubs/GrumPHP/Event/TaskEvent.stub.php new file mode 100644 index 0000000..9ffe72a --- /dev/null +++ b/stubs/GrumPHP/Event/TaskEvent.stub.php @@ -0,0 +1,16 @@ + + */ + public static function supportedPhpunitVersions(): array + { + return [ + 'PHPUnit 11' => [11, 'phpunit-11.xml'], + 'PHPUnit 12' => [12, 'phpunit.xml'], + ]; + } + + /** + * Tests resolving an unsupported PHPUnit version. + */ + public function testResolveRejectsUnsupportedPhpunitVersion(): void + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Unsupported PHPUnit major version 13.'); + + PhpunitConfigResolver::resolve(13); + } +}