From 1ca5b15d69f5186e470920a74b55193b2e92be83 Mon Sep 17 00:00:00 2001 From: Daniel Santos Date: Tue, 9 Sep 2025 17:24:39 +0100 Subject: [PATCH 1/3] Fix Qodana. Improve CI checks --- .github/workflows/code_quality.yml | 2 +- .github/workflows/cs_sniff.yml | 6 +++++ .../ArchitectureSniffer.php | 2 +- .../Helper/RuleBuilder.php | 25 ++++++++++++------- Kununu/CsFixer/Command/CsFixerCommand.php | 9 +++---- .../MethodSignatureArgumentsSniff.php | 6 ++--- .../PHP/NoNewLineBeforeDeclareStrictSniff.php | 2 +- composer.json | 10 +++++--- php-cs-fixer.php | 7 ++++-- qodana.yaml | 2 +- rector.php | 8 +++--- tests/SniffTestCase.php | 4 +-- .../CsFixer/Command/CsFixerCommandTest.php | 4 +-- .../Command/CsFixerGitHookCommandTest.php | 6 ++--- 14 files changed, 55 insertions(+), 38 deletions(-) diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index 1348a3c..bed9754 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -27,6 +27,6 @@ jobs: ssh_key: ${{ secrets.CLONE_SSH_KEY }} ssh_key_pub: ${{ secrets.CLONE_SSH_KEY_PUB }} - name: 'Qodana Scan' - uses: JetBrains/qodana-action@v2023.3 + uses: JetBrains/qodana-action@v2025.2 env: QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} diff --git a/.github/workflows/cs_sniff.yml b/.github/workflows/cs_sniff.yml index 145bfd7..3de262e 100644 --- a/.github/workflows/cs_sniff.yml +++ b/.github/workflows/cs_sniff.yml @@ -34,5 +34,11 @@ jobs: - name: Run code style sniffer run: vendor/bin/phpcs --standard=phpcs.xml Kununu/ tests/ + - name: Run PHP CS Fixer + run: vendor/bin/php-cs-fixer check --using-cache=no --config php-cs-fixer.php + - name: Run PHPStan run: vendor/bin/phpstan analyse + + - 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 abe8d24..c9ba1d4 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($include, 'App\\') + static fn($include) => str_starts_with((string) $include, 'App\\') ) ); diff --git a/Kununu/ArchitectureSniffer/Helper/RuleBuilder.php b/Kununu/ArchitectureSniffer/Helper/RuleBuilder.php index 61ff661..e80f8ca 100644 --- a/Kununu/ArchitectureSniffer/Helper/RuleBuilder.php +++ b/Kununu/ArchitectureSniffer/Helper/RuleBuilder.php @@ -5,7 +5,14 @@ use Kununu\ArchitectureSniffer\Configuration\ArchitectureLibrary; use Kununu\ArchitectureSniffer\Configuration\Group; -use Kununu\ArchitectureSniffer\Configuration\Rules; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustBeFinal; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustBeReadonly; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustExtend; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustImplement; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustNotDependOn; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustOnlyDependOn; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustOnlyHaveOnePublicMethod; +use Kununu\ArchitectureSniffer\Configuration\Rules\MustOnlyHaveOnePublicMethodNamed; use PHPat\Test\Builder\Rule as PHPatRule; final readonly class RuleBuilder @@ -16,53 +23,53 @@ public static function getRules(Group $group, ArchitectureLibrary $library): iterable { if ($group->shouldExtend()) { - yield Rules\MustExtend::createRule( + yield MustExtend::createRule( $group, $library ); } if ($group->shouldImplement()) { - yield Rules\MustImplement::createRule( + yield MustImplement::createRule( $group, $library ); } if ($group->shouldBeFinal()) { - yield Rules\MustBeFinal::createRule( + yield MustBeFinal::createRule( $group, $library ); } if ($group->shouldBeReadonly()) { - yield Rules\MustBeReadonly::createRule( + yield MustBeReadonly::createRule( $group, $library ); } if ($group->shouldDependOn()) { - yield Rules\MustOnlyDependOn::createRule( + yield MustOnlyDependOn::createRule( $group, $library ); } if ($group->shouldNotDependOn()) { - yield Rules\MustNotDependOn::createRule( + yield MustNotDependOn::createRule( $group, $library ); } if ($group->shouldOnlyHaveOnePublicMethodNamed()) { - yield Rules\MustOnlyHaveOnePublicMethodNamed::createRule( + yield MustOnlyHaveOnePublicMethodNamed::createRule( $group, $library ); - yield Rules\MustOnlyHaveOnePublicMethod::createRule( + yield MustOnlyHaveOnePublicMethod::createRule( $group, $library ); diff --git a/Kununu/CsFixer/Command/CsFixerCommand.php b/Kununu/CsFixer/Command/CsFixerCommand.php index 7eb9f62..96f869a 100644 --- a/Kununu/CsFixer/Command/CsFixerCommand.php +++ b/Kununu/CsFixer/Command/CsFixerCommand.php @@ -14,12 +14,9 @@ final class CsFixerCommand extends BaseCommand { - public const FAILURE = 1; - public const SUCCESS = 0; - - private const ARGUMENT_FILES = 'files'; - private const OPTION_CONFIG = 'config'; - private const OPTION_EXTRA_ARGS = 'extra-args'; + private const string ARGUMENT_FILES = 'files'; + private const string OPTION_CONFIG = 'config'; + private const string OPTION_EXTRA_ARGS = 'extra-args'; protected function configure(): void { diff --git a/Kununu/Sniffs/Formatting/MethodSignatureArgumentsSniff.php b/Kununu/Sniffs/Formatting/MethodSignatureArgumentsSniff.php index b030e81..a76423c 100644 --- a/Kununu/Sniffs/Formatting/MethodSignatureArgumentsSniff.php +++ b/Kununu/Sniffs/Formatting/MethodSignatureArgumentsSniff.php @@ -211,7 +211,7 @@ protected function getIndentationWhitespace(File $phpcsFile, int $prevIndex): st */ protected function getLineEndingPosition(array $tokens, int $position): int { - while (!empty($tokens[$position]) && !str_contains($tokens[$position]['content'], PHP_EOL)) { + while (!empty($tokens[$position]) && !str_contains((string) $tokens[$position]['content'], PHP_EOL)) { ++$position; } @@ -275,7 +275,7 @@ protected function getMethodSignatureMultilineLength( // closing parenthesis ++$totalLength; // column (:) and space before the returnType - $totalLength += mb_strlen($methodProperties['return_type']) + 2; + $totalLength += mb_strlen((string) $methodProperties['return_type']) + 2; return $totalLength; } @@ -286,7 +286,7 @@ protected function getMethodSignatureMultilineLength( protected function getParameterTotalLength(array $methodParameter): int { $length = 0; - $length += mb_strlen($methodParameter['content']); + $length += mb_strlen((string) $methodParameter['content']); return $length; } diff --git a/Kununu/Sniffs/PHP/NoNewLineBeforeDeclareStrictSniff.php b/Kununu/Sniffs/PHP/NoNewLineBeforeDeclareStrictSniff.php index 5b48732..1926253 100644 --- a/Kununu/Sniffs/PHP/NoNewLineBeforeDeclareStrictSniff.php +++ b/Kununu/Sniffs/PHP/NoNewLineBeforeDeclareStrictSniff.php @@ -24,7 +24,7 @@ public function process(File $phpcsFile, $stackPtr) if ($declare !== false) { $isEmptyLine = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, $declare); - if ($isEmptyLine !== false && str_contains($tokens[$isEmptyLine]['content'], "\n")) { + if ($isEmptyLine !== false && str_contains((string) $tokens[$isEmptyLine]['content'], "\n")) { $error = 'Empty line before declare(strict_types=1) is not allowed'; $fix = $phpcsFile->addFixableError($error, $isEmptyLine, 'EmptyLineBeforeDeclare'); diff --git a/composer.json b/composer.json index 50a5565..4ddf2b8 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "symfony/yaml": "^6.4" }, "require-dev": { - "kununu/scripts": "^5.1", + "kununu/scripts": "^6.1", "phpunit/phpunit": "^11.5" }, "autoload": { @@ -50,16 +50,18 @@ }, "scripts": { "test-unit": "phpunit", - "cs-fixer-check": "php-cs-fixer check --config=php-cs-fixer.php Kununu/ tests/", - "cs-fixer-fix": "php-cs-fixer fix --config=php-cs-fixer.php 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", "cs-check": "phpcs --standard=phpcs.xml Kununu/ tests/", "cs-fix": "phpcbf --standard=phpcs.xml Kununu/ tests/", "stan": "phpstan analyze", - "rector": "rector process --dry-run Kununu/ tests/", + "rector": "rector process --dry-run Kununu/ tests/ -vvv", + "rector-fix": "rector process Kununu/ tests/", "ci-checks": [ "@cs-fixer-check", "@cs-check", "@stan", + "@rector", "@test-unit" ] } diff --git a/php-cs-fixer.php b/php-cs-fixer.php index bedda2c..9a7035e 100644 --- a/php-cs-fixer.php +++ b/php-cs-fixer.php @@ -79,7 +79,10 @@ ]) ->setFinder( Finder::create() - ->exclude('vendor') - ->exclude('var') + ->exclude([ + 'vendor', + 'var', + '_data', + ]) ->in(__DIR__) ); diff --git a/qodana.yaml b/qodana.yaml index a3259c2..b78eaf2 100644 --- a/qodana.yaml +++ b/qodana.yaml @@ -1,5 +1,5 @@ version: "1.0" -linter: jetbrains/qodana-php:2023.3 +linter: jetbrains/qodana-php:2025.2 profile: name: qodana.recommended exclude: diff --git a/rector.php b/rector.php index 81b1041..d356972 100644 --- a/rector.php +++ b/rector.php @@ -3,16 +3,18 @@ use Rector\Config\RectorConfig; use Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector; -use Rector\PHPUnit\PHPUnit100\Rector\StmtsAwareInterface\WithConsecutiveRector; use Rector\PHPUnit\Set\PHPUnitSetList; return RectorConfig::configure() + ->withPhpSets(php83: true) + ->withAttributesSets(phpunit: true) + ->withComposerBased(phpunit: true) ->withSets([ - PHPUnitSetList::PHPUNIT_100, + PHPUnitSetList::PHPUNIT_110, ]) ->withSkip([ - WithConsecutiveRector::class, AddOverrideAttributeToOverriddenMethodsRector::class, __DIR__ . '/tests/bootstrap.php', + __DIR__ . '/rector.php', ]) ->withImportNames(); diff --git a/tests/SniffTestCase.php b/tests/SniffTestCase.php index 7f86144..ea48efb 100644 --- a/tests/SniffTestCase.php +++ b/tests/SniffTestCase.php @@ -17,9 +17,9 @@ */ class SniffTestCase extends TestCase { - private const FILE_BEFORE = 'before/Fixme.php'; + private const string FILE_BEFORE = 'before/Fixme.php'; - private const FILE_AFTER = 'after/Fixme.php'; + private const string FILE_AFTER = 'after/Fixme.php'; protected function assertSnifferFindsErrors(Sniff $sniffer, int $errorCount): array { diff --git a/tests/Unit/Kununu/CsFixer/Command/CsFixerCommandTest.php b/tests/Unit/Kununu/CsFixer/Command/CsFixerCommandTest.php index 8bc6263..fcb92eb 100644 --- a/tests/Unit/Kununu/CsFixer/Command/CsFixerCommandTest.php +++ b/tests/Unit/Kununu/CsFixer/Command/CsFixerCommandTest.php @@ -25,7 +25,7 @@ public function testCsFixerCommand(string $before, string $after): void $application->add(new CsFixerCommand()); $command = $application->find('kununu:cs-fixer'); - $tester = new CommandTester($command); + $tester = new CommandTester($command); $exitCode = $tester->execute([ 'files' => [$this->tempFile], @@ -44,7 +44,7 @@ public static function fixerCasesProvider(): array $cases = require $casesFile; - return array_map(fn ($case) => [$case['before'], $case['after']], $cases); + return array_map(fn($case) => [$case['before'], $case['after']], $cases); } private function contents(string $file): string diff --git a/tests/Unit/Kununu/CsFixer/Command/CsFixerGitHookCommandTest.php b/tests/Unit/Kununu/CsFixer/Command/CsFixerGitHookCommandTest.php index 38a58b7..aa6f179 100644 --- a/tests/Unit/Kununu/CsFixer/Command/CsFixerGitHookCommandTest.php +++ b/tests/Unit/Kununu/CsFixer/Command/CsFixerGitHookCommandTest.php @@ -20,7 +20,7 @@ public function testFailsWhenNotAGitRepo(): void $app->add(new CsFixerGitHookCommand()); $command = $app->find('kununu:cs-fixer-git-hook'); - $tester = new CommandTester($command); + $tester = new CommandTester($command); chdir($this->repoDir); @@ -54,7 +54,7 @@ public function testInstallsHookSuccessfully(): void $app->add(new CsFixerGitHookCommand()); $command = $app->find('kununu:cs-fixer-git-hook'); - $tester = new CommandTester($command); + $tester = new CommandTester($command); $exitCode = $tester->execute([]); @@ -67,7 +67,7 @@ public function testInstallsHookSuccessfully(): void self::assertTrue(is_executable($hook), 'pre-commit should be executable'); $symlinkConfig = $gitPath . '/kununu/.php-cs-fixer.php'; - $symlinkBin = $gitPath . '/kununu/php-cs-fixer'; + $symlinkBin = $gitPath . '/kununu/php-cs-fixer'; self::assertTrue(is_link($symlinkConfig), '.php-cs-fixer.php symlink should exist'); self::assertTrue(is_link($symlinkBin), 'php-cs-fixer symlink should exist'); From 0c51c60549009e79dace4d7c94636a17ca52380c Mon Sep 17 00:00:00 2001 From: Daniel Santos Date: Wed, 10 Sep 2025 09:07:44 +0100 Subject: [PATCH 2/3] Update path to architecture sniffer docs --- README.md | 2 +- {Kununu => docs}/ArchitectureSniffer/README.md | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {Kununu => docs}/ArchitectureSniffer/README.md (100%) diff --git a/README.md b/README.md index 421565d..5b7ae78 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ class: PHPAT\PHPStan\PHPStanExtension tags: [phpstan.extension] ``` -- For more details and advanced configuration, see [Kununu/ArchitectureSniffer/README.md](Kununu/ArchitectureSniffer/README.md). +- For more details and advanced configuration, see [Kununu/ArchitectureSniffer/README.md](docs/ArchitectureSniffer/README.md). ## Install diff --git a/Kununu/ArchitectureSniffer/README.md b/docs/ArchitectureSniffer/README.md similarity index 100% rename from Kununu/ArchitectureSniffer/README.md rename to docs/ArchitectureSniffer/README.md From 8e1dbc5de6e55886d914a1c8cd64257a465e158c Mon Sep 17 00:00:00 2001 From: Daniel Santos Date: Wed, 10 Sep 2025 09:08:34 +0100 Subject: [PATCH 3/3] Update readme --- README.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/README.md b/README.md index 5b7ae78..1b28215 100644 --- a/README.md +++ b/README.md @@ -57,22 +57,6 @@ ``` - For more details and advanced configuration, see [Kununu/ArchitectureSniffer/README.md](docs/ArchitectureSniffer/README.md). -## Install - -### Add custom private repositories to composer.json - -```json -{ - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/kununu/code-tools.git", - "no-api": true - } - ] -} -``` - ### Require Library as a dev dependency You can use this library by issuing the following command: