PluginProbe
Plugin Check (PCP) / 1.5.0
Plugin Check (PCP) v1.5.0
2.1.0 trunk 0.1 0.2.0 0.2.1 0.2.2 0.2.3 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.3.0 1.3.1 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 ci-artifacts
plugin-check / includes / Checker / Checks / Abstract_PHP_CodeSniffer_Check.php

Abstract_PHP_CodeSniffer_Check.php in Plugin Check (PCP) 1.5.0, at includes/Checker/Checks/Abstract_PHP_CodeSniffer_Check.php

254 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class WordPress\Plugin_Check\Checker\Checks\Abstract_PHP_CodeSniffer_Check
4 *
5 * @package plugin-check
6 */
7
8 namespace WordPress\Plugin_Check\Checker\Checks;
9
10 use Exception;
11 use PHP_CodeSniffer\Config;
12 use PHP_CodeSniffer\Runner;
13 use WordPress\Plugin_Check\Checker\Check_Result;
14 use WordPress\Plugin_Check\Checker\Static_Check;
15 use WordPress\Plugin_Check\Traits\Amend_Check_Result;
16 use WordPress\Plugin_Check\Utilities\Plugin_Request_Utility;
17
18 /**
19 * Check for running one or more PHP CodeSniffer sniffs.
20 *
21 * @since 1.0.0
22 */
23 abstract class Abstract_PHP_CodeSniffer_Check implements Static_Check {
24
25 use Amend_Check_Result;
26
27 /**
28 * List of allowed PHPCS arguments.
29 *
30 * @since 1.0.0
31 * @var array
32 */
33 protected $allowed_args = array(
34 'standard' => true,
35 'extensions' => true,
36 'sniffs' => true,
37 'runtime-set' => true,
38 'exclude' => true, //phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude
39 );
40
41 /**
42 * Returns an associative array of arguments to pass to PHPCS.
43 *
44 * @since 1.0.0
45 *
46 * @param Check_Result $result The check result to amend, including the plugin context to check.
47 * @return array {
48 * An associative array of PHPCS CLI arguments. Can include one or more of the following options.
49 *
50 * @type string $standard The name or path to the coding standard to check against.
51 * @type string $extensions A comma separated list of file extensions to check against.
52 * @type string $sniffs A comma separated list of sniff codes to include from checks.
53 * @type string $exclude A comma separated list of sniff codes to exclude from checks.
54 * }
55 */
56 abstract protected function get_args( Check_Result $result );
57
58 /**
59 * Amends the given result by running the check on the associated plugin.
60 *
61 * @SuppressWarnings(PHPMD.NPathComplexity)
62 *
63 * @since 1.0.0
64 *
65 * @param Check_Result $result The check result to amend, including the plugin context to check.
66 *
67 * @throws Exception Thrown when the check fails with a critical error (unrelated to any errors detected as part of
68 * the check).
69 */
70 final public function run( Check_Result $result ) {
71 // Include the PHPCS autoloader.
72 $autoloader = WP_PLUGIN_CHECK_PLUGIN_DIR_PATH . 'vendor/squizlabs/php_codesniffer/autoload.php';
73
74 if ( file_exists( $autoloader ) ) {
75 include_once $autoloader;
76 }
77
78 if ( ! class_exists( Runner::class ) ) {
79 throw new Exception(
80 __( 'Unable to find PHPCS Runner class.', 'plugin-check' )
81 );
82 }
83
84 if ( ! class_exists( Config::class ) ) {
85 throw new Exception(
86 __( 'Unable to find PHPCS Config class.', 'plugin-check' )
87 );
88 }
89
90 // Backup the original command line arguments.
91 $orig_cmd_args = $_SERVER['argv'] ?? '';
92
93 $args = $this->get_args( $result );
94
95 // Reset PHP_CodeSniffer config.
96 $this->reset_php_codesniffer_config();
97
98 // Get current installed_paths config.
99 $installed_paths = Config::getConfigData( 'installed_paths' );
100
101 // Override installed_paths to load custom sniffs.
102 if ( isset( $args['installed_paths'] ) && is_array( $args['installed_paths'] ) ) {
103 Config::setConfigData( 'installed_paths', implode( ',', $args['installed_paths'] ), true );
104 }
105
106 // Create the default arguments for PHPCS.
107 $defaults = $this->get_argv_defaults( $result );
108
109 // Set the check arguments for PHPCS.
110 $_SERVER['argv'] = $this->parse_argv( $args, $defaults );
111
112 // Run PHPCS.
113 try {
114 ob_start();
115 $runner = new Runner();
116 $runner->runPHPCS();
117 $reports = ob_get_clean();
118 } catch ( Exception $e ) {
119 $_SERVER['argv'] = $orig_cmd_args;
120 throw $e;
121 }
122
123 // Reset installed_paths.
124 Config::setConfigData( 'installed_paths', $installed_paths, true );
125
126 // Restore original arguments.
127 $_SERVER['argv'] = $orig_cmd_args;
128
129 // Parse the reports into data to add to the overall $result.
130 $reports = json_decode( trim( $reports ), true );
131
132 if ( empty( $reports['files'] ) ) {
133 return;
134 }
135
136 foreach ( $reports['files'] as $file_name => $file_results ) {
137 if ( empty( $file_results['messages'] ) ) {
138 continue;
139 }
140
141 foreach ( $file_results['messages'] as $file_message ) {
142 $this->add_result_message_for_file(
143 $result,
144 strtoupper( $file_message['type'] ) === 'ERROR',
145 esc_html( $file_message['message'] ),
146 $file_message['source'],
147 $file_name,
148 $file_message['line'],
149 $file_message['column'],
150 '',
151 $file_message['severity']
152 );
153 }
154 }
155 }
156
157 /**
158 * Parse the command arguments.
159 *
160 * @since 1.0.0
161 *
162 * @param array $argv An array of arguments to pass.
163 * @param array $defaults An array of default arguments.
164 * @return array An indexed array of PHPCS CLI arguments.
165 */
166 private function parse_argv( $argv, $defaults ) {
167 // Only accept allowed PHPCS arguments from check arguments array.
168 $check_args = array_intersect_key( $argv, $this->allowed_args );
169
170 // Format check arguments for PHPCS.
171 foreach ( $check_args as $key => $value ) {
172 if ( 'runtime-set' === $key ) {
173 if ( is_array( $value ) ) {
174 foreach ( $value as $item_key => $item_value ) {
175 $defaults = array_merge( $defaults, array( "--{$key}", $item_key, $item_value ) );
176 }
177 }
178 } else {
179 $defaults[] = "--{$key}=$value";
180 }
181 }
182
183 return $defaults;
184 }
185
186 /**
187 * Gets the default command arguments.
188 *
189 * @since 1.0.0
190 *
191 * @param Check_Result $result The check result to amend, including the plugin context to check.
192 * @return array An indexed array of PHPCS CLI arguments.
193 */
194 private function get_argv_defaults( Check_Result $result ): array {
195 $defaults = array(
196 '',
197 $result->plugin()->location(),
198 '--report=Json',
199 '--report-width=9999',
200 );
201
202 $ignore_patterns = array();
203
204 $directories_to_ignore = Plugin_Request_Utility::get_directories_to_ignore();
205 $files_to_ignore = Plugin_Request_Utility::get_files_to_ignore();
206
207 // Ignore directories.
208 if ( ! empty( $directories_to_ignore ) ) {
209 $ignore_patterns[] = '*/' . implode( '/*,*/', $directories_to_ignore ) . '/*';
210 }
211
212 // Ignore files.
213 if ( ! empty( $files_to_ignore ) ) {
214 $ignore_patterns[] = '/' . implode( ',/', $files_to_ignore );
215 }
216
217 if ( ! empty( $ignore_patterns ) ) {
218 $defaults[] = '--ignore=' . implode( ',', $ignore_patterns );
219 }
220
221 // Set the Minimum WP version supported for the plugin.
222 if ( $result->plugin()->minimum_supported_wp() ) {
223 // Due to the syntax of runtime-set, these must be passed as individual args.
224 $defaults[] = '--runtime-set';
225 $defaults[] = 'minimum_wp_version';
226 $defaults[] = $result->plugin()->minimum_supported_wp();
227 }
228
229 return $defaults;
230 }
231
232 /**
233 * Resets \PHP_CodeSniffer\Config::$overriddenDefaults to prevent
234 * incorrect results when running multiple checks.
235 *
236 * @since 1.0.0
237 */
238 private function reset_php_codesniffer_config() {
239 if ( class_exists( Config::class ) ) {
240 /*
241 * PHPStan ignore reason: PHPStan raised an issue because we can't
242 * use class in ReflectionClass.
243 *
244 * @phpstan-ignore-next-line
245 */
246 $reflected_phpcs_config = new \ReflectionClass( Config::class );
247 $overridden_defaults = $reflected_phpcs_config->getProperty( 'overriddenDefaults' );
248 $overridden_defaults->setAccessible( true );
249 $overridden_defaults->setValue( $reflected_phpcs_config, array() );
250 $overridden_defaults->setAccessible( false );
251 }
252 }
253 }
254