diff --git a/.gitignore b/.gitignore index e3e404997..160702ca8 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,7 @@ build ############ node_modules/ -vendor/ +/vendor/ ############ ## OSes diff --git a/includes/Checker/Checks/Plugin_Repo/File_Type_Check.php b/includes/Checker/Checks/Plugin_Repo/File_Type_Check.php index 7d4f97e67..bf90778c5 100644 --- a/includes/Checker/Checks/Plugin_Repo/File_Type_Check.php +++ b/includes/Checker/Checks/Plugin_Repo/File_Type_Check.php @@ -31,7 +31,8 @@ class File_Type_Check extends Abstract_File_Check { const TYPE_APPLICATION = 16; const TYPE_BADLY_NAMED = 32; const TYPE_LIBRARY_CORE = 64; - const TYPE_ALL = 127; // Same as all of the above with bitwise OR. + const TYPE_COMPOSER = 128; + const TYPE_ALL = 255; // Same as all of the above with bitwise OR. /** * Bitwise flags to control check behavior. @@ -75,6 +76,8 @@ public function get_categories() { * * @throws Exception Thrown when the check fails with a critical error (unrelated to any errors detected as part of * the check). + * + * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function check_files( Check_Result $result, array $files ) { if ( $this->flags & self::TYPE_COMPRESSED ) { @@ -99,6 +102,9 @@ protected function check_files( Check_Result $result, array $files ) { if ( $this->flags & self::TYPE_LIBRARY_CORE ) { $this->look_for_library_core_files( $result, $files ); } + if ( $this->flags & self::TYPE_COMPOSER ) { + $this->look_for_composer_files( $result, $files ); + } } /** @@ -372,6 +378,44 @@ function ( $file ) use ( $plugin_path ) { } } + /** + * Looks for composer files. + * + * @since 1.4.0 + * + * @param Check_Result $result The check result to amend, including the plugin context to check. + * @param array $files List of absolute file paths. + */ + protected function look_for_composer_files( Check_Result $result, array $files ) { + if ( $result->plugin()->is_single_file_plugin() ) { + return; + } + + $plugin_path = $result->plugin()->path(); + + if ( + is_dir( $plugin_path . 'vendor' ) && + file_exists( $plugin_path . 'vendor/autoload.php' ) && + ! file_exists( $plugin_path . 'composer.json' ) + ) { + $this->add_result_warning_for_file( + $result, + sprintf( + /* translators: 1: directory, 2: filename */ + esc_html__( 'The "%1$s" directory using composer exists, but "%2$s" file is missing.', 'plugin-check' ), + '/vendor', + 'composer.json' + ), + 'missing_composer_json_file', + 'composer.json', + 0, + 0, + 'https://developer.wordpress.org/plugins/wordpress-org/common-issues/#included-unneeded-folders', + 6 + ); + } + } + /** * Gets the description for the check. * diff --git a/tests/phpunit/testdata/plugins/test-plugin-file-type-composer-errors/load.php b/tests/phpunit/testdata/plugins/test-plugin-file-type-composer-errors/load.php new file mode 100644 index 000000000..bd9830168 --- /dev/null +++ b/tests/phpunit/testdata/plugins/test-plugin-file-type-composer-errors/load.php @@ -0,0 +1,17 @@ +assertArrayHasKey( 0, $errors['jquery.js'][0] ); $this->assertCount( 1, wp_list_filter( $errors['jquery.js'][0][0], array( 'code' => 'library_core_files' ) ) ); } + + public function test_run_with_composer_errors() { + $check_context = new Check_Context( UNIT_TESTS_PLUGIN_DIR . 'test-plugin-file-type-composer-errors/load.php' ); + $check_result = new Check_Result( $check_context ); + + $check = new File_Type_Check( File_Type_Check::TYPE_COMPOSER ); + $check->run( $check_result ); + + $warnings = $check_result->get_warnings(); + + $this->assertNotEmpty( $warnings ); + + $this->assertCount( 1, wp_list_filter( $warnings['composer.json'][0][0], array( 'code' => 'missing_composer_json_file' ) ) ); + } }