Skip to content

Commit

Permalink
WPCOMSH: plugin-dance improvements (#38423)
Browse files Browse the repository at this point in the history
* Improve plugin-dance

* Add changelogger

* Formatting changes.

* Changes.

* Changes.

* Allow for interactive input on reactivation.

* Fix Phan error by returning.
  • Loading branch information
TimBroddin authored Jul 23, 2024
1 parent 18ef499 commit eb62c5f
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Improve plugin-dance command.
178 changes: 145 additions & 33 deletions projects/plugins/wpcomsh/class-wpcomsh-cli-commands.php
Original file line number Diff line number Diff line change
Expand Up @@ -963,12 +963,48 @@ public function fatal_error_emails_disable( $args, $assoc_args ) { // phpcs:igno
}
}

/**
* Check if the site is healthy after activating a plugin.
* This is a helper function for the plugin-dance command.
*
* @return bool
*/
private function do_plugin_dance_health_check() {
$result = WP_CLI::runcommand(
'--skip-themes= --skip-plugins= wpcomsh plugin-dance-health-check', // pass empty values to skip-themes and skip-plugins.
array(
'return' => true,
'launch' => true, // must run in a new process to avoid false positives.
'exit_error' => false,
)
);

return (bool) strpos( $result, 'Healthy' );
}

/**
* Tries disabling all plugins & enabling them one by one to find the plugin causing the issue.
* Outputs a list of plugins that are disabled.
*
* ## OPTIONS
*
* [--strategy=<strategy>]
* : The strategy to use to find the breaking plugin. Defaults to 'one-by-one'.
* ---
* default: one-by-one
* options:
* - one-by-one
* - disable-all
*
* @subcommand plugin-dance
*/
public function plugin_dance( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
public function plugin_dance( $args, $assoc_args ) {
$healthy = $this->do_plugin_dance_health_check();
if ( $healthy ) {
WP_CLI::success( '✔ Site health check passed before doing anything.' );
return;
}

$plugins = WP_CLI::runcommand(
'--skip-plugins --skip-themes plugin list --status=active --format=json',
array(
Expand All @@ -979,52 +1015,130 @@ public function plugin_dance( $args, $assoc_args ) { // phpcs:ignore VariableAna

$plugins = json_decode( $plugins, true );

// deactivate all active plugins.
WP_CLI::runcommand(
'--skip-plugins --skip-themes wpcomsh deactivate-user-plugins',
array(
'launch' => false,
)
// Filter out plugins we won't be touching. These won't be deactivated by deactivate-user-plugins.
$plugins_to_reactivate = array_filter(
$plugins,
function ( $plugin ) {
$plugin_name = $plugin['name'];
if ( in_array( $plugin_name, WPCOMSH_CLI_DONT_DEACTIVATE_PLUGINS, true ) || in_array( $plugin_name, WPCOMSH_CLI_ECOMMERCE_PLAN_PLUGINS, true ) ) {
WP_CLI::log( sprintf( 'ℹ️ Skipping %s.', $plugin_name ) );
return false;
}

return true;
}
);

$breaking_plugins = array();

// loop through each active plugin and activate one by one.
foreach ( $plugins as $plugin ) {
if ( 'one-by-one' === $assoc_args['strategy'] ) {
while ( ! $healthy ) {
$plugin_to_deactivate = array_pop( $plugins_to_reactivate );
if ( empty( $plugin_to_deactivate ) ) {
WP_CLI::error( '❌ Site health check failed after testing all plugins one by one.' );
return;
}

WP_CLI::runcommand(
sprintf( '--skip-themes plugin deactivate %s', $plugin_to_deactivate['name'] ),
array(
'launch' => false,
'return' => true,
)
);

$healthy = $this->do_plugin_dance_health_check();

if ( ! $healthy ) {
WP_CLI::log( sprintf( 'ℹ️ Site health check still failed after deactivating: %s. Reactivating.', $plugin_to_deactivate['name'] ) );
$result = WP_CLI::runcommand(
sprintf( '--skip-themes plugin activate %s', $plugin_to_deactivate['name'] ),
array(
'launch' => true, // needed for exit_error => false.
'return' => true,
'exit_error' => false,
)
);

if ( empty( $result ) ) {
WP_CLI::log( sprintf( '❌ Plugin did not like being activated: %s (probably broken).', $plugin_to_deactivate['name'] ) );
$breaking_plugins[] = array(
'name' => $plugin_to_deactivate['name'],
'version' => $plugin_to_deactivate['version'],
);
}
} else {
WP_CLI::log( sprintf( '✔ Site health check passed after deactivating: %s.', $plugin_to_deactivate['name'] ) );
$breaking_plugins[] = array(
'name' => $plugin_to_deactivate['name'],
'version' => $plugin_to_deactivate['version'],
);
}
}
} elseif ( 'disable-all' === $assoc_args['strategy'] ) {
WP_CLI::log( 'ℹ️ Deactivating all user plugins.' );

// deactivate all active plugins.
WP_CLI::runcommand(
'--skip-themes plugin activate ' . $plugin['name'],
'--skip-plugins --skip-themes wpcomsh deactivate-user-plugins',
array(
'launch' => false,
'return' => true,
)
);

$result = WP_CLI::runcommand(
'--skip-themes= --skip-plugins= wpcomsh plugin-dance-health-check', // pass empty values to skip-themes and skip-plugins.
array(
'return' => true,
'launch' => true, // must run in a new process to avoid false positives.
'exit_error' => false,
)
);
if ( ! $this->do_plugin_dance_health_check() ) {
WP_CLI::log( '❌ Site health check failed after deactivating all plugins. Something non-plugin related is causing the issue. Trying to reactivate all plugins.' );

if ( ! strpos( $result, 'Healthy' ) ) {
// deactivate the breaking plugin
WP_CLI::runcommand(
'--skip-themes plugin deactivate ' . $plugin['name'],
'--skip-themes --skip-plugins wpcomsh reactivate-user-plugins',
array()
);
return;
}

WP_CLI::log( sprintf( 'ℹ️ %d plugins will be reactivated one by one to find the breaking plugin.', count( $plugins_to_reactivate ) ) );

// loop through each active plugin and activate one by one.
foreach ( $plugins_to_reactivate as $plugin ) {
$result = WP_CLI::runcommand(
sprintf( '--skip-themes plugin activate %s', $plugin['name'] ),
array(
'launch' => false,
'return' => true,
'launch' => true, // needed for exit_error => false.
'return' => true,
'exit_error' => false,
)
);
WP_CLI::log( '❌ Plugin activated, site health check failed and deactivated: ' . $plugin['name'] );
if ( empty( $result ) ) {
WP_CLI::log( sprintf( '❌ Plugin did not like being activated: %s (probably broken).', $plugin['name'] ) );
$breaking_plugins[] = array(
'name' => $plugin['name'],
'version' => $plugin['version'],
);
continue;
}

$breaking_plugins[] = array(
'name' => $plugin['name'],
'version' => $plugin['version'],
);
} else {
WP_CLI::log( '✔ Plugin activated and site health check passed: ' . $plugin['name'] );
if ( ! $this->do_plugin_dance_health_check() ) {
// deactivate the breaking plugin
WP_CLI::runcommand(
sprintf( '--skip-themes plugin deactivate %s', $plugin['name'] ),
array(
'launch' => false,
'return' => true,
)
);
WP_CLI::log( sprintf( '❌ Plugin activated, site health check failed and deactivated: %s.', $plugin['name'] ) );

$breaking_plugins[] = array(
'name' => $plugin['name'],
'version' => $plugin['version'],
);
} else {
WP_CLI::log( sprintf( '✔ Plugin activated and site health check passed: %s.', $plugin['name'] ) );
}
}

if ( empty( $breaking_plugins ) ) {
WP_CLI::success( 'All plugins passed the site health check.' );
}
}

Expand All @@ -1034,8 +1148,6 @@ public function plugin_dance( $args, $assoc_args ) { // phpcs:ignore VariableAna
array( 'name', 'version' )
);
$formatter->display_items( $breaking_plugins );
} else {
WP_CLI::success( 'All plugins passed the site health check.' );
}
}

Expand Down

0 comments on commit eb62c5f

Please sign in to comment.