From 6db323ee2582a4be95be6dab4ac390641bb897b5 Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Fri, 23 Sep 2022 16:35:00 +0200 Subject: [PATCH 1/8] =?UTF-8?q?=E2=9C=A8=20add=20rector.php=20with=20first?= =?UTF-8?q?=20configuration=20try?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 20 +++--- grumphp.yml | 17 ++++- rector.php | 41 ++++++++++++ src/Composer/Plugin.php | 70 +++++++++++--------- src/RectorSettings.php | 142 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 248 insertions(+), 42 deletions(-) create mode 100644 rector.php create mode 100644 src/RectorSettings.php diff --git a/composer.json b/composer.json index ab3d649..c72d4d1 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ "*": "dist" }, "allow-plugins": { - "phpro/grumphp": true + "phpro/grumphp": true, + "phpstan/extension-installer": true } }, "support": { @@ -28,24 +29,27 @@ }, "autoload": { "psr-4": { - "PLUS\\": "src/" + "PLUS\\GrumPHPConfig\\": "src/" } }, "require": { "php": "~7.4 || ~8.0 || ~8.1", - "composer-plugin-api": "^1.0.0 || ^2.0.0", - "phpro/grumphp": "^1.5.1", + "composer-plugin-api": "^2.0.0", + "phpro/grumphp": "^1.13", "pluswerk/grumphp-bom-task": "^7.0.0", "pluswerk/grumphp-xliff-task": "^5.0.0", - "squizlabs/php_codesniffer": "^3.6.2", + "squizlabs/php_codesniffer": "^3.7.1", "enlightn/security-checker": "^1.10.0", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpstan/phpstan": "^1.4.7" + "phpstan/phpstan": "^1.8.6", + "phpstan/extension-installer": "^1.1", + "rector/rector": "^0.14.3", + "palpalani/grumphp-rector-task": "^0.8.6" }, "extra": { - "class": "PLUS\\Composer\\Plugin" + "class": "PLUS\\GrumPHPConfig\\Composer\\Plugin" }, "require-dev": { - "composer/composer": "^1.10.25 || ^2.2.7" + "composer/composer": "^2.4.2" } } diff --git a/grumphp.yml b/grumphp.yml index c5404e1..f58badc 100644 --- a/grumphp.yml +++ b/grumphp.yml @@ -1,11 +1,13 @@ parameters: - convention.process_timeout: 60 + convention.process_timeout: 240 convention.security_checker_blocking: true convention.jsonlint_ignore_pattern: [] convention.xmllint_ignore_pattern: [] convention.yamllint_ignore_pattern: [] convention.phpcslint_ignore_pattern: [] - convention.xlifflint_ignore_pattern: ["#typo3conf/l10n/(.*)#"] + convention.xlifflint_ignore_pattern: [] + convention.rector_ignore_pattern: [] + convention.rector_config: 'rector.php' convention.phpstan_level: max grumphp: stop_on_failure: false @@ -29,7 +31,7 @@ grumphp: ignore_patterns: "%convention.jsonlint_ignore_pattern%" phpcs: standard: "PSR12" - warning_severity: 900000 + warning_severity: 0 tab_width: 4 ignore_patterns: "%convention.phpcslint_ignore_pattern%" phpstan: @@ -49,6 +51,15 @@ grumphp: plus_bom_fixer: metadata: priority: 1 + rector: + whitelist_patterns: [ ] + config: "%convention.rector_config%" + triggered_by: [ 'php' ] + clear-cache: false + ignore_patterns: "%convention.rector_ignore_pattern%" + no-progress-bar: false + files_on_pre_commit: false extensions: - PLUS\GrumPHPBomTask\ExtensionLoader - PLUS\GrumPHPXliffTask\ExtensionLoader + - palPalani\GrumPhpRectorTask\ExtensionLoader diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..09e6f28 --- /dev/null +++ b/rector.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +use PLUS\GrumPHPConfig\RectorSettings; +use Rector\Config\RectorConfig; + +return static function (RectorConfig $rectorConfig): void { + $rectorConfig->parallel(240); + $rectorConfig->importNames(); + $rectorConfig->importShortClasses(); + + $rectorConfig->paths( + [ + //remove that you don't need + __DIR__ . '/src', + #__DIR__ . '/extensions', + ] + ); + + // define sets of rules + $rectorConfig->sets( + [ + ...RectorSettings::sets(), + ] + ); + + // remove some rules + // ignore some files + $rectorConfig->skip( + [ + ...RectorSettings::skip(), + + /** + * do not touch these files + */ + __DIR__ . '/src/Example', + __DIR__ . '/src/Example.php', + ] + ); +}; diff --git a/src/Composer/Plugin.php b/src/Composer/Plugin.php index 95c8f28..3740c1a 100644 --- a/src/Composer/Plugin.php +++ b/src/Composer/Plugin.php @@ -1,6 +1,6 @@ <?php -namespace PLUS\Composer; +namespace PLUS\GrumPHPConfig\Composer; use Composer\Composer; use Composer\DependencyResolver\Operation\InstallOperation; @@ -17,38 +17,25 @@ class Plugin implements PluginInterface, EventSubscriberInterface { + /** @var string */ private const PACKAGE_NAME = 'pluswerk/grumphp-config'; + + /** @var string */ private const DEFAULT_CONFIG_PATH = 'vendor/' . self::PACKAGE_NAME . '/grumphp.yml'; - /** - * @var Composer - */ protected Composer $composer; - /** - * @var IOInterface - */ - protected IOInterface $consoleIo; + protected IOInterface $io; - /** - * @var array<string, mixed> - */ - protected array $extra; + /** @var array<string, mixed> */ + protected array $extra = []; - /** - * @var bool - */ protected bool $shouldSetConfigPath = false; - /** - * @param \Composer\Composer $composer - * @param \Composer\IO\IOInterface $consoleIo - * @retrun void - */ - public function activate(Composer $composer, IOInterface $consoleIo): void + public function activate(Composer $composer, IOInterface $io): void { $this->composer = $composer; - $this->consoleIo = $consoleIo; + $this->io = $io; $this->extra = $this->composer->getPackage()->getExtra(); } @@ -64,6 +51,8 @@ public static function getSubscribedEvents(): array ScriptEvents::POST_INSTALL_CMD => 'runScheduledTasks', ScriptEvents::POST_UPDATE_CMD => 'runScheduledTasks', + + ScriptEvents::POST_AUTOLOAD_DUMP => 'postAutoloadDump', ]; } @@ -106,6 +95,7 @@ public function setConfigPath(): void $this->message('not setting config path, extra.' . self::PACKAGE_NAME . '.auto-setting is false', 'yellow'); return; } + $this->setExtra(self::PACKAGE_NAME . '.auto-setting', true); if ($this->getExtra('grumphp.config-default-path') !== self::DEFAULT_CONFIG_PATH) { $this->setExtra('grumphp.config-default-path', self::DEFAULT_CONFIG_PATH); @@ -119,6 +109,7 @@ public function removeConfigPath(): void $this->message('not removing config path, extra.' . self::PACKAGE_NAME . '.auto-setting is false', 'yellow'); return; } + unset($this->extra[self::PACKAGE_NAME]); $this->removeExtra(self::PACKAGE_NAME); @@ -128,6 +119,7 @@ public function removeConfigPath(): void } elseif ($this->getExtra()) { $key = 'grumphp'; } + $this->removeExtra($key); $this->message('auto removed config path and ' . self::PACKAGE_NAME . ' settings', 'green'); } @@ -143,26 +135,24 @@ public function getExtra(string $name = null) if ($name === null) { return $this->extra; } + $arr = $this->extra; $bits = explode('.', $name); $last = array_pop($bits); foreach ($bits as $bit) { - if (!isset($arr[$bit])) { - $arr[$bit] = []; - } + $arr[$bit] ??= []; + if (!is_array($arr[$bit])) { return null; } + $arr = &$arr[$bit]; } - if (isset($arr[$last])) { - return $arr[$last]; - } - return null; + + return $arr[$last] ?? null; } /** - * @param string $name * @param string|bool $value */ public function setExtra(string $name, $value): void @@ -177,6 +167,7 @@ public function removeExtra(string $name = null): void if ($name !== null) { $key .= '.' . $name; } + $configSource = $this->composer->getConfig()->getConfigSource(); $configSource->removeProperty($key); } @@ -189,7 +180,8 @@ public function message(string $message, string $color = null): void $colorStart = '<fg=' . $color . '>'; $colorEnd = '</fg=' . $color . '>'; } - $this->consoleIo->write(self::PACKAGE_NAME . ': ' . $colorStart . $message . $colorEnd); + + $this->io->write(self::PACKAGE_NAME . ': ' . $colorStart . $message . $colorEnd); } /** @@ -205,4 +197,20 @@ public function deactivate(Composer $composer, IOInterface $io): void public function uninstall(Composer $composer, IOInterface $io): void { } + + + // Rector config copy: + + public function postAutoloadDump(): void + { + $this->createRectorConfig(); + } + + private function createRectorConfig(): void + { + if (!file_exists(getcwd() . '/rector.php')) { + copy(dirname(__DIR__, 2) . '/rector.php', getcwd() . '/rector.php'); + $this->message('rector.php file created', 'yellow'); + } + } } diff --git a/src/RectorSettings.php b/src/RectorSettings.php new file mode 100644 index 0000000..27f4241 --- /dev/null +++ b/src/RectorSettings.php @@ -0,0 +1,142 @@ +<?php + +declare(strict_types=1); + +namespace PLUS\GrumPHPConfig; + +use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector; +use Rector\CodeQuality\Rector\If_\SimplifyIfElseToTernaryRector; +use Rector\CodeQuality\Rector\Isset_\IssetOnPropertyObjectToPropertyExistsRector; +use Rector\CodingStyle\Rector\ClassMethod\UnSpreadOperatorRector; +use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; +use Rector\CodingStyle\Rector\If_\NullableCompareToNullRector; +use Rector\CodingStyle\Rector\PostInc\PostIncDecToPreIncDecRector; +use Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector; +use Rector\Php70\Rector\Assign\ListSwapArrayOrderRector; +use Rector\Php74\Rector\LNumber\AddLiteralSeparatorToNumberRector; +use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; +use Rector\Privatization\Rector\Class_\ChangeReadOnlyVariableWithDefaultValueToConstantRector; +use Rector\Privatization\Rector\Class_\FinalizeClassesWithoutChildrenRector; +use Rector\Set\ValueObject\LevelSetList; +use Rector\Set\ValueObject\SetList; + +class RectorSettings +{ + /** + * @return array<int,string> + */ + public static function sets(): array + { + $phpfile = constant(LevelSetList::class . '::UP_TO_PHP_' . PHP_MAJOR_VERSION . PHP_MINOR_VERSION); + assert(is_string($phpfile)); + + return [ + // SetList::ACTION_INJECTION_TO_CONSTRUCTOR_INJECTION, // NO + SetList::CODE_QUALITY, // YES + SetList::CODING_STYLE, // YES + SetList::DEAD_CODE, // YES + //SetList::GMAGICK_TO_IMAGICK, // NO + //SetList::MONOLOG_20, // no usage + //SetList::MYSQL_TO_MYSQLI, // no usage + //SetList::NAMING, //NO is not good + $phpfile, + //SetList::PHP_52, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_53, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_54, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_55, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_56, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_70, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_71, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_72, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_73, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_74, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_80, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_81, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + //SetList::PHP_82, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... + SetList::PRIVATIZATION, // some things may be bad + SetList::PSR_4, // dose nothing? + SetList::TYPE_DECLARATION, // YES + SetList::TYPE_DECLARATION_STRICT, // YES please + SetList::EARLY_RETURN, //YES + //SetList::RECTOR_CONFIG, // NO + ]; + } + + /** + * @return array<int, string> + */ + public static function skip(): array + { + return [ + /** + * FROM: if($object) { + * TO: if($object !== null) { + */ + NullableCompareToNullRector::class, + /** + * FROM: $i++ + * TO: ++$i + */ + PostIncDecToPreIncDecRector::class, + /** + * FROM: if(count($array)) { + * TO: if($array !== []) { + */ + CountArrayToEmptyArrayComparisonRector::class, + /** + * FROM: switch($x) { + * TO: if($X === '...') { + */ + BinarySwitchToIfElseRector::class, + /** + * FROM: ->select('a', 'b') + * TO: ->select(['a', 'b']) + */ + UnSpreadOperatorRector::class, + /** + * FROM: $domain = 'https://efsrgtdhj'; + * TO: self::DOMAIN + */ + ChangeReadOnlyVariableWithDefaultValueToConstantRector::class, + /** + * FROM: class XYZ { + * TO: final class XYZ { + */ + FinalizeClassesWithoutChildrenRector::class, + /** + * DOCS: be careful, run this just once, since it can keep swapping order back and forth + * => we don't do it once! + */ + ListSwapArrayOrderRector::class, + /** + * FROM: 1305630314 + * TO: 1_305_630_314 + */ + AddLiteralSeparatorToNumberRector::class, + /** + * Maybe to a later date? + * + * FROM: public string $username = ''; + * TO: __construct(public string $username = '') + */ + ClassPropertyAssignToConstructorPromotionRector::class, + /** + * Maybe to a later date? + * + * FROM: if($x) { + * TO: $x ? $abcde + $xyz : $trsthjzuj - $gesrtdnzmf + */ + SimplifyIfElseToTernaryRector::class, + /** + * FROM: if ($timeInMinutes % 60) { + * TO: if ($timeInMinutes % 60 !== 0) { + */ + ExplicitBoolCompareRector::class, + /** + * FROM: isset($this->x); + * TO: property_exists($this, 'x') && $this->x !== null; + */ + IssetOnPropertyObjectToPropertyExistsRector::class, + ]; + } +} From 14a387b73422de2a6bc9dfc6b45059a944207857 Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Sat, 8 Oct 2022 12:27:48 +0200 Subject: [PATCH 2/8] Update rector.php --- rector.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rector.php b/rector.php index 09e6f28..06c03b0 100644 --- a/rector.php +++ b/rector.php @@ -14,7 +14,8 @@ [ //remove that you don't need __DIR__ . '/src', - #__DIR__ . '/extensions', + //__DIR__ . '/extensions', + //__DIR__ . '/Classes', ] ); @@ -32,10 +33,10 @@ ...RectorSettings::skip(), /** - * do not touch these files + * rector should not touch these files */ - __DIR__ . '/src/Example', - __DIR__ . '/src/Example.php', + //__DIR__ . '/src/Example', + //__DIR__ . '/src/Example.php', ] ); }; From ab3043c489bca7db86b76b17a5d8e5b534674acd Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Sun, 9 Oct 2022 11:22:20 +0200 Subject: [PATCH 3/8] =?UTF-8?q?=E2=9C=A8=20do=20not=20change=20composer.js?= =?UTF-8?q?on=20for=20grumphp.yml=20config=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/run-grumphp-test.yml | 3 +- composer.json | 102 +++++------ grumphp.yml | 4 +- phpstan-baseline.neon | 51 ++++++ phpstan.neon | 8 +- rector.php | 11 +- src/Composer/Plugin.php | 231 ++++++++++--------------- src/RectorSettings.php | 3 +- src/VersionUtility.php | 43 +++++ stubs/ConfigSourceInterface.stub | 15 -- 10 files changed, 253 insertions(+), 218 deletions(-) create mode 100644 phpstan-baseline.neon create mode 100644 src/VersionUtility.php delete mode 100644 stubs/ConfigSourceInterface.stub diff --git a/.github/workflows/run-grumphp-test.yml b/.github/workflows/run-grumphp-test.yml index 59bdd24..7472e64 100644 --- a/.github/workflows/run-grumphp-test.yml +++ b/.github/workflows/run-grumphp-test.yml @@ -9,14 +9,13 @@ jobs: - '7.4' - '8.0' - '8.1' + - '8.2-rc' composer: - install --no-progress --no-scripts -n - - require phpro/grumphp:* --no-progress --no-scripts -n - update --no-progress --no-scripts -n --prefer-lowest container: image: kanti/buildy:${{ matrix.php }} steps: - uses: actions/checkout@v2 - - run: jq '.config.platform.php = "${{ matrix.php }}"' composer.json > composer.json_tmp && mv composer.json_tmp composer.json - run: composer ${{ matrix.composer }} - run: ./vendor/bin/grumphp run diff --git a/composer.json b/composer.json index c72d4d1..2fc4106 100644 --- a/composer.json +++ b/composer.json @@ -1,55 +1,55 @@ { - "name": "pluswerk/grumphp-config", - "description": "GrumPHP config for php projects(mainly TYPO3)", - "type": "composer-plugin", - "license": "LGPL-3.0-or-later", - "authors": [ - { - "name": "Matthias Vogel", - "email": "matthias.vogel@pluswerk.ag", - "homepage": "http://pluswerk.ag" - } - ], - "config": { - "platform": { - "php": "7.4" - }, - "preferred-install": { - "pluswerk/grumphp-bom-task": "source", - "pluswerk/grumphp-xliff-task": "source", - "*": "dist" - }, - "allow-plugins": { - "phpro/grumphp": true, - "phpstan/extension-installer": true - } - }, - "support": { - "issues": "https://github.com/pluswerk/grumphp-config/issues" - }, - "autoload": { - "psr-4": { - "PLUS\\GrumPHPConfig\\": "src/" - } - }, - "require": { - "php": "~7.4 || ~8.0 || ~8.1", - "composer-plugin-api": "^2.0.0", - "phpro/grumphp": "^1.13", - "pluswerk/grumphp-bom-task": "^7.0.0", - "pluswerk/grumphp-xliff-task": "^5.0.0", - "squizlabs/php_codesniffer": "^3.7.1", - "enlightn/security-checker": "^1.10.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpstan/phpstan": "^1.8.6", - "phpstan/extension-installer": "^1.1", - "rector/rector": "^0.14.3", - "palpalani/grumphp-rector-task": "^0.8.6" - }, - "extra": { - "class": "PLUS\\GrumPHPConfig\\Composer\\Plugin" + "name" : "pluswerk/grumphp-config", + "description" : "GrumPHP config for php projects(mainly TYPO3)", + "type" : "composer-plugin", + "license" : "LGPL-3.0-or-later", + "authors" : [ + { + "name" : "Matthias Vogel", + "email" : "matthias.vogel@pluswerk.ag", + "homepage" : "https://pluswerk.ag" + } + ], + "config" : { + "preferred-install" : { + "pluswerk/grumphp-bom-task" : "source", + "pluswerk/grumphp-xliff-task" : "source", + "*" : "dist" }, - "require-dev": { - "composer/composer": "^2.4.2" + "allow-plugins" : { + "phpro/grumphp" : true, + "phpstan/extension-installer" : true + } + }, + "support" : { + "issues" : "https://github.com/pluswerk/grumphp-config/issues" + }, + "autoload" : { + "psr-4" : { + "PLUS\\GrumPHPConfig\\" : "src/" } + }, + "require" : { + "php" : "~7.4 || ~8.0 || ~8.1 || ~8.2", + "composer-plugin-api" : "^2.1.0", + "phpro/grumphp" : "^1.13", + "pluswerk/grumphp-bom-task" : "^7.0.0", + "pluswerk/grumphp-xliff-task" : "^5.0.0", + "squizlabs/php_codesniffer" : "^3.7.1", + "enlightn/security-checker" : "^1.10.0", + "php-parallel-lint/php-parallel-lint" : "^1.3.2", + "phpstan/phpstan" : "^1.8.8", + "phpstan/extension-installer" : "^1.1", + "rector/rector" : "^0.14.5", + "palpalani/grumphp-rector-task" : "^0.8.6", + "composer/semver" : "^3.3.0", + "symfony/yaml" : "^5.4.0 || ^6.0" + }, + "extra" : { + "class" : "PLUS\\GrumPHPConfig\\Composer\\Plugin" + }, + "require-dev" : { + "roave/security-advisories" : "dev-latest", + "composer/composer" : "^2.4.2" + } } diff --git a/grumphp.yml b/grumphp.yml index f58badc..c4ed91a 100644 --- a/grumphp.yml +++ b/grumphp.yml @@ -8,7 +8,9 @@ parameters: convention.xlifflint_ignore_pattern: [] convention.rector_ignore_pattern: [] convention.rector_config: 'rector.php' + convention.rector_clear-cache: false convention.phpstan_level: max + grumphp: stop_on_failure: false hide_circumvention_tip: true @@ -55,7 +57,7 @@ grumphp: whitelist_patterns: [ ] config: "%convention.rector_config%" triggered_by: [ 'php' ] - clear-cache: false + clear-cache: "%convention.rector_clear-cache%" ignore_patterns: "%convention.rector_ignore_pattern%" no-progress-bar: false files_on_pre_commit: false diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..d396b7f --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,51 @@ +parameters: + ignoreErrors: + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/Composer/Plugin.php + + - + message: "#^Cannot access offset 'config\\-default\\-path' on mixed\\.$#" + count: 1 + path: src/Composer/Plugin.php + + - + message: "#^Cannot access offset 'imports' on mixed\\.$#" + count: 1 + path: src/Composer/Plugin.php + + - + message: "#^Cannot access offset 'parameters' on mixed\\.$#" + count: 2 + path: src/Composer/Plugin.php + + - + message: "#^Cannot access offset 'resource' on mixed\\.$#" + count: 1 + path: src/Composer/Plugin.php + + - + message: "#^Cannot access offset 0 on mixed\\.$#" + count: 1 + path: src/Composer/Plugin.php + + - + message: "#^Cannot access offset mixed on mixed\\.$#" + count: 2 + path: src/Composer/Plugin.php + + - + message: "#^Cannot cast mixed to string\\.$#" + count: 1 + path: src/Composer/Plugin.php + + - + message: "#^Cannot access offset 'php' on mixed\\.$#" + count: 1 + path: src/VersionUtility.php + + - + message: "#^Method PLUS\\\\GrumPHPConfig\\\\VersionUtility\\:\\:getRootComposerJsonData\\(\\) should return array but returns mixed\\.$#" + count: 1 + path: src/VersionUtility.php diff --git a/phpstan.neon b/phpstan.neon index 8682e43..4bbcb1f 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,7 @@ +includes: + - phpstan-baseline.neon + parameters: - stubFiles: - - stubs/ConfigSourceInterface.stub + level: max + paths: + - src diff --git a/rector.php b/rector.php index 06c03b0..3ddaa30 100644 --- a/rector.php +++ b/rector.php @@ -11,12 +11,11 @@ $rectorConfig->importShortClasses(); $rectorConfig->paths( - [ - //remove that you don't need - __DIR__ . '/src', - //__DIR__ . '/extensions', - //__DIR__ . '/Classes', - ] + array_filter([ + is_dir(__DIR__ . '/src') ? __DIR__ . '/src' : null, + is_dir(__DIR__ . '/extensions') ? __DIR__ . '/extensions' : null, + is_dir(__DIR__ . '/Classes') ? __DIR__ . '/Classes' : null, + ]) ); // define sets of rules diff --git a/src/Composer/Plugin.php b/src/Composer/Plugin.php index 3740c1a..8fb0d20 100644 --- a/src/Composer/Plugin.php +++ b/src/Composer/Plugin.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace PLUS\GrumPHPConfig\Composer; use Composer\Composer; @@ -11,32 +13,36 @@ use Composer\Installer\PackageEvents; use Composer\IO\IOInterface; use Composer\Plugin\PluginInterface; -use Composer\Script\Event; use Composer\Script\ScriptEvents; -use GrumPHP\Event\TaskEvents; +use GrumPHP\Configuration\Configuration; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\Routing\Loader\YamlFileLoader; +use Symfony\Component\Yaml\Yaml; -class Plugin implements PluginInterface, EventSubscriberInterface +final class Plugin implements PluginInterface, EventSubscriberInterface { - /** @var string */ - private const PACKAGE_NAME = 'pluswerk/grumphp-config'; - - /** @var string */ - private const DEFAULT_CONFIG_PATH = 'vendor/' . self::PACKAGE_NAME . '/grumphp.yml'; - - protected Composer $composer; + private Composer $composer; - protected IOInterface $io; - - /** @var array<string, mixed> */ - protected array $extra = []; - - protected bool $shouldSetConfigPath = false; + private IOInterface $io; public function activate(Composer $composer, IOInterface $io): void { $this->composer = $composer; $this->io = $io; - $this->extra = $this->composer->getPackage()->getExtra(); + } + + /** + * {@inheritdoc} + */ + public function deactivate(Composer $composer, IOInterface $io): void + { + } + + /** + * {@inheritdoc} + */ + public function uninstall(Composer $composer, IOInterface $io): void + { } /** @@ -45,134 +51,109 @@ public function activate(Composer $composer, IOInterface $io): void public static function getSubscribedEvents(): array { return [ - PackageEvents::POST_PACKAGE_UPDATE => 'postPackageUpdate', - PackageEvents::POST_PACKAGE_INSTALL => 'postPackageInstall', - PackageEvents::PRE_PACKAGE_UNINSTALL => 'prePackageUninstall', + PackageEvents::POST_PACKAGE_UPDATE => 'heavyProcessing', + PackageEvents::POST_PACKAGE_INSTALL => 'heavyProcessing', - ScriptEvents::POST_INSTALL_CMD => 'runScheduledTasks', - ScriptEvents::POST_UPDATE_CMD => 'runScheduledTasks', + ScriptEvents::POST_INSTALL_CMD => 'heavyProcessing', + ScriptEvents::POST_UPDATE_CMD => 'heavyProcessing', - ScriptEvents::POST_AUTOLOAD_DUMP => 'postAutoloadDump', + ScriptEvents::POST_AUTOLOAD_DUMP => 'simpleProcessing', ]; } - public function postPackageUpdate(PackageEvent $event): void + public function heavyProcessing(): void { - $operation = $event->getOperation(); - if ($operation instanceof UpdateOperation && $operation->getTargetPackage()->getName() === self::PACKAGE_NAME) { - $this->shouldSetConfigPath = true; - } + $this->removeOldConfigPath(); + $this->createGrumphpConfig(); + + $this->simpleProcessing(); } - public function postPackageInstall(PackageEvent $event): void + public function simpleProcessing(): void { - $operation = $event->getOperation(); - if ($operation instanceof InstallOperation && $operation->getPackage()->getName() === self::PACKAGE_NAME) { - $this->shouldSetConfigPath = true; - } + $this->createRectorConfig(); } - public function prePackageUninstall(PackageEvent $event): void + private function removeOldConfigPath(): void { - $operation = $event->getOperation(); - if ($operation instanceof UninstallOperation && $operation->getPackage()->getName() === self::PACKAGE_NAME) { - $this->removeConfigPath(); + $rootPackage = $this->composer->getPackage(); + $extra = $rootPackage->getExtra(); + $configSource = $this->composer->getConfig()->getConfigSource(); + + $configDefaultPath = $extra['grumphp']['config-default-path'] ?? ''; + if (in_array($configDefaultPath, ['grumphp.yml', 'vendor/pluswerk/grumphp-config/grumphp.yml'])) { + unset($extra['grumphp']['config-default-path']); + $configSource->removeProperty('extra.grumphp.config-default-path'); + $this->message('removed extra.grumphp.config-default-path', 'yellow'); + if (empty($extra['grumphp'])) { + unset($extra['grumphp']); + $configSource->removeProperty('extra.grumphp'); + $this->message('removed extra.grumphp', 'yellow'); + } } - } - public function runScheduledTasks(): void - { - if ($this->shouldSetConfigPath) { - $this->setConfigPath(); + if (isset($extra['pluswerk/grumphp-config'])) { + unset($extra['pluswerk/grumphp-config']); + $configSource->removeProperty('extra.pluswerk/grumphp-config'); + $this->message('removed extra.pluswerk/grumphp-config', 'yellow'); } - } - //ACTIONS: + $rootPackage->setExtra($extra); + } - public function setConfigPath(): void + private function createRectorConfig(): void { - if ($this->getExtra(self::PACKAGE_NAME . '.auto-setting') === false) { - $this->message('not setting config path, extra.' . self::PACKAGE_NAME . '.auto-setting is false', 'yellow'); - return; - } - - $this->setExtra(self::PACKAGE_NAME . '.auto-setting', true); - if ($this->getExtra('grumphp.config-default-path') !== self::DEFAULT_CONFIG_PATH) { - $this->setExtra('grumphp.config-default-path', self::DEFAULT_CONFIG_PATH); - $this->message('auto setting grumphp.config-default-path', 'green'); + if (!file_exists(getcwd() . '/rector.php')) { + copy(dirname(__DIR__, 2) . '/rector.php', getcwd() . '/rector.php'); + $this->message('rector.php file created', 'yellow'); } } - public function removeConfigPath(): void + private function createGrumphpConfig(): void { - if ($this->getExtra(self::PACKAGE_NAME . '.auto-setting') === false) { - $this->message('not removing config path, extra.' . self::PACKAGE_NAME . '.auto-setting is false', 'yellow'); - return; + $grumphpPath = getcwd() . '/grumphp.yml'; + $grumphpTemplatePath = dirname(__DIR__, 2) . '/grumphp.yml'; + if (!file_exists($grumphpPath)) { + $defaultImport = [ + 'imports' => [ + ['resource' => 'vendor/pluswerk/grumphp-config/grumphp.yml'], + ], + ]; + file_put_contents($grumphpPath, Yaml::dump($defaultImport)); + $this->message('grumphp.yml file created', 'yellow'); } - unset($this->extra[self::PACKAGE_NAME]); - $this->removeExtra(self::PACKAGE_NAME); + $data = Yaml::parseFile($grumphpPath); - $key = null; - if ($this->getExtra('grumphp')) { - $key = 'grumphp.config-default-path'; - } elseif ($this->getExtra()) { - $key = 'grumphp'; + if (($data['imports'][0]['resource'] ?? '') !== 'vendor/pluswerk/grumphp-config/grumphp.yml') { + return; } - $this->removeExtra($key); - $this->message('auto removed config path and ' . self::PACKAGE_NAME . ' settings', 'green'); - } + $changed = false; - // HELPER: - - /** - * @param string|null $name - * @return mixed - */ - public function getExtra(string $name = null) - { - if ($name === null) { - return $this->extra; - } - - $arr = $this->extra; - $bits = explode('.', $name); - $last = array_pop($bits); - foreach ($bits as $bit) { - $arr[$bit] ??= []; + $templateData = Yaml::parseFile($grumphpTemplatePath); + foreach ($templateData['parameters'] ?? [] as $key => $value) { + if (!str_starts_with((string)$key, 'convention.')) { + continue; + } - if (!is_array($arr[$bit])) { - return null; + if (($data['parameters'][$key] ?? null) === $value) { + continue; } - $arr = &$arr[$bit]; + $data['parameters'][$key] = $value; + $changed = true; } - return $arr[$last] ?? null; - } - - /** - * @param string|bool $value - */ - public function setExtra(string $name, $value): void - { - $configSource = $this->composer->getConfig()->getConfigSource(); - $configSource->addProperty('extra.' . $name, $value); - } - - public function removeExtra(string $name = null): void - { - $key = 'extra'; - if ($name !== null) { - $key .= '.' . $name; + if ($changed) { + file_put_contents($grumphpPath, Yaml::dump($data)); + $this->message('added some default conventions to grumphp.yml', 'yellow'); } - - $configSource = $this->composer->getConfig()->getConfigSource(); - $configSource->removeProperty($key); } - public function message(string $message, string $color = null): void + // HELPER: + + private function message(string $message, string $color = null): void { $colorStart = ''; $colorEnd = ''; @@ -181,36 +162,6 @@ public function message(string $message, string $color = null): void $colorEnd = '</fg=' . $color . '>'; } - $this->io->write(self::PACKAGE_NAME . ': ' . $colorStart . $message . $colorEnd); - } - - /** - * {@inheritdoc} - */ - public function deactivate(Composer $composer, IOInterface $io): void - { - } - - /** - * {@inheritdoc} - */ - public function uninstall(Composer $composer, IOInterface $io): void - { - } - - - // Rector config copy: - - public function postAutoloadDump(): void - { - $this->createRectorConfig(); - } - - private function createRectorConfig(): void - { - if (!file_exists(getcwd() . '/rector.php')) { - copy(dirname(__DIR__, 2) . '/rector.php', getcwd() . '/rector.php'); - $this->message('rector.php file created', 'yellow'); - } + $this->io->write('pluswerk/grumphp-config' . ': ' . $colorStart . $message . $colorEnd); } } diff --git a/src/RectorSettings.php b/src/RectorSettings.php index 27f4241..cc87b11 100644 --- a/src/RectorSettings.php +++ b/src/RectorSettings.php @@ -27,7 +27,8 @@ class RectorSettings */ public static function sets(): array { - $phpfile = constant(LevelSetList::class . '::UP_TO_PHP_' . PHP_MAJOR_VERSION . PHP_MINOR_VERSION); + $phpVersion = VersionUtility::getMinimalPhpVersion() ?? PHP_MAJOR_VERSION . PHP_MINOR_VERSION; + $phpfile = constant(LevelSetList::class . '::UP_TO_PHP_' . $phpVersion); assert(is_string($phpfile)); return [ diff --git a/src/VersionUtility.php b/src/VersionUtility.php new file mode 100644 index 0000000..6b7430e --- /dev/null +++ b/src/VersionUtility.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +namespace PLUS\GrumPHPConfig; + +use Composer\InstalledVersions; +use Composer\Semver\VersionParser; + +use function json_decode; + +final class VersionUtility +{ + public static function getMinimalPhpVersion(): ?string + { + $phpVersionConstrain = self::getRootComposerJsonData()['require']['php'] ?? false; + if (!$phpVersionConstrain) { + return null; + } + + if (!is_string($phpVersionConstrain)) { + return null; + } + + $parser = new VersionParser(); + $lowerPhpVersion = $parser->parseConstraints($phpVersionConstrain)->getLowerBound()->getVersion(); + if (!preg_match('#(?<major>\d)\.(?<minor>\d)\..*#', $lowerPhpVersion, $matches)) { + return null; + } + + return $matches['major'] . $matches['minor']; + } + + /** + * @return array<mixed> + */ + private static function getRootComposerJsonData(): array + { + $rootPackage = InstalledVersions::getRootPackage(); + $contents = file_get_contents($rootPackage['install_path'] . 'composer.json'); + return json_decode((string)$contents, true, 512, JSON_THROW_ON_ERROR) ?: []; + } +} diff --git a/stubs/ConfigSourceInterface.stub b/stubs/ConfigSourceInterface.stub deleted file mode 100644 index ffae886..0000000 --- a/stubs/ConfigSourceInterface.stub +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -namespace Composer\Config; - -interface ConfigSourceInterface { - /** - * Add a property - * - * @param string $name Name - * @param string|string[]|bool|float|int $value Value - * - * @return void - */ - public function addProperty($name, $value); -} From 7dd9a780f20ad2adb80872e62f7d8cdde826526a Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Sun, 9 Oct 2022 17:21:52 +0200 Subject: [PATCH 4/8] =?UTF-8?q?=E2=9C=A8=20update=20phpstan=20errors=20and?= =?UTF-8?q?=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 40 ++--------------------------------- phpstan-baseline.neon | 35 ------------------------------ phpstan.neon | 1 + src/Composer/Plugin.php | 47 ++++++++++++++++++++++++++++++++++------- 4 files changed, 42 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 62cbcd4..8d4fc15 100644 --- a/README.md +++ b/README.md @@ -8,47 +8,11 @@ composer require pluswerk/grumphp-config --dev ```` -pluswerk/grumphp-config will add the required ``extra.grumphp.config-default-path`` automatically to your ``composer.json``. - -If pluswerk/grumphp-config should not edit your composer.json then you must add this: -````json -{ - "extra": { - "pluswerk/grumphp-config": { - "auto-setting": false - } - } -} -```` +pluswerk/grumphp-config will create `grumphp.yml`, `rector.php` and require some project specific resources if necessary ### You want to override settings?: - -Make a new grumphp.yml config file. You can put it in the root folder. -````yaml -imports: - - { resource: vendor/pluswerk/grumphp-config/grumphp.yml } - - -parameters: - convention.phpstan_level: 1 - convention.xmllint_ignore_pattern: - - "typo3conf/ext/extension/Resources/Private/Templates/List.xml" -```` - -There you can override some convention: - - -| Key | Default | -|-------------------------------------|-------------------------------| -| convention.process_timeout | 60 | -| convention.security_checker_blocking| true | -| convention.jsonlint_ignore_pattern | [] | -| convention.xmllint_ignore_pattern | [] | -| convention.yamllint_ignore_pattern | [] | -| convention.phpcslint_ignore_pattern | [] | -| convention.xlifflint_ignore_pattern | ["#typo3conf/l10n/(.*)#"] | -| convention.phpstan_level | max | +Look into your generated grumphp.yml ### Upgrade to grumphp-config 5 diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d396b7f..3ba01bf 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,45 +1,10 @@ parameters: ignoreErrors: - - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: src/Composer/Plugin.php - - message: "#^Cannot access offset 'config\\-default\\-path' on mixed\\.$#" count: 1 path: src/Composer/Plugin.php - - - message: "#^Cannot access offset 'imports' on mixed\\.$#" - count: 1 - path: src/Composer/Plugin.php - - - - message: "#^Cannot access offset 'parameters' on mixed\\.$#" - count: 2 - path: src/Composer/Plugin.php - - - - message: "#^Cannot access offset 'resource' on mixed\\.$#" - count: 1 - path: src/Composer/Plugin.php - - - - message: "#^Cannot access offset 0 on mixed\\.$#" - count: 1 - path: src/Composer/Plugin.php - - - - message: "#^Cannot access offset mixed on mixed\\.$#" - count: 2 - path: src/Composer/Plugin.php - - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: src/Composer/Plugin.php - - message: "#^Cannot access offset 'php' on mixed\\.$#" count: 1 diff --git a/phpstan.neon b/phpstan.neon index 4bbcb1f..9d7a3f6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,5 +3,6 @@ includes: parameters: level: max + reportUnmatchedIgnoredErrors: false paths: - src diff --git a/src/Composer/Plugin.php b/src/Composer/Plugin.php index 8fb0d20..363b869 100644 --- a/src/Composer/Plugin.php +++ b/src/Composer/Plugin.php @@ -9,11 +9,14 @@ use Composer\DependencyResolver\Operation\UninstallOperation; use Composer\DependencyResolver\Operation\UpdateOperation; use Composer\EventDispatcher\EventSubscriberInterface; +use Composer\InstalledVersions; use Composer\Installer\PackageEvent; use Composer\Installer\PackageEvents; use Composer\IO\IOInterface; use Composer\Plugin\PluginInterface; +use Composer\Script\Event; use Composer\Script\ScriptEvents; +use Exception; use GrumPHP\Configuration\Configuration; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\YamlFileLoader; @@ -51,11 +54,8 @@ public function uninstall(Composer $composer, IOInterface $io): void public static function getSubscribedEvents(): array { return [ - PackageEvents::POST_PACKAGE_UPDATE => 'heavyProcessing', - PackageEvents::POST_PACKAGE_INSTALL => 'heavyProcessing', - - ScriptEvents::POST_INSTALL_CMD => 'heavyProcessing', ScriptEvents::POST_UPDATE_CMD => 'heavyProcessing', + ScriptEvents::POST_INSTALL_CMD => 'heavyProcessing', ScriptEvents::POST_AUTOLOAD_DUMP => 'simpleProcessing', ]; @@ -64,6 +64,7 @@ public static function getSubscribedEvents(): array public function heavyProcessing(): void { $this->removeOldConfigPath(); + $this->installTypo3Dependencies(); $this->createGrumphpConfig(); $this->simpleProcessing(); @@ -101,6 +102,30 @@ private function removeOldConfigPath(): void $rootPackage->setExtra($extra); } + private function installTypo3Dependencies(): void + { + if (!InstalledVersions::isInstalled('typo3/cms-core')) { + return; + } + + $typo3RelatedPackages = [ + 'saschaegerer/phpstan-typo3' => '>=1.1.2', + 'ssch/typo3-rector' => '1.0.x-dev', + ]; + + $changed = false; + foreach ($typo3RelatedPackages as $package => $version) { + if (!InstalledVersions::isInstalled($package)) { + $this->composer->getConfig()->getConfigSource()->addLink('require-dev', $package, $version); + $changed = true; + } + } + + if ($changed) { + passthru('composer update ' . implode(' ', array_keys($typo3RelatedPackages))); + } + } + private function createRectorConfig(): void { if (!file_exists(getcwd() . '/rector.php')) { @@ -119,11 +144,14 @@ private function createGrumphpConfig(): void ['resource' => 'vendor/pluswerk/grumphp-config/grumphp.yml'], ], ]; - file_put_contents($grumphpPath, Yaml::dump($defaultImport)); + file_put_contents($grumphpPath, Yaml::dump($defaultImport, 2, 2)); $this->message('grumphp.yml file created', 'yellow'); } $data = Yaml::parseFile($grumphpPath); + assert(is_array($data)); + $data['parameters'] ??= []; + assert(is_array($data['parameters'])); if (($data['imports'][0]['resource'] ?? '') !== 'vendor/pluswerk/grumphp-config/grumphp.yml') { return; @@ -132,12 +160,15 @@ private function createGrumphpConfig(): void $changed = false; $templateData = Yaml::parseFile($grumphpTemplatePath); - foreach ($templateData['parameters'] ?? [] as $key => $value) { + assert(is_array($templateData)); + $templateData['parameters'] ??= []; + assert(is_array($templateData['parameters'])); + foreach ($templateData['parameters'] as $key => $value) { if (!str_starts_with((string)$key, 'convention.')) { continue; } - if (($data['parameters'][$key] ?? null) === $value) { + if (array_key_exists((string)$key, $data['parameters'])) { continue; } @@ -146,7 +177,7 @@ private function createGrumphpConfig(): void } if ($changed) { - file_put_contents($grumphpPath, Yaml::dump($data)); + file_put_contents($grumphpPath, Yaml::dump($data, 2, 2)); $this->message('added some default conventions to grumphp.yml', 'yellow'); } } From dfeaa429f887c4332ecbe1728888bdc831e8175e Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Fri, 2 Dec 2022 11:39:33 +0100 Subject: [PATCH 5/8] Set parallel timeout to default --- rector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rector.php b/rector.php index 3ddaa30..13f0f89 100644 --- a/rector.php +++ b/rector.php @@ -6,7 +6,7 @@ use Rector\Config\RectorConfig; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->parallel(240); + $rectorConfig->parallel(); $rectorConfig->importNames(); $rectorConfig->importShortClasses(); From f417a83214bf78595be8572c9f682aaaa672510f Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Mon, 5 Dec 2022 13:56:22 +0100 Subject: [PATCH 6/8] =?UTF-8?q?=E2=9C=A8=20add=20TYPO3=20to=20rector.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + composer.json | 12 +++++--- rector.php | 6 ++++ src/Composer/Plugin.php | 10 +++--- src/RectorSettings.php | 67 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 80 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index a784fd3..501d35c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /composer.lock .idea +var diff --git a/composer.json b/composer.json index 2fc4106..9fb5257 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,10 @@ "*" : "dist" }, "allow-plugins" : { - "phpro/grumphp" : true, - "phpstan/extension-installer" : true + "phpro/grumphp": true, + "phpstan/extension-installer": true, + "typo3/cms-composer-installers": true, + "typo3/class-alias-loader": true } }, "support" : { @@ -40,10 +42,12 @@ "php-parallel-lint/php-parallel-lint" : "^1.3.2", "phpstan/phpstan" : "^1.8.8", "phpstan/extension-installer" : "^1.1", - "rector/rector" : "^0.14.5", + "rector/rector" : "^0.14.8", "palpalani/grumphp-rector-task" : "^0.8.6", "composer/semver" : "^3.3.0", - "symfony/yaml" : "^5.4.0 || ^6.0" + "symfony/yaml" : "^5.4.0 || ^6.0", + "saschaegerer/phpstan-typo3": "^1.8.2", + "ssch/typo3-rector": "^1.0.6" }, "extra" : { "class" : "PLUS\\GrumPHPConfig\\Composer\\Plugin" diff --git a/rector.php b/rector.php index 13f0f89..9276b21 100644 --- a/rector.php +++ b/rector.php @@ -4,11 +4,14 @@ use PLUS\GrumPHPConfig\RectorSettings; use Rector\Config\RectorConfig; +use Rector\Caching\ValueObject\Storage\FileCacheStorage; return static function (RectorConfig $rectorConfig): void { $rectorConfig->parallel(); $rectorConfig->importNames(); $rectorConfig->importShortClasses(); + $rectorConfig->cacheClass(FileCacheStorage::class); + $rectorConfig->cacheDirectory('./var/cache/rector'); $rectorConfig->paths( array_filter([ @@ -22,6 +25,8 @@ $rectorConfig->sets( [ ...RectorSettings::sets(), + // the filesystem caching disables parallel execution, but why? + ...RectorSettings::setsTypo3(), ] ); @@ -30,6 +35,7 @@ $rectorConfig->skip( [ ...RectorSettings::skip(), + ...RectorSettings::skipTypo3(), /** * rector should not touch these files diff --git a/src/Composer/Plugin.php b/src/Composer/Plugin.php index 363b869..b8503b1 100644 --- a/src/Composer/Plugin.php +++ b/src/Composer/Plugin.php @@ -16,6 +16,7 @@ use Composer\Plugin\PluginInterface; use Composer\Script\Event; use Composer\Script\ScriptEvents; +use Composer\Semver\VersionParser; use Exception; use GrumPHP\Configuration\Configuration; use Symfony\Component\Config\FileLocator; @@ -109,20 +110,21 @@ private function installTypo3Dependencies(): void } $typo3RelatedPackages = [ - 'saschaegerer/phpstan-typo3' => '>=1.1.2', - 'ssch/typo3-rector' => '1.0.x-dev', + 'saschaegerer/phpstan-typo3' => '^1.8.2', + 'ssch/typo3-rector' => '^1.0.6', ]; $changed = false; foreach ($typo3RelatedPackages as $package => $version) { - if (!InstalledVersions::isInstalled($package)) { + if (!InstalledVersions::isInstalled($package) || !InstalledVersions::satisfies(new VersionParser(), $package, $version)) { $this->composer->getConfig()->getConfigSource()->addLink('require-dev', $package, $version); + $this->message(sprintf('installing %s in version %s for pluswerk/grumphp-config', $package, $version), 'yellow'); $changed = true; } } if ($changed) { - passthru('composer update ' . implode(' ', array_keys($typo3RelatedPackages))); + passthru('composer update -W ' . implode(' ', array_keys($typo3RelatedPackages))); } } diff --git a/src/RectorSettings.php b/src/RectorSettings.php index cc87b11..8698dcd 100644 --- a/src/RectorSettings.php +++ b/src/RectorSettings.php @@ -4,6 +4,7 @@ namespace PLUS\GrumPHPConfig; +use Composer\InstalledVersions; use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector; use Rector\CodeQuality\Rector\If_\SimplifyIfElseToTernaryRector; use Rector\CodeQuality\Rector\Isset_\IssetOnPropertyObjectToPropertyExistsRector; @@ -19,19 +20,27 @@ use Rector\Privatization\Rector\Class_\FinalizeClassesWithoutChildrenRector; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; +use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector; +use Ssch\TYPO3Rector\Rector\Migrations\RenameClassMapAliasRector; +use Ssch\TYPO3Rector\Set\Typo3LevelSetList; +use Ssch\TYPO3Rector\Set\Typo3SetList; -class RectorSettings +final class RectorSettings { /** * @return array<int,string> */ - public static function sets(): array + public static function sets(bool $entirety = false): array { $phpVersion = VersionUtility::getMinimalPhpVersion() ?? PHP_MAJOR_VERSION . PHP_MINOR_VERSION; - $phpfile = constant(LevelSetList::class . '::UP_TO_PHP_' . $phpVersion); - assert(is_string($phpfile)); + $phpFile = constant(SetList::class . '::PHP_' . $phpVersion); + if ($entirety) { + $phpFile = constant(LevelSetList::class . '::UP_TO_PHP_' . $phpVersion); + } - return [ + assert(is_string($phpFile)); + + return array_filter([ // SetList::ACTION_INJECTION_TO_CONSTRUCTOR_INJECTION, // NO SetList::CODE_QUALITY, // YES SetList::CODING_STYLE, // YES @@ -40,7 +49,7 @@ public static function sets(): array //SetList::MONOLOG_20, // no usage //SetList::MYSQL_TO_MYSQLI, // no usage //SetList::NAMING, //NO is not good - $phpfile, + $phpFile, //SetList::PHP_52, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... //SetList::PHP_53, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... //SetList::PHP_54, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... @@ -55,11 +64,31 @@ public static function sets(): array //SetList::PHP_81, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... //SetList::PHP_82, // YES, included in LevelSetList::class . '::UP_TO_PHP_' ... SetList::PRIVATIZATION, // some things may be bad - SetList::PSR_4, // dose nothing? + $entirety ? SetList::PSR_4 : null, SetList::TYPE_DECLARATION, // YES SetList::TYPE_DECLARATION_STRICT, // YES please SetList::EARLY_RETURN, //YES - //SetList::RECTOR_CONFIG, // NO + ]); + } + + /** + * @return array<int, string> + */ + public static function setsTypo3(bool $entirety = false): array + { + if (!InstalledVersions::isInstalled('typo3/cms-core')) { + return []; + } + + [$typo3MajorVersion] = explode('.', (string)InstalledVersions::getVersion('typo3/cms-core'), 2); + $setList = constant(Typo3SetList::class . '::TYPO3_' . $typo3MajorVersion); + if ($entirety) { + $setList = constant(Typo3LevelSetList::class . '::UP_TO_TYPO3_' . $typo3MajorVersion); + } + + assert(is_string($setList)); + return [ + $setList, ]; } @@ -138,6 +167,28 @@ public static function skip(): array * TO: property_exists($this, 'x') && $this->x !== null; */ IssetOnPropertyObjectToPropertyExistsRector::class, + /** + * FROM: * @ var ObjectStorage<Moption> + * TO: * @ var ObjectStorage + */ + TypedPropertyFromStrictGetterMethodReturnTypeRector::class, + ]; + } + + /** + * @return array<int, string> + */ + public static function skipTypo3(): array + { + if (!InstalledVersions::isInstalled('typo3/cms-core')) { + return []; + } + + return [ + /** + * not used: + */ + RenameClassMapAliasRector::class ]; } } From 805dedb861306af56a18ab2ba1ee439f62f3ca8c Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Wed, 1 Feb 2023 16:17:10 +0100 Subject: [PATCH 7/8] Update VersionUtility.php --- src/VersionUtility.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/VersionUtility.php b/src/VersionUtility.php index 6b7430e..141d694 100644 --- a/src/VersionUtility.php +++ b/src/VersionUtility.php @@ -4,10 +4,10 @@ namespace PLUS\GrumPHPConfig; -use Composer\InstalledVersions; use Composer\Semver\VersionParser; use function json_decode; +use function getcwd; final class VersionUtility { @@ -36,8 +36,7 @@ public static function getMinimalPhpVersion(): ?string */ private static function getRootComposerJsonData(): array { - $rootPackage = InstalledVersions::getRootPackage(); - $contents = file_get_contents($rootPackage['install_path'] . 'composer.json'); + $contents = file_get_contents(getcwd() . '/composer.json'); return json_decode((string)$contents, true, 512, JSON_THROW_ON_ERROR) ?: []; } } From 34415e097973ea3923dcbcc00ff1daa4744ea279 Mon Sep 17 00:00:00 2001 From: Matthias Vogel <m.vogel@andersundsehr.com> Date: Thu, 2 Feb 2023 12:56:52 +0100 Subject: [PATCH 8/8] =?UTF-8?q?=E2=9C=A8=20add=20new=20config=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/run-grumphp-test.yml | 4 +-- composer.json | 17 ++++++---- grumphp.yml | 9 +++--- phpstan-baseline.neon | 7 +++- rector.php | 5 ++- src/Composer/Plugin.php | 17 +++++----- src/RectorSettings.php | 5 ++- src/VersionUtility.php | 44 ++++++++++++++++++++++++-- 8 files changed, 77 insertions(+), 31 deletions(-) diff --git a/.github/workflows/run-grumphp-test.yml b/.github/workflows/run-grumphp-test.yml index 7472e64..c8f55a7 100644 --- a/.github/workflows/run-grumphp-test.yml +++ b/.github/workflows/run-grumphp-test.yml @@ -4,12 +4,12 @@ jobs: test: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: php: - - '7.4' - '8.0' - '8.1' - - '8.2-rc' + - '8.2' composer: - install --no-progress --no-scripts -n - update --no-progress --no-scripts -n --prefer-lowest diff --git a/composer.json b/composer.json index 9fb5257..c232e63 100644 --- a/composer.json +++ b/composer.json @@ -32,9 +32,9 @@ } }, "require" : { - "php" : "~7.4 || ~8.0 || ~8.1 || ~8.2", + "php" : "~8.0 || ~8.1 || ~8.2", "composer-plugin-api" : "^2.1.0", - "phpro/grumphp" : "^1.13", + "phpro/grumphp" : "^1.15", "pluswerk/grumphp-bom-task" : "^7.0.0", "pluswerk/grumphp-xliff-task" : "^5.0.0", "squizlabs/php_codesniffer" : "^3.7.1", @@ -42,18 +42,21 @@ "php-parallel-lint/php-parallel-lint" : "^1.3.2", "phpstan/phpstan" : "^1.8.8", "phpstan/extension-installer" : "^1.1", - "rector/rector" : "^0.14.8", - "palpalani/grumphp-rector-task" : "^0.8.6", + "rector/rector" : "^0.15.10", "composer/semver" : "^3.3.0", - "symfony/yaml" : "^5.4.0 || ^6.0", - "saschaegerer/phpstan-typo3": "^1.8.2", - "ssch/typo3-rector": "^1.0.6" + "symfony/yaml" : "^5.4.0 || ^6.0" }, "extra" : { "class" : "PLUS\\GrumPHPConfig\\Composer\\Plugin" }, "require-dev" : { + "saschaegerer/phpstan-typo3" : "^1.8.2", + "ssch/typo3-rector" : "^1.1.3", "roave/security-advisories" : "dev-latest", "composer/composer" : "^2.4.2" + }, + "require-typo3" : { + "saschaegerer/phpstan-typo3" : "^1.8.2", + "ssch/typo3-rector" : "^1.1.3" } } diff --git a/grumphp.yml b/grumphp.yml index c4ed91a..697c113 100644 --- a/grumphp.yml +++ b/grumphp.yml @@ -7,6 +7,7 @@ parameters: convention.phpcslint_ignore_pattern: [] convention.xlifflint_ignore_pattern: [] convention.rector_ignore_pattern: [] + convention.rector_enabled: true convention.rector_config: 'rector.php' convention.rector_clear-cache: false convention.phpstan_level: max @@ -54,14 +55,12 @@ grumphp: metadata: priority: 1 rector: - whitelist_patterns: [ ] + metadata: + enabled: "%convention.rector_enabled%" config: "%convention.rector_config%" triggered_by: [ 'php' ] - clear-cache: "%convention.rector_clear-cache%" + clear_cache: "%convention.rector_clear-cache%" ignore_patterns: "%convention.rector_ignore_pattern%" - no-progress-bar: false - files_on_pre_commit: false extensions: - PLUS\GrumPHPBomTask\ExtensionLoader - PLUS\GrumPHPXliffTask\ExtensionLoader - - palPalani\GrumPhpRectorTask\ExtensionLoader diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3ba01bf..8324867 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -11,6 +11,11 @@ parameters: path: src/VersionUtility.php - - message: "#^Method PLUS\\\\GrumPHPConfig\\\\VersionUtility\\:\\:getRootComposerJsonData\\(\\) should return array but returns mixed\\.$#" + message: "#^Method PLUS\\\\GrumPHPConfig\\\\VersionUtility\\:\\:getRequire\\(\\) should return array\\<string, string\\> but returns mixed\\.$#" + count: 1 + path: src/VersionUtility.php + + - + message: "#^Method PLUS\\\\GrumPHPConfig\\\\VersionUtility\\:\\:readJson\\(\\) should return array\\<string, mixed\\> but returns mixed\\.$#" count: 1 path: src/VersionUtility.php diff --git a/rector.php b/rector.php index 9276b21..cb9a514 100644 --- a/rector.php +++ b/rector.php @@ -24,9 +24,8 @@ // define sets of rules $rectorConfig->sets( [ - ...RectorSettings::sets(), - // the filesystem caching disables parallel execution, but why? - ...RectorSettings::setsTypo3(), + ...RectorSettings::sets(true), + ...RectorSettings::setsTypo3(false), ] ); diff --git a/src/Composer/Plugin.php b/src/Composer/Plugin.php index b8503b1..a0812af 100644 --- a/src/Composer/Plugin.php +++ b/src/Composer/Plugin.php @@ -19,6 +19,7 @@ use Composer\Semver\VersionParser; use Exception; use GrumPHP\Configuration\Configuration; +use PLUS\GrumPHPConfig\VersionUtility; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Yaml\Yaml; @@ -50,13 +51,16 @@ public function uninstall(Composer $composer, IOInterface $io): void } /** - * @return array<string, string> + * @return array<string, string|array{0:string, 1:int}> */ public static function getSubscribedEvents(): array { + $priority = 1000; + // priority higher than phpro/grumphp so it dose not ask if you want to create a grumphp.yml, + // as we do that for you return [ - ScriptEvents::POST_UPDATE_CMD => 'heavyProcessing', - ScriptEvents::POST_INSTALL_CMD => 'heavyProcessing', + ScriptEvents::POST_UPDATE_CMD => ['heavyProcessing', $priority], + ScriptEvents::POST_INSTALL_CMD => ['heavyProcessing', $priority], ScriptEvents::POST_AUTOLOAD_DUMP => 'simpleProcessing', ]; @@ -109,10 +113,7 @@ private function installTypo3Dependencies(): void return; } - $typo3RelatedPackages = [ - 'saschaegerer/phpstan-typo3' => '^1.8.2', - 'ssch/typo3-rector' => '^1.0.6', - ]; + $typo3RelatedPackages = VersionUtility::getRequire('typo3'); $changed = false; foreach ($typo3RelatedPackages as $package => $version) { @@ -124,7 +125,7 @@ private function installTypo3Dependencies(): void } if ($changed) { - passthru('composer update -W ' . implode(' ', array_keys($typo3RelatedPackages))); + passthru('composer update -W --no-scripts ' . implode(' ', array_keys($typo3RelatedPackages))); } } diff --git a/src/RectorSettings.php b/src/RectorSettings.php index 8698dcd..e913512 100644 --- a/src/RectorSettings.php +++ b/src/RectorSettings.php @@ -66,7 +66,6 @@ public static function sets(bool $entirety = false): array SetList::PRIVATIZATION, // some things may be bad $entirety ? SetList::PSR_4 : null, SetList::TYPE_DECLARATION, // YES - SetList::TYPE_DECLARATION_STRICT, // YES please SetList::EARLY_RETURN, //YES ]); } @@ -76,11 +75,11 @@ public static function sets(bool $entirety = false): array */ public static function setsTypo3(bool $entirety = false): array { - if (!InstalledVersions::isInstalled('typo3/cms-core')) { + if (!VersionUtility::isInstalled('typo3/cms-core')) { return []; } - [$typo3MajorVersion] = explode('.', (string)InstalledVersions::getVersion('typo3/cms-core'), 2); + [$typo3MajorVersion] = explode('.', (string)VersionUtility::getVersion('typo3/cms-core'), 2); $setList = constant(Typo3SetList::class . '::TYPO3_' . $typo3MajorVersion); if ($entirety) { $setList = constant(Typo3LevelSetList::class . '::UP_TO_TYPO3_' . $typo3MajorVersion); diff --git a/src/VersionUtility.php b/src/VersionUtility.php index 141d694..f2afcf2 100644 --- a/src/VersionUtility.php +++ b/src/VersionUtility.php @@ -11,6 +11,11 @@ final class VersionUtility { + /** + * @var array{versions?: array<string, mixed>} + */ + private static array $installed = []; + public static function getMinimalPhpVersion(): ?string { $phpVersionConstrain = self::getRootComposerJsonData()['require']['php'] ?? false; @@ -36,7 +41,42 @@ public static function getMinimalPhpVersion(): ?string */ private static function getRootComposerJsonData(): array { - $contents = file_get_contents(getcwd() . '/composer.json'); - return json_decode((string)$contents, true, 512, JSON_THROW_ON_ERROR) ?: []; + return self::readJson(getcwd() . '/composer.json'); + } + + /** + * we can not use \Composer\InstalledVersions::isInstalled because rector has its own vendor dir with different dependencies. + */ + public static function isInstalled(string $packageName): bool + { + self::$installed = self::$installed ?: require getcwd() . '/vendor/composer/installed.php'; + return isset(self::$installed['versions'][$packageName]) && empty(self::$installed['versions'][$packageName]['dev_requirement']); + } + + /** + * we can not use \Composer\InstalledVersions::getVersion because rector has its own vendor dir with different dependencies. + */ + public static function getVersion(string $packageName): ?string + { + self::$installed = self::$installed ?: require getcwd() . '/vendor/composer/installed.php'; + return self::$installed['versions'][$packageName]['version'] ?? null; + } + + /** + * @return array<string, string> + */ + public static function getRequire(string $requireSectionName): array + { + $file = dirname(__DIR__) . '/composer.json'; + $composerJsonData = self::readJson($file); + return $composerJsonData['require-' . $requireSectionName] ?? []; + } + + /** + * @return array<string, mixed> + */ + private static function readJson(string $file): array + { + return json_decode((string)(file_get_contents($file)), true, 512, JSON_THROW_ON_ERROR) ?: []; } }