diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index de9023b..693a507 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -52,6 +52,9 @@ jobs: - name: Run PHPStan run: vendor/bin/phpstan analyse + - name: Run Psalm + run: vendor/bin/psalm --no-cache + - name: Run Rector run: vendor/bin/rector process --ansi --dry-run --config rector.php Kununu/ tests/ diff --git a/Kununu/ArchitectureSniffer/ArchitectureSniffer.php b/Kununu/ArchitectureSniffer/ArchitectureSniffer.php index c9ba1d4..e370a06 100644 --- a/Kununu/ArchitectureSniffer/ArchitectureSniffer.php +++ b/Kununu/ArchitectureSniffer/ArchitectureSniffer.php @@ -73,7 +73,7 @@ public function testArchitecture(): iterable $architecture, static fn(array $group) => !array_filter( is_array($group[Group::INCLUDES_KEY] ?? null) ? $group[Group::INCLUDES_KEY] : [], - static fn($include) => str_starts_with((string) $include, 'App\\') + static fn(mixed $include): bool => str_starts_with((string) $include, 'App\\') ) ); diff --git a/Kununu/ArchitectureSniffer/Helper/TypeChecker.php b/Kununu/ArchitectureSniffer/Helper/TypeChecker.php index 6f5956e..677e5a8 100644 --- a/Kununu/ArchitectureSniffer/Helper/TypeChecker.php +++ b/Kununu/ArchitectureSniffer/Helper/TypeChecker.php @@ -13,13 +13,7 @@ public static function isArrayKeysOfStrings(mixed $arr): bool return false; } - foreach (array_keys($arr) as $key) { - if (!is_string($key)) { - return false; - } - } - - return true; + return array_all(array_keys($arr), static fn($key) => is_string($key)); } public static function isArrayOfStrings(mixed $arr): bool diff --git a/Kununu/CsFixer/Command/CsFixerCommand.php b/Kununu/CsFixer/Command/CsFixerCommand.php index 178788f..5e0fded 100644 --- a/Kununu/CsFixer/Command/CsFixerCommand.php +++ b/Kununu/CsFixer/Command/CsFixerCommand.php @@ -76,7 +76,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return self::FAILURE; } - $configSource = $input->getOption(self::OPTION_CONFIG) ?: __DIR__ . '/../../../php-cs-fixer.php'; + $configSource = $input->getOption(self::OPTION_CONFIG) ?? __DIR__ . '/../../../php-cs-fixer.php'; $configPath = realpath($configSource); if ($configPath === false || !is_file($configPath)) { diff --git a/Kununu/CsFixer/Command/CsFixerGitHookCommand.php b/Kununu/CsFixer/Command/CsFixerGitHookCommand.php index 2ef8db3..e622566 100644 --- a/Kununu/CsFixer/Command/CsFixerGitHookCommand.php +++ b/Kununu/CsFixer/Command/CsFixerGitHookCommand.php @@ -140,7 +140,9 @@ private function resolveVendorDir(string $rootGitPath): string foreach ($candidates as $candidate) { if (is_dir($candidate)) { - return realpath($candidate) ?: $candidate; + $resolved = realpath($candidate); + + return $resolved !== false ? $resolved : $candidate; } } diff --git a/Kununu/CsFixer/CsFixerPlugin.php b/Kununu/CsFixer/CsFixerPlugin.php index 5678c95..18bee40 100644 --- a/Kununu/CsFixer/CsFixerPlugin.php +++ b/Kununu/CsFixer/CsFixerPlugin.php @@ -19,8 +19,8 @@ final class CsFixerPlugin implements PluginInterface, EventSubscriberInterface, Capable { - private Composer $composer; - private IOInterface $io; + private ?Composer $composer = null; + private ?IOInterface $io = null; public static function getSubscribedEvents(): array { @@ -54,6 +54,10 @@ public function getCapabilities(): array /** @throws ExceptionInterface */ public function addCsFixerGitHooks(): void { + if ($this->composer === null || $this->io === null) { + return; + } + $command = new CsFixerGitHookCommand(); $command->setComposer($this->composer); $command->setIO($this->io); diff --git a/bin/code-tools b/bin/code-tools index 178cf37..6bb4b03 100755 --- a/bin/code-tools +++ b/bin/code-tools @@ -20,6 +20,7 @@ fi readonly CONFIG_FILES=( "dist/php-cs-fixer.php.dist" "dist/phpcs.xml.dist" + "dist/psalm.xml.dist" "dist/rector.php.dist" "dist/.editorconfig.dist" ) @@ -32,6 +33,7 @@ Usage: vendor/bin/code-tools publish:config [tool-name] Valid tool names: cs-fixer => copies dist/php-cs-fixer.php.dist code-sniffer => copies dist/phpcs.xml.dist + psalm => copies dist/psalm.xml.dist rector => copies dist/rector.php.dist editorconfig => copies dist/.editorconfig.dist EOF @@ -79,6 +81,9 @@ case "$tool_name" in code-sniffer) copy_config_file "dist/phpcs.xml.dist" ;; + psalm) + copy_config_file "dist/psalm.xml.dist" + ;; rector) copy_config_file "dist/rector.php.dist" ;; diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php index 236115a..9ae1971 100644 --- a/composer-dependency-analyser.php +++ b/composer-dependency-analyser.php @@ -20,8 +20,10 @@ [ 'friendsofphp/php-cs-fixer', 'phpstan/phpstan', + 'psalm/plugin-symfony', 'rector/rector', 'squizlabs/php_codesniffer', + 'vimeo/psalm', ], [ErrorType::UNUSED_DEPENDENCY] ); diff --git a/composer.json b/composer.json index 1874d6d..420f5fc 100644 --- a/composer.json +++ b/composer.json @@ -16,11 +16,13 @@ "friendsofphp/php-cs-fixer": "^3.93", "phpat/phpat": "^0.11.4", "phpstan/phpstan": "^2.1", + "psalm/plugin-symfony": "^5.3", "rector/rector": "^2.0", "squizlabs/php_codesniffer": "^3.10", "symfony/console": "^6.4 || ^7.4", "symfony/process": "^6.4 || ^7.4", - "symfony/yaml": "^6.4 || ^7.4" + "symfony/yaml": "^6.4 || ^7.4", + "vimeo/psalm": "^6.16" }, "require-dev": { "ergebnis/composer-normalize": "^2.50", @@ -57,12 +59,15 @@ "@cs-check", "@stan", "@rector", + "@psalm", "@test-unit" ], "cs-check": "phpcs --standard=phpcs.xml Kununu/ tests/", "cs-fix": "phpcbf --standard=phpcs.xml Kununu/ tests/", "cs-fixer-check": "php-cs-fixer check --config=php-cs-fixer.php", "cs-fixer-fix": "php-cs-fixer fix --config=php-cs-fixer.php", + "psalm": "psalm --no-cache", + "psalm-baseline": "psalm --no-cache --set-baseline=psalm-baseline.xml", "rector": "rector process --dry-run Kununu/ tests/", "rector-fix": "rector process Kununu/ tests/", "stan": "phpstan analyze", diff --git a/dist/psalm.xml.dist b/dist/psalm.xml.dist new file mode 100644 index 0000000..cba18c8 --- /dev/null +++ b/dist/psalm.xml.dist @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..6e5b0ae --- /dev/null +++ b/psalm.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +