From 1e85d9a53bf6312a5eec4ffd5dea7e73e44d8f82 Mon Sep 17 00:00:00 2001 From: Antonio Mangiacapra <11173091+antonioeatgoat@users.noreply.github.com> Date: Fri, 25 Aug 2023 12:55:22 +0200 Subject: [PATCH 1/8] Update dependencies --- composer.json | 7 +++---- phpcs.xml | 10 ++++++---- tests/cases/FixturesTest.php | 1 + tests/src/FixtureContentParser.php | 4 ++++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index ff6f4fa..7644e18 100644 --- a/composer.json +++ b/composer.json @@ -29,11 +29,10 @@ ], "minimum-stability": "stable", "require": { - "php": ">=7", + "php": ">=7.4", "squizlabs/php_codesniffer": "^3.6.0", - "dealerdirect/phpcodesniffer-composer-installer": "~0.7.0", - "wp-coding-standards/wpcs": "^2.3", - "automattic/vipwpcs": "^2.2", + "dealerdirect/phpcodesniffer-composer-installer": "~1.0.0", + "automattic/vipwpcs": "dev-3.0/updates-for-wpcs-3.0", "phpcompatibility/php-compatibility": "^9.3.5", "automattic/phpcs-neutron-standard": "^1.6.0" }, diff --git a/phpcs.xml b/phpcs.xml index 8a81c7a..dec7c58 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -60,9 +60,7 @@ Curated list of WordPress specific rules. See https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards --> - - - + @@ -98,7 +96,6 @@ - @@ -152,6 +149,8 @@ Generic --> + + @@ -161,6 +160,7 @@ + @@ -173,6 +173,8 @@ + + - - + - - - - - - warning - - - warning - - - warning - - - warning - - - warning - - - warning - - - warning - diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 76b6d6e..d997102 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,22 +1,20 @@ - - - tests/cases/FixturesTest.php - - - tests/cases/PhpcsHelpersTest.php - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" + bootstrap="tests/bootstrap.php" + colors="true"> + + + ./Inpsyde + + + + + tests/cases/FixturesTest.php + + + tests/cases/PhpcsHelpersTest.php + + diff --git a/psalm.xml b/psalm.xml index ee09b08..53e46c1 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,11 +1,14 @@ - - - diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 878abe6..6fd220d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,6 @@ -parse($fixtureFile); + [$sniffClass, $expected, $properties] = $parser->parse($fixtureFile); $file = $this->createPhpcsForFixture($sniffClass, $fixtureFile, $properties); $actual = (new SniffMessagesExtractor($file))->extractMessages(); @@ -105,7 +103,7 @@ private function validateCodes( SniffMessages $actual, string $fixture, string $sniffClass - ) { + ): void { $where = sprintf("\nin fixture file '%s' line %%d\nfor sniff '%s'", $fixture, $sniffClass); @@ -136,7 +134,7 @@ private function validateCode( string $code, string $where, string $actualCode = null - ) { + ): void { $message = $code ? sprintf('Expected %s code \'%s\' was not found', $type, $code) @@ -158,7 +156,7 @@ private function validateTotals( SniffMessages $actual, string $fixtureFile, string $sniffClass - ) { + ): void { $expectedTotal = $expected->total(); $actualTotal = $actual->total(); @@ -195,22 +193,20 @@ private function createPhpcsForFixture( array $properties ): File { - $sniffName = str_replace('.', DIRECTORY_SEPARATOR, $sniffName) . 'Sniff'; - $sniffFile = getenv('SNIFFS_PATH') . DIRECTORY_SEPARATOR . "{$sniffName}.php"; - if (!file_exists($sniffFile) || !is_readable($sniffFile)) { + $sniffFile = str_replace('.', '/', "{$sniffName}Sniff"); + $sniffPath = getenv('SNIFFS_PATH') . "/{$sniffFile}.php"; + if (!file_exists($sniffPath) || !is_readable($sniffPath)) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - throw new Exception("Non-existent of unreadable sniff file '$sniffFile' found."); + throw new Exception("Non-existent of unreadable sniff file '{$sniffPath}' found."); } $config = new Config(); - $config->standards = []; - /** @var Ruleset $ruleset */ - $ruleset = (new \ReflectionClass(Ruleset::class))->newInstanceWithoutConstructor(); - $ruleset->registerSniffs([$sniffFile], [], []); - $ruleset->populateTokenListeners(); + $config->standards = [dirname(getenv('SNIFFS_PATH'))]; + $config->sniffs = ["Inpsyde.{$sniffName}"]; + $ruleset = new Ruleset($config); $baseSniffNamespace = getenv('SNIFFS_NAMESPACE'); - $sniffFqn = str_replace(DIRECTORY_SEPARATOR, '\\', $sniffName); + $sniffFqn = str_replace('/', '\\', $sniffFile); foreach ($properties as $name => $value) { $ruleset->setSniffProperty("{$baseSniffNamespace}\\{$sniffFqn}", $name, $value); } diff --git a/tests/cases/PhpcsHelpersTest.php b/tests/cases/PhpcsHelpersTest.php index d94b1e3..bbdc19e 100644 --- a/tests/cases/PhpcsHelpersTest.php +++ b/tests/cases/PhpcsHelpersTest.php @@ -1,5 +1,14 @@ readFile($fixturePath) as $lineNum => $line) { $this->readLine($lineNum, $line, $accumulator); } - // phpcs:enable return $this->processResults($accumulator, $fixturePath); } /** - * @param \stdClass $accumulator + * @param object $accumulator * @param string $fixturePath * @return array */ - private function processResults(\stdClass $accumulator, string $fixturePath): array + private function processResults(object $accumulator, string $fixturePath): array { - $results = [ - $accumulator->sniff, - $accumulator->messages, - $accumulator->warnings, - $accumulator->errors, - $accumulator->properties->values, - ]; - if (!$accumulator->process->content) { return [ - $this->checkSniffName(array_shift($results)), - new SniffMessages($results[1], $results[2], $results[0]), + $this->checkSniffName($accumulator->sniff), + new SniffMessages( + $accumulator->warnings, + $accumulator->errors, + $accumulator->messages + ), $accumulator->properties->values, ]; } // phpcs:disable eval("\$cb = {$accumulator->process->content};"); - /** @var callable $cb */ - $results = $cb(...$results); + $params = [ + $accumulator->sniff, + $accumulator->messages, + $accumulator->warnings, + $accumulator->errors, + $accumulator->properties->values, + ]; + /** @var mixed $cb */ + $results = is_callable($cb) ? $cb(...$params) : null; // phpcs:enable + $results = array_values(array_pad(is_array($results) ? $results : [], 5, null)); + [$sniff, $messages, $warnings, $errors, $properties] = $results; + if ( - $accumulator->process->content - && !is_array($results) - || count($results) !== 5 - || !is_string($results[0] ?? null) - || !is_array($results[1] ?? null) - || !is_array($results[2] ?? null) - || !is_array($results[3] ?? null) - || !is_array($results[4] ?? null) + !is_string($sniff) + || !is_array($messages) + || !is_array($warnings) + || !is_array($errors) + || !is_array($properties) ) { - throw new Exception( - // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped + throw new \Error( sprintf( "Process callback for fixture '%s' (lines #%s:#%s) returned invalid output.", $fixturePath, $accumulator->process->start, $accumulator->process->end ) - // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped ); } return [ - $this->checkSniffName(array_shift($results)), - new SniffMessages($results[1], $results[2], $results[0]), - $results[3], + $this->checkSniffName($sniff), + new SniffMessages($warnings, $errors, $messages), + $properties, ]; } @@ -127,10 +122,10 @@ private function processResults(\stdClass $accumulator, string $fixturePath): ar * @param string|null $sniff * @return string */ - private function checkSniffName(string $sniff = null): string + private function checkSniffName(?string $sniff): string { if ($sniff === null) { - throw new Exception("No sniff class found for the test."); + throw new \Error("No sniff class found for the test."); } static $regex; @@ -140,8 +135,7 @@ private function checkSniffName(string $sniff = null): string } if (!preg_match('~^' . $regex . '$~', $sniff)) { - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - throw new Exception("Invalid sniff name '{$sniff}'."); + throw new \Error("Invalid sniff name '{$sniff}'."); } return $sniff; @@ -154,6 +148,10 @@ private function checkSniffName(string $sniff = null): string private function readFile(string $file): \Generator { $handle = fopen($file, 'rb'); + if ($handle === false) { + throw new \Error("Could not open '{$file}' for reading."); + } + $lineNum = 1; $line = fgets($handle); @@ -168,9 +166,9 @@ private function readFile(string $file): \Generator /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator */ - private function readLine(int $lineNum, string $line, \stdClass $accumulator) + private function readLine(int $lineNum, string $line, object $accumulator): void { if ( !$this->readProcessLine($lineNum, $line, $accumulator) @@ -184,10 +182,10 @@ private function readLine(int $lineNum, string $line, \stdClass $accumulator) /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator * @return bool */ - private function readProcessLine(int $lineNum, string $line, \stdClass $accumulator): bool + private function readProcessLine(int $lineNum, string $line, object $accumulator): bool { if ($accumulator->process->end !== false) { return false; @@ -213,10 +211,10 @@ private function readProcessLine(int $lineNum, string $line, \stdClass $accumula /** * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator * @return bool */ - private function readSniffLine(string $line, \stdClass $accumulator): bool + private function readSniffLine(string $line, object $accumulator): bool { if ($accumulator->sniff) { return false; @@ -238,10 +236,10 @@ private function readSniffLine(string $line, \stdClass $accumulator): bool /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator * @return bool */ - private function readPropertiesLine(int $lineNum, string $line, \stdClass $accumulator): bool + private function readPropertiesLine(int $lineNum, string $line, object $accumulator): bool { static $pattern; $pattern or $pattern = '~\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*=\s*([^;]+);~'; @@ -274,9 +272,9 @@ private function readPropertiesLine(int $lineNum, string $line, \stdClass $accum /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator */ - private function readTokenLine(int $lineNum, string $line, \stdClass $accumulator) + private function readTokenLine(int $lineNum, string $line, object $accumulator): void { static $pattern; if (!$pattern) { diff --git a/tests/src/SniffMessages.php b/tests/src/SniffMessages.php index c5aa846..339b8f5 100644 --- a/tests/src/SniffMessages.php +++ b/tests/src/SniffMessages.php @@ -1,9 +1,6 @@ messagesContainTotal = true; } @@ -69,7 +53,7 @@ public function messages(): array * @param int $line * @return string|null */ - public function messageIn(int $line) + public function messageIn(int $line): ?string { return $this->messages[$line] ?? null; } @@ -99,7 +83,7 @@ public function errors(): array * @param int $line * @return string|null */ - public function errorIn(int $line) + public function errorIn(int $line): ?string { return $this->errors[$line] ?? null; } @@ -124,7 +108,7 @@ public function warnings(): array * @param int $line * @return string|null */ - public function warningIn(int $line) + public function warningIn(int $line): ?string { return $this->warnings[$line] ?? null; } diff --git a/tests/src/SniffMessagesExtractor.php b/tests/src/SniffMessagesExtractor.php index 6f8f8b7..1f98b27 100644 --- a/tests/src/SniffMessagesExtractor.php +++ b/tests/src/SniffMessagesExtractor.php @@ -1,9 +1,6 @@ file->process(); - list($warnings, $errors) = $this->normalize( + [$warnings, $errors] = $this->normalize( $this->file->getWarnings(), $this->file->getErrors() ); From 6a404be1eb4dfbfe3ba28013a3f783c30a64e72f Mon Sep 17 00:00:00 2001 From: Giuseppe Mazzapica Date: Sat, 26 Aug 2023 00:29:04 +0200 Subject: [PATCH 8/8] Make use of reusable workflows for QA --- .github/workflows/php-qa.yml | 76 --------------------- .github/workflows/quality-assurance-php.yml | 51 ++++++++++++++ 2 files changed, 51 insertions(+), 76 deletions(-) delete mode 100644 .github/workflows/php-qa.yml create mode 100644 .github/workflows/quality-assurance-php.yml diff --git a/.github/workflows/php-qa.yml b/.github/workflows/php-qa.yml deleted file mode 100644 index 8cf444a..0000000 --- a/.github/workflows/php-qa.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: PHP Quality Assurance -on: - push: - pull_request: - workflow_dispatch: -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -jobs: - static-qa: - runs-on: ubuntu-latest - if: ${{ !contains(github.event.head_commit.message, 'no static qa') }} - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 7.4 - coverage: none - tools: cs2pr - - - name: Install dependencies - uses: ramsey/composer-install@v2 - - - name: Check code styles - run: | - ./vendor/bin/phpcs -q --report-full --report-checkstyle="phpcs-report.xml" --runtime-set testVersion 7.0- --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 - cs2pr --graceful-warnings phpcs-report.xml - - - name: Check Psalm - run: ./vendor/bin/psalm --output-format=github --no-cache - - unit-tests: - runs-on: ubuntu-latest - if: ${{ !contains(github.event.head_commit.message, 'no unit tests') }} - strategy: - fail-fast: true - matrix: - php-ver: [ '7.4', '8.0', '8.1', '8.2' ] - deps-mode: [ 'lowest', 'highest' ] - include: - - php-ver: '8.1' - dependency-versions: 'highest' - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-ver }} - ini-values: zend.assertions=1, error_reporting=-1, display_errors=On - coverage: none - tools: cs2pr, parallel-lint:^1.3.1 - - - name: Check syntax error in sources - if: ${{ (matrix.deps-mode == 'highest') }} - run: parallel-lint ./Inpsyde/ ./tests/src/ ./tests/cases/ --checkstyle | cs2pr - - - name: Remove Psalm before tests to prevent installation conflicts - run: composer remove vimeo/psalm --no-update - - - name: Install dependencies - uses: ramsey/composer-install@v2 - with: - dependency-versions: ${{ matrix.deps-mode }} - - - name: Migrate PHPUnit config for PHPUnit 9 - if: ${{ (matrix.php-ver >= 7.3) && (matrix.deps-mode == 'highest') }} - run: ./vendor/bin/phpunit --migrate-configuration - - - name: Run unit tests - run: ./vendor/bin/phpunit --testsuite=unit --no-coverage diff --git a/.github/workflows/quality-assurance-php.yml b/.github/workflows/quality-assurance-php.yml new file mode 100644 index 0000000..cee505f --- /dev/null +++ b/.github/workflows/quality-assurance-php.yml @@ -0,0 +1,51 @@ +name: PHP Quality Assurance + +on: + push: + paths: + - '**workflows/quality-assurance-php.yml' + - '**.php' + - '**phpcs.xml.dist' + - '**phpunit.xml.dist' + - '**psalm.xml' + workflow_dispatch: + inputs: + jobs: + required: true + type: choice + default: 'Run all' + description: 'Choose jobs to run' + options: + - 'Run all' + - 'Run PHPCS only' + - 'Run Psalm only' + - 'Run lint only' + - 'Run static analysis' + - 'Run unit tests only' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint-php: + uses: inpsyde/reusable-workflows/.github/workflows/lint-php.yml@main + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run lint only') || (github.event.inputs.jobs == 'Run static analysis')) }} + with: + PHP_MATRIX: '["7.4", "8.0", "8.1", "8.2"]' + LINT_ARGS: '-e php --colors --show-deprecated ./Inpsyde' + + coding-standards-analysis-php: + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run PHPCS only') || (github.event.inputs.jobs == 'Run static analysis')) }} + uses: inpsyde/reusable-workflows/.github/workflows/coding-standards-php.yml@main + + static-code-analysis-php: + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run Psalm only') || (github.event.inputs.jobs == 'Run static analysis')) }} + uses: inpsyde/reusable-workflows/.github/workflows/static-analysis-php.yml@main + + tests-unit-php: + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run unit tests only')) }} + uses: inpsyde/reusable-workflows/.github/workflows/tests-unit-php.yml@main + with: + PHP_MATRIX: '["7.4", "8.0", "8.1", "8.2"]' + PHPUNIT_ARGS: '--no-coverage'