diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 5a1048e4bcea5..c1edb9e04ffc3 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -3,23 +3,9 @@ - - - - - - - - - - error - + - - - - /extensions/blocks/podcast-player/templates/* diff --git a/bin/PHPCSStandards/Jetpack/ruleset.xml b/bin/PHPCSStandards/Jetpack/ruleset.xml deleted file mode 100644 index e2fc11150a211..0000000000000 --- a/bin/PHPCSStandards/Jetpack/ruleset.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Jetpack Specific lint rules. - diff --git a/bin/phpcs-requirelist.js b/bin/phpcs-requirelist.js index 00bcdae05a58b..507478eda07b2 100644 --- a/bin/phpcs-requirelist.js +++ b/bin/phpcs-requirelist.js @@ -86,5 +86,4 @@ module.exports = [ 'tests/php/general/test-class.jetpack-network.php', 'tests/php/test_class.jetpack_photon.php', 'views/admin/deactivation-dialog.php', - 'bin/PHPCSStandards', ]; diff --git a/composer.json b/composer.json index a9cd7d1717136..f90bfd88276fc 100644 --- a/composer.json +++ b/composer.json @@ -39,11 +39,9 @@ "nojimage/twitter-text-php": "3.1.1" }, "require-dev": { + "automattic/jetpack-codesniffer": "@dev", "dealerdirect/phpcodesniffer-composer-installer": "0.7.0", - "phpcompatibility/phpcompatibility-wp": "2.1.0", - "sirbrillig/phpcs-changed": "2.5.1", - "sirbrillig/phpcs-variable-analysis": "2.8.3", - "wp-coding-standards/wpcs": "2.3.0" + "sirbrillig/phpcs-changed": "2.5.1" }, "scripts": { "php:compatibility": "vendor/bin/phpcs -p -s --runtime-set testVersion '5.6-' --standard=PHPCompatibilityWP --ignore=docker,tools,tests,node_modules,vendor,packages/*/wordpress --extensions=php", diff --git a/composer.lock b/composer.lock index 1b20731d7b6ed..3707b1c5f06a7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "31c2399fec4166dba523747a45bc3e63", + "content-hash": "efff4548a1ae7ce5242533ce98017806", "packages": [ { "name": "automattic/jetpack-a8c-mc-stats", @@ -927,6 +927,43 @@ } ], "packages-dev": [ + { + "name": "automattic/jetpack-codesniffer", + "version": "dev-add/codesniffer-package", + "dist": { + "type": "path", + "url": "./packages/codesniffer", + "reference": "d74b803f4fe94393e83a65207cbbe9b0532da356" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "0.*", + "phpcompatibility/phpcompatibility-wp": "2.1.0", + "sirbrillig/phpcs-variable-analysis": "2.8.3", + "wp-coding-standards/wpcs": "2.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "Jetpack\\Sniffs\\": "Jetpack/Sniffs" + } + }, + "scripts": { + "phpunit": [ + "@composer install", + "./vendor/phpunit/phpunit/phpunit --colors=always" + ] + }, + "license": [ + "GPL-2.0-or-later" + ], + "description": "Jetpack Coding Standards. Based on the WordPress Coding Standards, with some additions.", + "transport-options": { + "relative": true + } + }, { "name": "dealerdirect/phpcodesniffer-composer-installer", "version": "v0.7.0", @@ -1380,7 +1417,8 @@ "automattic/jetpack-status": 20, "automattic/jetpack-sync": 20, "automattic/jetpack-terms-of-service": 20, - "automattic/jetpack-tracking": 20 + "automattic/jetpack-tracking": 20, + "automattic/jetpack-codesniffer": 20 }, "prefer-stable": true, "prefer-lowest": false, diff --git a/packages/codesniffer/.gitattributes b/packages/codesniffer/.gitattributes new file mode 100644 index 0000000000000..a6921e6098673 --- /dev/null +++ b/packages/codesniffer/.gitattributes @@ -0,0 +1,4 @@ +# Files not needed to be distributed in the package. +.gitattributes export-ignore +phpunit.xml.dist export-ignore +tests/ export-ignore diff --git a/packages/codesniffer/.gitignore b/packages/codesniffer/.gitignore new file mode 100644 index 0000000000000..7579f74311d35 --- /dev/null +++ b/packages/codesniffer/.gitignore @@ -0,0 +1,2 @@ +vendor +composer.lock diff --git a/bin/PHPCSStandards/Jetpack/Sniffs/Constants/MasterUserConstantSniff.php b/packages/codesniffer/Jetpack/Sniffs/Constants/MasterUserConstantSniff.php similarity index 100% rename from bin/PHPCSStandards/Jetpack/Sniffs/Constants/MasterUserConstantSniff.php rename to packages/codesniffer/Jetpack/Sniffs/Constants/MasterUserConstantSniff.php diff --git a/packages/codesniffer/Jetpack/ruleset.xml b/packages/codesniffer/Jetpack/ruleset.xml new file mode 100644 index 0000000000000..16b0495ded62e --- /dev/null +++ b/packages/codesniffer/Jetpack/ruleset.xml @@ -0,0 +1,22 @@ + + + Jetpack coding standards. Based on the WordPress coding standards, with some additions. + + + + + + + + + + error + + + + + + + + + diff --git a/packages/codesniffer/README.md b/packages/codesniffer/README.md new file mode 100644 index 0000000000000..8593855673d6f --- /dev/null +++ b/packages/codesniffer/README.md @@ -0,0 +1,27 @@ +Jetpack Coding Standard +======================= + +This is a package implementing phpcs sniffs for the Jetpack Coding Standard. + +This standard is generally that of WordPress, with a few additions. + +Usage +----- + +In your project's `composer.json`, add the following lines: + +```json +{ + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "*", + "automattic/jetpack-codesniffer": "^1" + } +} +``` + +Your project must use the default composer vendor directory, `vendor`. + +You should then include the Jetpack rules in your `.phpcs.xml.dist`, like +```xml + +``` diff --git a/packages/codesniffer/composer.json b/packages/codesniffer/composer.json new file mode 100644 index 0000000000000..3487821d714cd --- /dev/null +++ b/packages/codesniffer/composer.json @@ -0,0 +1,28 @@ +{ + "name": "automattic/jetpack-codesniffer", + "description": "Jetpack Coding Standards. Based on the WordPress Coding Standards, with some additions.", + "type": "phpcodesniffer-standard", + "license": "GPL-2.0-or-later", + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "0.*", + "phpcompatibility/phpcompatibility-wp": "2.1.0", + "sirbrillig/phpcs-variable-analysis": "2.8.3", + "wp-coding-standards/wpcs": "2.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5" + }, + "autoload": { + "psr-4": { + "Jetpack\\Sniffs\\": "Jetpack/Sniffs" + } + }, + "scripts": { + "phpunit": [ + "@composer install", + "./vendor/phpunit/phpunit/phpunit --colors=always" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/packages/codesniffer/phpunit.xml.dist b/packages/codesniffer/phpunit.xml.dist new file mode 100644 index 0000000000000..98ca0f0599aee --- /dev/null +++ b/packages/codesniffer/phpunit.xml.dist @@ -0,0 +1,16 @@ + + + + tests/php/tests + + + + + . + + tests + vendor + + + + diff --git a/packages/codesniffer/tests/php/bootstrap.php b/packages/codesniffer/tests/php/bootstrap.php new file mode 100644 index 0000000000000..b938003f446ec --- /dev/null +++ b/packages/codesniffer/tests/php/bootstrap.php @@ -0,0 +1,18 @@ + $details ) { + PHP_CodeSniffer\Autoload::addSearchPath( $details['path'], $details['namespace'] ); +} diff --git a/packages/codesniffer/tests/php/tests/files/master-user-constant.php.report b/packages/codesniffer/tests/php/tests/files/master-user-constant.php.report new file mode 100644 index 0000000000000..0f4b4dfe0660f --- /dev/null +++ b/packages/codesniffer/tests/php/tests/files/master-user-constant.php.report @@ -0,0 +1,2 @@ + 9 | WARNING | JETPACK_MASTER_USER constant should not be used. Use the blog token to make requests instead, or use the current user token when needed. + | | (Jetpack.Constants.MasterUserConstant.ShouldNotBeUsed) diff --git a/packages/codesniffer/tests/php/tests/files/master-user-constant.php.tolint b/packages/codesniffer/tests/php/tests/files/master-user-constant.php.tolint new file mode 100644 index 0000000000000..7830c27e86bc2 --- /dev/null +++ b/packages/codesniffer/tests/php/tests/files/master-user-constant.php.tolint @@ -0,0 +1,10 @@ +assertInternalType( 'string', $contents ); + + $config = new Config(); + + $config->standards = array( __DIR__ . '/../../../Jetpack/ruleset.xml' ); + $config->files = array( $file ); + $config->encoding = 'utf-8'; + $config->reports = array( 'full' => null ); + $config->colors = false; + $config->reportWidth = PHP_INT_MAX; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + $config->showSources = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + $config->tabWidth = 4; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + + $ruleset = new Ruleset( $config ); + $dummy = new DummyFile( $contents, $ruleset, $config ); + $dummy->process(); + + if ( ! $fix ) { + $reporter = new Reporter( $config ); + $reporter->cacheFileReport( $dummy ); + ob_start(); + $reporter->printReport( 'full' ); + $result = ob_get_clean(); + + // Clean up output. + $lines = preg_split( '/[\r\n]+/', $result, -1, PREG_SPLIT_NO_EMPTY ); + $lines = preg_grep( '/^-*$|^(?:Time:|FILE:|FOUND|PHPCBF) /', $lines, PREG_GREP_INVERT ); + return implode( "\n", $lines ) . "\n"; + } elseif ( $dummy->getFixableCount() ) { + $dummy->fixer->fixFile(); + return $dummy->fixer->getContents(); + } else { + return $contents; + } + } + + /** + * Test the sniffs by running phpcs or phpcbf against a file. + * + * @dataProvider provide_files + * @param string $file Base filename, without the ".tolint", ".report", or ".fixed" extension. + * @param bool $fix Run as phpcbf rather than phpcs. + */ + public function test_phpcs( $file, $fix ) { + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + $expect = file_get_contents( $fix ? "$file.fixed" : "$file.report" ); + $this->assertInternalType( 'string', $expect ); + $this->assertEquals( $expect, $this->run_phpcs( $file, $fix ) ); + } + + /** + * Provide arguments for `test_phpcs()`. + * + * @return array + */ + public function provide_files() { + $dir_iterator = new RecursiveDirectoryIterator( __DIR__ . '/files', RecursiveDirectoryIterator::CURRENT_AS_PATHNAME ); + $iterator = new RegexIterator( + new RecursiveIteratorIterator( $dir_iterator ), + '/\.(?:tolint|report|fixed)$/' + ); + $files = iterator_to_array( $iterator ); + + $ret = array(); + foreach ( $files as $file => $dummy ) { + $i = strrpos( $file, '.' ); + $ext = substr( $file, $i ); + $file = substr( $file, 0, $i ); + + switch ( $ext ) { + case '.tolint': + if ( ! isset( $files[ "$file.report" ] ) && ! isset( $files[ "$file.fixed" ] ) ) { + fprintf( STDERR, "%s: %s.tolint exists, but both %s.report and %s.fixed are missing.\n", __METHOD__, $file, $file, $file ); + } + break; + + case '.report': + case '.fixed': + if ( isset( $files[ "$file.tolint" ] ) ) { + $ret[ "$file$ext" ] = array( $file, '.fixed' === $ext ); + } else { + fprintf( STDERR, "%s: %s exists, but %s.tolint is missing.\n", __METHOD__, $file . $ext, $file ); + } + break; + } + } + + return $ret; + } + +}