diff --git a/features/plugin-update.feature b/features/plugin-update.feature index 1cf5e248..7f7e1e5e 100644 --- a/features/plugin-update.feature +++ b/features/plugin-update.feature @@ -268,6 +268,94 @@ Feature: Update WordPress plugins Success: Updated 1 of 1 plugins (1 skipped). """ + # Tests for --auto-update-indicated feature + # Note: These tests verify the flag handling and error cases. + # The actual update behavior when autoupdate is true from the server + # cannot be easily tested as it requires mocking WordPress.org API responses. + # The update functionality itself is handled by the existing update_many method. + + @require-wp-5.2 + Scenario: Show auto_update_indicated field in plugin list + Given a WP install + + When I run `wp plugin install wordpress-importer --version=0.5 --force` + Then STDOUT should not be empty + + When I run `wp plugin list --fields=name,version,update,auto_update_indicated` + Then STDOUT should be a table containing rows: + | name | version | update | auto_update_indicated | + | wordpress-importer | 0.5 | available | no | + + @require-wp-5.2 + Scenario: Using --auto-update-indicated flag when no plugins have auto-update indicated + Given a WP install + + When I run `wp plugin install wordpress-importer --version=0.5 --force` + Then STDOUT should not be empty + + When I run `wp plugin update --auto-update-indicated` + Then STDOUT should be: + """ + Success: No plugins with server-indicated automatic updates available. + """ + + @require-wp-5.2 + Scenario: Error when using --version with --auto-update-indicated + Given a WP install + + When I try `wp plugin update --auto-update-indicated --version=1.0.0` + Then STDERR should be: + """ + Error: Cannot use --version with --auto-update-indicated. The version is determined by the server. + """ + And the return code should be 1 + + @require-wp-5.2 + Scenario: Error when using --minor with --auto-update-indicated + Given a WP install + + When I try `wp plugin update --auto-update-indicated --minor` + Then STDERR should be: + """ + Error: Cannot use --minor or --patch with --auto-update-indicated. The version is determined by the server. + """ + And the return code should be 1 + + @require-wp-5.2 + Scenario: Error when using --patch with --auto-update-indicated + Given a WP install + + When I try `wp plugin update --auto-update-indicated --patch` + Then STDERR should be: + """ + Error: Cannot use --minor or --patch with --auto-update-indicated. The version is determined by the server. + """ + And the return code should be 1 + + @require-wp-5.2 + Scenario: Error when specifying plugin names with --auto-update-indicated + Given a WP install + + When I try `wp plugin update akismet --auto-update-indicated` + Then STDERR should be: + """ + Error: Cannot specify plugin names with --auto-update-indicated. This flag updates all plugins with server-indicated automatic updates. + """ + And the return code should be 1 + + @require-wp-5.2 + Scenario: Preview updates with --auto-update-indicated and --dry-run + Given a WP install + + When I run `wp plugin install wordpress-importer --version=0.5 --force` + Then STDOUT should not be empty + + When I run `wp plugin update --auto-update-indicated --dry-run` + Then STDOUT should be: + """ + Success: No plugins with server-indicated automatic updates available. + """ + @require-wp-5.2 Scenario: Updating all plugins should show the name of each plugin as it is updated Given a WP install diff --git a/features/theme-update.feature b/features/theme-update.feature index adc546b0..a71fdb1a 100644 --- a/features/theme-update.feature +++ b/features/theme-update.feature @@ -155,6 +155,87 @@ Feature: Update WordPress themes 1.1.1 """ + # Tests for --auto-update-indicated feature + # Note: These tests verify the flag handling and error cases. + # The actual update behavior when autoupdate is true from the server + # cannot be easily tested as it requires mocking WordPress.org API responses. + # The update functionality itself is handled by the existing update_many method. + + Scenario: Show auto_update_indicated field in theme list + Given a WP install + + When I run `wp theme install twentytwelve --version=3.0 --force` + Then STDOUT should not be empty + + When I run `wp theme list --fields=name,version,update,auto_update_indicated` + Then STDOUT should be a table containing rows: + | name | version | update | auto_update_indicated | + | twentytwelve | 3.0 | available | no | + + Scenario: Using --auto-update-indicated flag when no themes have auto-update indicated + Given a WP install + + When I run `wp theme install twentytwelve --version=3.0 --force` + Then STDOUT should not be empty + + When I run `wp theme update --auto-update-indicated` + Then STDOUT should be: + """ + Success: No themes with server-indicated automatic updates available. + """ + + Scenario: Error when using --version with --auto-update-indicated + Given a WP install + + When I try `wp theme update --auto-update-indicated --version=1.0.0` + Then STDERR should be: + """ + Error: Cannot use --version with --auto-update-indicated. The version is determined by the server. + """ + And the return code should be 1 + + Scenario: Error when using --minor with --auto-update-indicated + Given a WP install + + When I try `wp theme update --auto-update-indicated --minor` + Then STDERR should be: + """ + Error: Cannot use --minor or --patch with --auto-update-indicated. The version is determined by the server. + """ + And the return code should be 1 + + Scenario: Error when using --patch with --auto-update-indicated + Given a WP install + + When I try `wp theme update --auto-update-indicated --patch` + Then STDERR should be: + """ + Error: Cannot use --minor or --patch with --auto-update-indicated. The version is determined by the server. + """ + And the return code should be 1 + + Scenario: Error when specifying theme names with --auto-update-indicated + Given a WP install + + When I try `wp theme update twentytwelve --auto-update-indicated` + Then STDERR should be: + """ + Error: Cannot specify theme names with --auto-update-indicated. This flag updates all themes with server-indicated automatic updates. + """ + And the return code should be 1 + + Scenario: Preview updates with --auto-update-indicated and --dry-run + Given a WP install + + When I run `wp theme install twentytwelve --version=3.0 --force` + Then STDOUT should not be empty + + When I run `wp theme update --auto-update-indicated --dry-run` + Then STDOUT should be: + """ + Success: No themes with server-indicated automatic updates available. + """ + @require-wp-4.5 Scenario: Updating all themes should show the name of each theme as it is updated Given a WP install diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index ae04e702..7930bfdd 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -726,6 +726,9 @@ protected function install_from_repo( $slug, $assoc_args ) { * [--insecure] * : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack. * + * [--auto-update-indicated] + * : Only update plugins where the server response indicates an automatic update. Updates to the version indicated by the server, not necessarily the latest version. Cannot be used with `--version`, `--minor`, or `--patch`. + * * ## EXAMPLES * * $ wp plugin update bbpress --version=dev @@ -777,6 +780,11 @@ protected function install_from_repo( $slug, $assoc_args ) { public function update( $args, $assoc_args ) { $all = Utils\get_flag_value( $assoc_args, 'all', false ); + // Handle --auto-update-indicated flag if present. + if ( $this->handle_auto_update_indicated( $args, $assoc_args ) ) { + return; + } + $args = $this->check_optional_args_and_all( $args, $all ); if ( ! $args ) { return; @@ -825,8 +833,9 @@ protected function get_item_list() { $duplicate_names[ $name ] = array(); } - $requires = isset( $update_info ) && isset( $update_info['requires'] ) ? $update_info['requires'] : null; - $requires_php = isset( $update_info ) && isset( $update_info['requires_php'] ) ? $update_info['requires_php'] : null; + $requires = isset( $update_info ) && isset( $update_info['requires'] ) ? $update_info['requires'] : null; + $requires_php = isset( $update_info ) && isset( $update_info['requires_php'] ) ? $update_info['requires_php'] : null; + $auto_update_indicated = isset( $update_info ) && isset( $update_info['autoupdate'] ) ? (bool) $update_info['autoupdate'] : false; // If an update has requires_php set, check to see if the local version of PHP meets that requirement // The plugins update API already filters out plugins that don't meet WordPress requirements, but does not @@ -868,6 +877,7 @@ protected function get_item_list() { 'description' => wordwrap( $details['Description'] ), 'file' => $file, 'auto_update' => in_array( $file, $auto_updates, true ), + 'auto_update_indicated' => $auto_update_indicated, 'author' => $details['Author'], 'tested_up_to' => '', 'requires' => $requires, @@ -1794,6 +1804,7 @@ public function delete( $args, $assoc_args ) { * * requires_php * * wporg_status * * wporg_last_updated + * * auto_update_indicated * * ## EXAMPLES * diff --git a/src/Theme_Command.php b/src/Theme_Command.php index e18b17e8..f276ec41 100644 --- a/src/Theme_Command.php +++ b/src/Theme_Command.php @@ -691,6 +691,9 @@ public function get( $args, $assoc_args ) { * [--insecure] * : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack. * + * [--auto-update-indicated] + * : Only update themes where the server response indicates an automatic update. Updates to the version indicated by the server, not necessarily the latest version. Cannot be used with `--version`, `--minor`, or `--patch`. + * * ## EXAMPLES * * # Update multiple themes @@ -741,6 +744,11 @@ public function get( $args, $assoc_args ) { public function update( $args, $assoc_args ) { $all = Utils\get_flag_value( $assoc_args, 'all', false ); + // Handle --auto-update-indicated flag if present. + if ( $this->handle_auto_update_indicated( $args, $assoc_args ) ) { + return; + } + $args = $this->check_optional_args_and_all( $args, $all ); if ( ! $args ) { return; @@ -945,6 +953,7 @@ public function delete( $args, $assoc_args ) { * * update_id * * title * * description + * * auto_update_indicated * * ## EXAMPLES * diff --git a/src/WP_CLI/CommandWithUpgrade.php b/src/WP_CLI/CommandWithUpgrade.php index fe1126ca..d1623c97 100755 --- a/src/WP_CLI/CommandWithUpgrade.php +++ b/src/WP_CLI/CommandWithUpgrade.php @@ -562,6 +562,62 @@ protected function get_upgrader( $assoc_args ) { return Utils\get_upgrader( $upgrader_class, $insecure, new ExtensionUpgraderSkin() ); } + /** + * Handles the --auto-update-indicated flag logic for both plugins and themes. + * + * This method validates flag combinations, filters items by auto_update_indicated, + * and processes updates if any items are found. + * + * @param array $args Positional arguments (item names). + * @param array $assoc_args Associative arguments (flags). + * @return bool Returns true if auto-update-indicated was handled, false otherwise. + */ + protected function handle_auto_update_indicated( $args, $assoc_args ) { + $auto_update_indicated = Utils\get_flag_value( $assoc_args, 'auto-update-indicated', false ); + + if ( ! $auto_update_indicated ) { + return false; + } + + // Don't allow --version to be set with --auto-update-indicated, as the version comes from the server. + if ( isset( $assoc_args['version'] ) ) { + WP_CLI::error( 'Cannot use --version with --auto-update-indicated. The version is determined by the server.' ); + } + + // Don't allow --minor or --patch to be set with --auto-update-indicated, as the version comes from the server. + if ( isset( $assoc_args['minor'] ) || isset( $assoc_args['patch'] ) ) { + WP_CLI::error( 'Cannot use --minor or --patch with --auto-update-indicated. The version is determined by the server.' ); + } + + // Don't allow item names to be specified with --auto-update-indicated. + if ( ! empty( $args ) ) { + WP_CLI::error( "Cannot specify {$this->item_type} names with --auto-update-indicated. This flag updates all {$this->item_type}s with server-indicated automatic updates." ); + } + + // Get all items with their update info. + $items = $this->get_item_list(); + + // Filter to only include items where auto_update_indicated is true. + $auto_update_items = array_filter( + $items, + function ( $item ) { + return ! empty( $item['auto_update_indicated'] ); + } + ); + + // Get the item names to update. + $args = array_values( wp_list_pluck( $auto_update_items, 'name' ) ); + + if ( empty( $args ) ) { + WP_CLI::success( "No {$this->item_type}s with server-indicated automatic updates available." ); + return true; + } + + // Process the updates. + $this->update_many( $args, $assoc_args ); + return true; + } + protected function update_many( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); @@ -812,6 +868,12 @@ function ( $value ) { } elseif ( false === $value ) { $value = 'off'; } + } elseif ( 'auto_update_indicated' === $field ) { + if ( true === $value ) { + $value = 'yes'; + } elseif ( false === $value ) { + $value = 'no'; + } } } diff --git a/src/WP_CLI/ParseThemeNameInput.php b/src/WP_CLI/ParseThemeNameInput.php index 2c177f2f..b0bc1ae6 100644 --- a/src/WP_CLI/ParseThemeNameInput.php +++ b/src/WP_CLI/ParseThemeNameInput.php @@ -90,8 +90,9 @@ private function get_all_themes() { } foreach ( wp_get_themes( [ 'errors' => null ] ) as $key => $theme ) { - $stylesheet = $theme->get_stylesheet(); - $update_info = ( isset( $all_update_info->response[ $stylesheet ] ) && null !== $all_update_info->response[ $theme->get_stylesheet() ] ) ? (array) $all_update_info->response[ $theme->get_stylesheet() ] : null; + $stylesheet = $theme->get_stylesheet(); + $update_info = ( isset( $all_update_info->response[ $stylesheet ] ) && null !== $all_update_info->response[ $theme->get_stylesheet() ] ) ? (array) $all_update_info->response[ $theme->get_stylesheet() ] : null; + $auto_update_indicated = isset( $update_info ) && isset( $update_info['autoupdate'] ) ? (bool) $update_info['autoupdate'] : false; // Unlike plugin update responses, the wordpress.org API does not seem to check and filter themes that don't meet // WordPress version requirements into a separate no_updates array @@ -149,6 +150,7 @@ private function get_all_themes() { 'description' => wordwrap( $theme->get( 'Description' ) ), 'author' => $theme->get( 'Author' ), 'auto_update' => in_array( $stylesheet, $auto_updates, true ), + 'auto_update_indicated' => $auto_update_indicated, 'requires' => $requires, 'requires_php' => $requires_php, 'update_unavailable_reason' => isset( $update_unavailable_reason ) ? $update_unavailable_reason : '',