Making WordPress.org

Changeset 14565


Ignore:
Timestamp:
10/24/2025 06:11:26 AM (3 months ago)
Author:
dd32
Message:

Plugin Directory: Run Plugin Check over new plugin releases.

Props davidperez, dd32.
Closes https://github.com/WordPress/wordpress.org/pull/515
See #6108, #5637, #5868.
Fixes #8018.

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/jobs/class-manager.php

    r14412 r14565  
    2222        'import_plugin_i18n' => array( __NAMESPACE__ . '\Plugin_i18n_Import', 'cron_trigger' ),
    2323        'import_zip'         => array( __NAMESPACE__ . '\Plugin_ZIP_Import', 'cron_trigger' ),
     24        'scan_plugin'        => array( __NAMESPACE__ . '\Plugin_Updates_PCP', 'cron_trigger' ),
    2425    );
    2526
     
    4142        add_action( 'plugin_directory_daily_post_checks', array( __NAMESPACE__ . '\Daily_Post_Checks', 'cron_trigger' ) );
    4243        add_action( 'plugin_directory_create_svn_repo', array( __NAMESPACE__ . '\SVN_Repo_Creation', 'cron_trigger' ) );
     44
     45        // Hook into the plugin import process to queue a job.
     46        add_action( 'wporg_plugins_imported', array( __NAMESPACE__ . '\Plugin_Updates_PCP', 'wporg_plugins_imported' ), 10, 5 );
    4347
    4448        // A cronjob to check cronjobs
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-upload-handler.php

    r14494 r14565  
    44use WP_Error;
    55use WordPressdotorg\Plugin_Directory\CLI\Import;
     6use WordPressdotorg\Plugin_Directory\Jobs\Plugin_Updates_PCP;
    67use WordPressdotorg\Plugin_Directory\Readme\Parser;
    78use WordPressdotorg\Plugin_Directory\Plugin_Directory;
     
    656657
    657658    /**
    658      * Sends a plugin through Plugin Check.
     659     * Checks the uploaded plugin via Plugin Check.
    659660     *
    660661     * @return array The results of the plugin check.
    661662     */
    662663    public function check_plugin() {
    663         // Run the checks.
    664         if (
    665             ! defined( 'WPCLI' ) ||
    666             ! defined( 'WP_CLI_CONFIG_PATH' ) ||
    667             // The plugin must be activated in order to have plugin-check run.
    668             ! defined( 'WP_PLUGIN_CHECK_VERSION' ) ||
    669             // WordPress.org only..
    670             ! function_exists( 'notify_slack' )
    671         ) {
    672             // If we can't run plugin-check, we'll just return a pass.
    673             return [
    674                 'verdict' => true,
    675                 'results' => [],
    676                 'html'    => '',
    677             ];
    678         }
    679 
    680         // Run plugin check via CLI
    681         $start_time = microtime(1);
    682         $env_vars   = [
    683             'PATH'               => $_ENV['PATH'] ?? '/usr/local/bin:/usr/bin:/bin',
    684             'WP_CLI_CONFIG_PATH' => WP_CLI_CONFIG_PATH,
     664        // If we can't run plugin-check, we'll just return a pass.
     665        $default_return = [
     666            'verdict' => true,
     667            'results' => [],
     668            'html'    => '',
    685669        ];
    686         $command    = WPCLI . ' --url=https://wordpress.org/plugins ' .
    687                       'plugin check ' .
    688                       '--error-severity=7 --warning-severity=6 --include-low-severity-errors ' .
    689                       '--categories=plugin_repo --format=json ' .
    690                       '--slug=' . escapeshellarg( $this->plugin_slug ) . ' ' .
    691                       escapeshellarg( $this->plugin_root );
    692 
    693         $plugin_check_process = proc_open(
    694             $command,
    695             [
    696                 1 => [ 'pipe', 'w' ], // STDOUT
    697                 2 => [ 'pipe', 'w' ], // STDERR
    698             ],
    699             $pipes,
    700             null,
    701             $env_vars
    702         );
    703         if ( ! $plugin_check_process ) {
    704             // If we can't run plugin-check, we'll just return a pass.
    705             return [
    706                 'verdict' => true,
    707                 'results' => [],
    708                 'html'    => '',
    709             ];
    710         }
    711         do {
    712             usleep( 100000 ); // 0.1s
    713 
    714             $total_time = round( microtime(1) - $start_time, 1 );
    715 
    716             $proc_status = proc_get_status( $plugin_check_process );
    717             $return_code = $proc_status['exitcode'] ?? 1;
    718 
    719             if ( $total_time >= 45 && $proc_status['running'] ) {
    720                 // Terminate it.
    721                 proc_terminate( $plugin_check_process );
    722             }
    723         } while ( $proc_status['running'] && $total_time <= 60 ); // 60s max, just in case.
    724 
    725         $output = stream_get_contents( $pipes[1] );
    726         $stderr = rtrim( stream_get_contents( $pipes[2] ), "\n" );
    727 
    728         // Remove ABSPATH from the output if present.
    729         $output = str_replace( ABSPATH, '/', $output );
    730         $output = str_replace( str_replace( '/', '\/', ABSPATH ), '\/', $output ); // JSON encoded
    731         $stderr = str_replace( ABSPATH, '/', $stderr );
    732 
    733         // Close the process.
    734         fclose( $pipes[1] );
    735         fclose( $pipes[2] );
    736         proc_close( $plugin_check_process );
    737 
    738         /**
    739          * Anything that plugin-check outputs that we want to discard completely.
    740          */
    741         $is_ignored_code = static function( $code ) {
    742             $ignored_codes = [
    743             ];
    744 
    745             return (
    746                 in_array( $code, $ignored_codes, true ) ||
    747                 // All the Readme parser warnings are duplicated, we'll exclude those.
    748                 str_starts_with( $code, 'readme_parser_warnings_' )
    749             );
    750         };
    751 
    752         /*
    753          * Convert the output into an array.
    754          * Format:
    755          * FILE: example.extension
    756          * [{.....}]
    757          *
    758          * FILE: example2.extension
    759          * [{.....}]
    760          */
    761         $verdict         = true;
    762         $results         = [];
    763         $results_by_type = [];
    764         $output          = explode( "\n", $output );
    765         foreach ( array_chunk( $output, 3 ) as $file_result ) {
    766             if ( ! str_starts_with( $file_result[0], 'FILE:' ) ) {
    767                 continue;
    768             }
    769 
    770             $filename = trim( explode( ':' , $file_result[0], 2 )[1] );
    771             $json     = json_decode( $file_result[1], true );
    772 
    773             foreach ( $json as $record ) {
    774                 $record['file'] = $filename;
    775 
    776                 if ( $is_ignored_code( $record['code'] ) ) {
    777                     continue;
    778                 }
    779 
    780                 $results[] = $record;
    781 
    782                 $results_by_type[ $record['type'] ] ??= [];
    783                 $results_by_type[ $record['type'] ][] = $record;
    784 
    785                 // Record submission stats.
    786                 if ( function_exists( 'bump_stats_extra' ) && 'production' === wp_get_environment_type() ) {
    787                     bump_stats_extra( 'plugin-check-' . $record['type'], $record['code'] );
    788                 }
    789 
    790                 // Determine if it failed the checks.
    791                 if ( $verdict && 'ERROR' === $record['type'] ) {
    792                     $verdict = false;
    793                 }
    794             }
    795         }
     670
     671        if ( ! function_exists( 'notify_slack' ) ) {
     672            return $default_return;
     673        }
     674
     675        $result = Plugin_Updates_PCP::run_plugin_check( $this->plugin_slug, $this->plugin_root, '' /* should be stable tag */, 'new' );
     676        if ( false === $result ) {
     677            return $default_return;
     678        }
     679
     680        $verdict     = $result['verdict'];
     681        $results     = $result['results'];
     682        $return_code = $result['return_code'];
     683        $total_time  = $result['total_time'];
    796684
    797685        // Generage the HTML for the Plugin Check output.
     
    838726        if ( ! $verdict ) {
    839727            // Slack dm the logs.
    840             $zip_name = reset( $_FILES )['name'];
     728            $zip_name = reset( $_FILES )['name'] ?? '';
    841729            $failpass = $verdict ? ':white_check_mark: passed' : ':x: failed';
    842730            if ( $return_code > 1 ) { // TODO: Temporary, as we're always hitting this branch.
     
    879767        } elseif ( $return_code ) {
    880768            // Log plugin-check timing out.
    881             $zip_name   = reset( $_FILES )['name'];
     769            $zip_name   = reset( $_FILES )['name'] ?? '';
    882770            $output     = implode( "\n", $output );
    883771            $debug      = '';
Note: See TracChangeset for help on using the changeset viewer.