-
Notifications
You must be signed in to change notification settings - Fork 67
Add wp db status command for database health overview
#307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
970cf3f
0a6e265
7c06ca3
94d0fea
ba35677
66478f6
8a0d032
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,7 +50,8 @@ | |
| "db search", | ||
| "db tables", | ||
| "db size", | ||
| "db columns" | ||
| "db columns", | ||
| "db status" | ||
| ] | ||
| }, | ||
| "autoload": { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| Feature: Display database status overview | ||
|
|
||
| Scenario: Display database status for a WordPress install | ||
| Given a WP install | ||
|
|
||
| When I run `wp db status` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Database Name: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Tables: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Total Size: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Prefix: wp_ | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Engine: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Charset: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Collation: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Check Status: | ||
| """ | ||
|
|
||
| Scenario: Verify database status shows correct database name | ||
| Given a WP install | ||
|
|
||
| When I run `wp db status` | ||
| Then STDOUT should contain: | ||
| """ | ||
| wp_cli_test | ||
| """ | ||
|
|
||
| Scenario: Verify database status shows check status as OK | ||
| Given a WP install | ||
|
|
||
| When I run `wp db status` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Check Status: OK | ||
| """ | ||
swissspidy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Scenario: Run db status with MySQL defaults to check the database | ||
| Given a WP install | ||
|
|
||
| When I run `wp db status --defaults` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Database Name: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Check Status: OK | ||
| """ | ||
|
|
||
| Scenario: Run db status with --no-defaults to check the database | ||
| Given a WP install | ||
|
|
||
| When I run `wp db status --no-defaults` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Database Name: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Check Status: OK | ||
| """ | ||
|
|
||
| Scenario: Run db status with passed-in options | ||
| Given a WP install | ||
|
|
||
| When I run `wp db status --dbuser=wp_cli_test` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Database Name: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Check Status: OK | ||
| """ | ||
|
|
||
| When I run `wp db status --dbpass=password1` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Database Name: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Check Status: OK | ||
| """ | ||
|
|
||
| When I run `wp db status --dbuser=wp_cli_test --dbpass=password1` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Database Name: | ||
| """ | ||
| And STDOUT should contain: | ||
| """ | ||
| Check Status: OK | ||
| """ | ||
|
|
||
| When I try `wp db status --dbuser=no_such_user` | ||
| Then the return code should not be 0 | ||
|
|
||
| When I try `wp db status --dbpass=no_such_pass` | ||
| Then the return code should not be 0 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1247,6 +1247,152 @@ public function prefix() { | |
| WP_CLI::log( $wpdb->prefix ); | ||
| } | ||
|
|
||
| /** | ||
| * Displays a quick database status overview. | ||
| * | ||
| * Shows key database information including name, table count, size, | ||
| * prefix, engine, charset, collation, and health check status. This | ||
| * command is useful for getting a quick snapshot of database health | ||
| * without needing to run multiple separate commands. | ||
| * | ||
| * ## OPTIONS | ||
| * | ||
| * [--dbuser=<value>] | ||
| * : Username to pass to mysql. Defaults to DB_USER. | ||
| * | ||
| * [--dbpass=<value>] | ||
| * : Password to pass to mysql. Defaults to DB_PASSWORD. | ||
| * | ||
| * [--defaults] | ||
| * : Loads the environment's MySQL option files. Default behavior is to skip loading them to avoid failures due to misconfiguration. | ||
| * | ||
| * ## EXAMPLES | ||
| * | ||
| * $ wp db status | ||
| * Database Name: wp_cli_test | ||
| * Tables: 54 | ||
| * Total Size: 312 KB | ||
| * Prefix: wp_ | ||
| * Engine: InnoDB | ||
| * Charset: utf8mb4 | ||
| * Collation: utf8mb4_unicode_ci | ||
| * Check Status: OK | ||
| * | ||
| * @when before_wp_load | ||
| */ | ||
| public function status( $_, $assoc_args ) { | ||
| global $wpdb; | ||
|
|
||
| // Get database name. | ||
| $db_name = DB_NAME; | ||
|
|
||
| // Get table count. | ||
| $table_count = count( Utils\wp_get_table_names( [], [ 'scope' => 'all' ] ) ); | ||
|
|
||
| // Get total database size. | ||
| $db_size_bytes = $wpdb->get_var( | ||
| $wpdb->prepare( | ||
| 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES where table_schema = %s GROUP BY table_schema;', | ||
| DB_NAME | ||
| ) | ||
| ); | ||
|
|
||
| // Format size to human-readable. | ||
| if ( empty( $db_size_bytes ) || $db_size_bytes <= 0 ) { | ||
| $db_size = '0 B'; | ||
| } else { | ||
| $size_key = floor( log( $db_size_bytes ) / log( 1000 ) ); | ||
| $sizes = [ 'B', 'KB', 'MB', 'GB', 'TB' ]; | ||
| $size_format = isset( $sizes[ $size_key ] ) ? $sizes[ $size_key ] : $sizes[0]; | ||
| $divisor = pow( 1000, $size_key ); | ||
| $db_size = round( $db_size_bytes / $divisor, 2 ) . ' ' . $size_format; | ||
| } | ||
|
|
||
| // Get prefix. | ||
| $prefix = $wpdb->prefix; | ||
|
|
||
| // Get engine, charset, and collation from information_schema across all tables with the prefix. | ||
| $table_info = $wpdb->get_row( | ||
| $wpdb->prepare( | ||
| 'SELECT ' | ||
| . 'COUNT(DISTINCT ENGINE) AS engine_count, ' | ||
| . 'MIN(ENGINE) AS engine, ' | ||
| . 'COUNT(DISTINCT CCSA.character_set_name) AS charset_count, ' | ||
| . 'MIN(CCSA.character_set_name) AS charset, ' | ||
| . 'COUNT(DISTINCT TABLE_COLLATION) AS collation_count, ' | ||
| . 'MIN(TABLE_COLLATION) AS collation ' | ||
| . 'FROM information_schema.TABLES T ' | ||
| . 'LEFT JOIN information_schema.COLLATION_CHARACTER_SET_APPLICABILITY CCSA ' | ||
| . 'ON CCSA.collation_name = T.table_collation ' | ||
| . 'WHERE T.table_schema = %s ' | ||
| . 'AND T.table_name LIKE %s', | ||
| DB_NAME, | ||
| $wpdb->esc_like( $prefix ) . '%' | ||
| ) | ||
| ); | ||
|
|
||
| if ( $table_info ) { | ||
| $engine_count = isset( $table_info->engine_count ) ? (int) $table_info->engine_count : 0; | ||
| $charset_count = isset( $table_info->charset_count ) ? (int) $table_info->charset_count : 0; | ||
| $collation_count = isset( $table_info->collation_count ) ? (int) $table_info->collation_count : 0; | ||
|
|
||
| if ( $engine_count > 1 ) { | ||
| $engine = 'Mixed'; | ||
| } elseif ( isset( $table_info->engine ) && '' !== $table_info->engine ) { | ||
| $engine = $table_info->engine; | ||
| } else { | ||
| $engine = 'N/A'; | ||
| } | ||
|
|
||
| if ( $charset_count > 1 ) { | ||
| $charset = 'Mixed'; | ||
| } elseif ( isset( $table_info->charset ) && '' !== $table_info->charset ) { | ||
| $charset = $table_info->charset; | ||
| } else { | ||
| $charset = 'N/A'; | ||
| } | ||
|
|
||
| if ( $collation_count > 1 ) { | ||
| $collation = 'Mixed'; | ||
| } elseif ( isset( $table_info->collation ) && '' !== $table_info->collation ) { | ||
| $collation = $table_info->collation; | ||
| } else { | ||
| $collation = 'N/A'; | ||
| } | ||
| } else { | ||
| $engine = 'N/A'; | ||
| $charset = 'N/A'; | ||
| $collation = 'N/A'; | ||
| } | ||
| // Run database check silently to get status. | ||
| if ( $table_count > 0 ) { | ||
| $command = sprintf( | ||
| '/usr/bin/env %s%s %s', | ||
| Utils\get_sql_check_command(), | ||
| $this->get_defaults_flag_string( $assoc_args ), | ||
| '%s' | ||
| ); | ||
| list( $stdout, $stderr, $exit_code ) = self::run( | ||
| Utils\esc_cmd( $command, DB_NAME ), | ||
| array_merge( [ 'check' => true ], $assoc_args ), | ||
| false | ||
| ); | ||
| $check_status = ( 0 === $exit_code ) ? 'OK' : 'Error'; | ||
| } else { | ||
| // No tables to check; mark status as not applicable. | ||
| $check_status = 'N/A'; | ||
| } | ||
| // Output formatted status. | ||
| WP_CLI::log( sprintf( '%-18s %s', 'Database Name:', $db_name ) ); | ||
| WP_CLI::log( sprintf( '%-18s %d', 'Tables:', $table_count ) ); | ||
| WP_CLI::log( sprintf( '%-18s %s', 'Total Size:', $db_size ) ); | ||
| WP_CLI::log( sprintf( '%-18s %s', 'Prefix:', $prefix ) ); | ||
| WP_CLI::log( sprintf( '%-18s %s', 'Engine:', $engine ) ); | ||
| WP_CLI::log( sprintf( '%-18s %s', 'Charset:', $charset ) ); | ||
| WP_CLI::log( sprintf( '%-18s %s', 'Collation:', $collation ) ); | ||
| WP_CLI::log( sprintf( '%-18s %s', 'Check Status:', $check_status ) ); | ||
|
Comment on lines
+1386
to
+1393
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The block of $status_items = [
'Database Name' => $db_name,
'Tables' => $table_count,
'Total Size' => $db_size,
'Prefix' => $prefix,
'Engine' => $engine,
'Charset' => $charset,
'Collation' => $collation,
'Check Status' => $check_status,
];
foreach ( $status_items as $label => $value ) {
WP_CLI::log( sprintf( '%-18s %s', $label . ':', $value ) );
} |
||
| } | ||
|
|
||
| /** | ||
| * Finds a string in the database. | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Behat tests are split across multiple scenarios, each testing a small part of the command's output. This makes the tests less robust as they don't verify the output structure as a whole. Combining these into a single, more comprehensive scenario would improve test clarity and strength. Using
should matchwith regular expressions for dynamic values like table count and size will also make the assertions more precise and resilient to minor changes.