Skip to content

Commit

Permalink
Scheduled Updates: Move arbitrary actions to callbacks (#36835)
Browse files Browse the repository at this point in the history
* Scheduled Updates: Move arbitrary actions to callbacks

* Revert args changes and fix static analyzer

* Version bumps

* Fix up logs handling after rebase

* Remove unnecessary status callback
  • Loading branch information
obenland authored Apr 23, 2024
1 parent e0333f5 commit ae8815b
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 74 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Scheduled Updates: Move arbitrary actions to callbacks
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public static function clear( string $schedule_id = null ) {
*/
public static function infer_status_from_logs( $schedule_id ) {
$logs = self::get( $schedule_id );
if ( is_wp_error( $logs ) || empty( $logs ) ) {
if ( empty( $logs ) ) {
return false;
}

Expand Down Expand Up @@ -198,6 +198,41 @@ public static function infer_status_from_logs( $schedule_id ) {
);
}

/**
* Replaces the logs with the old schedule ID with new ones.
*
* @param string $old_schedule_id The old schedule ID.
* @param string $new_schedule_id The new schedule ID.
*/
public static function replace_logs_schedule_id( $old_schedule_id, $new_schedule_id ) {
if ( $old_schedule_id === $new_schedule_id ) {
return;
}

$logs = get_option( self::OPTION_NAME, array() );

if ( isset( $logs[ $old_schedule_id ] ) ) {
// Replace the logs with the old schedule ID with new ones.
$logs[ $new_schedule_id ] = $logs[ $old_schedule_id ];
unset( $logs[ $old_schedule_id ] );

update_option( self::OPTION_NAME, $logs );
}
}

/**
* Deletes the logs for a schedule ID when the current request is a DELETE request.
*
* @param string $schedule_id The ID of the schedule to delete.
* @param object $event The deleted event object.
* @param \WP_REST_Request $request The request object.
*/
public static function delete_logs_schedule_id( $schedule_id, $event, $request ) {
if ( $request->get_method() === \WP_REST_Server::DELETABLE ) {
self::clear( $schedule_id );
}
}

/**
* Splits the logs into runs based on the PLUGIN_UPDATES_START action.
*
Expand Down Expand Up @@ -225,33 +260,4 @@ private static function split_logs_into_runs( $logs ) {

return $runs;
}

/**
* Replaces the logs with the old schedule ID with new ones.
*
* @param string $old_schedule_id The old schedule ID.
* @param string $new_schedule_id The new schedule ID.
*
* @return bool True if the logs were successfully replaced, false otherwise.
*/
public static function replace_logs_schedule_id( $old_schedule_id, $new_schedule_id ) {

if ( $old_schedule_id === $new_schedule_id ) {
return false;
}

$logs = get_option( self::OPTION_NAME, array() );

if ( isset( $logs[ $old_schedule_id ] ) ) {
// Replace the logs with the old schedule ID with new ones
$logs[ $new_schedule_id ] = $logs[ $old_schedule_id ];
unset( $logs[ $old_schedule_id ] );

update_option( self::OPTION_NAME, $logs );

return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public static function init() {
add_filter( 'views_plugins', array( Scheduled_Updates_Admin::class, 'add_scheduled_updates_view' ) );
add_filter( 'plugin_auto_update_setting_html', array( Scheduled_Updates_Admin::class, 'show_scheduled_updates' ), 10, 2 );

add_action( 'jetpack_scheduled_update_created', array( __CLASS__, 'maybe_disable_autoupdates' ), 10, 3 );
add_action( 'jetpack_scheduled_update_deleted', array( __CLASS__, 'enable_autoupdates' ), 10, 2 );
add_action( 'jetpack_scheduled_update_updated', array( Scheduled_Updates_Logs::class, 'replace_logs_schedule_id' ), 10, 2 );
add_action( 'jetpack_scheduled_update_deleted', array( Scheduled_Updates_Logs::class, 'delete_logs_schedule_id' ), 10, 3 );

// Update cron sync option after options update.
$callback = array( __CLASS__, 'update_option_cron' );

Expand Down Expand Up @@ -251,6 +256,53 @@ public static function allowlist_scheduled_plugins( $update, $item ) {
return $update;
}

/**
* Maybe disable autoupdates.
*
* @param string $id The ID of the schedule.
* @param object $event The event object.
* @param \WP_REST_Request $request The request object.
*/
public static function maybe_disable_autoupdates( $id, $event, $request ) {
require_once ABSPATH . 'wp-admin/includes/update.php';

if ( wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
// Remove the plugins that are now updated on a schedule from the auto-update list.
$auto_update_plugins = get_option( 'auto_update_plugins', array() );
$auto_update_plugins = array_diff( $auto_update_plugins, $request['plugins'] );
update_option( 'auto_update_plugins', $auto_update_plugins );
}
}

/**
* Enable autoupdates.
*
* @param string $id The ID of the schedule.
* @param object $event The deleted event object.
*/
public static function enable_autoupdates( $id, $event ) {
require_once ABSPATH . 'wp-admin/includes/update.php';

if ( ! wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
return;
}

$events = wp_get_scheduled_events( static::PLUGIN_CRON_HOOK );
unset( $events[ $id ] );

// Find the plugins that are not part of any other schedule.
$plugins = $event->args;
foreach ( wp_list_pluck( $events, 'args' ) as $args ) {
$plugins = array_diff( $plugins, $args );
}

// Add the plugins that are no longer updated on a schedule to the auto-update list.
$auto_update_plugins = get_option( 'auto_update_plugins', array() );
$auto_update_plugins = array_unique( array_merge( $auto_update_plugins, $plugins ) );
usort( $auto_update_plugins, 'strnatcasecmp' );
update_option( 'auto_update_plugins', $auto_update_plugins );
}

/**
* Registers the is_managed field for the plugin REST API.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,17 @@ public function create_item( $request ) {
return $event;
}

require_once ABSPATH . 'wp-admin/includes/update.php';

if ( wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
// Remove the plugins that are now updated on a schedule from the auto-update list.
$auto_update_plugins = get_option( 'auto_update_plugins', array() );
$auto_update_plugins = array_diff( $auto_update_plugins, $plugins );
update_option( 'auto_update_plugins', $auto_update_plugins );
}

$id = Scheduled_Updates::generate_schedule_id( $plugins );

/**
* Fires when a scheduled update is created.
*
* @param string $id The ID of the schedule.
* @param object $event The event object.
* @param WP_REST_Request $request The request object.
*/
do_action( 'jetpack_scheduled_update_created', $id, $event, $request );

return rest_ensure_response( $id );
}

Expand Down Expand Up @@ -342,20 +342,21 @@ public function update_item( $request ) {
return $result;
}

$previous_schedule_status = Scheduled_Updates::get_scheduled_update_status( $request['schedule_id'] );

$clear_logs = false;
$deleted = $this->delete_item( $request, $clear_logs );
$deleted = $this->delete_item( $request );
if ( is_wp_error( $deleted ) ) {
return $deleted;
}

$item = $this->create_item( $request );

// Sets the previous status.
if ( $previous_schedule_status ) {
Scheduled_Updates_Logs::replace_logs_schedule_id( $request['schedule_id'], $item->data );
}
/**
* Fires when a scheduled update is updated.
*
* @param string $old_id The ID of the schedule to update.
* @param string $new_id The ID of the updated event.
* @param WP_REST_Request $request The request object.
*/
do_action( 'jetpack_scheduled_update_updated', $request['schedule_id'], $item->data, $request );

return $item;
}
Expand Down Expand Up @@ -472,10 +473,9 @@ public function delete_item_permissions_check( $request ) { // phpcs:ignore Vari
* Deletes an existing update schedule.
*
* @param WP_REST_Request $request Request object.
* @param bool $clear_logs Whether to clear the logs or not.
* @return WP_REST_Response|WP_Error
*/
public function delete_item( $request, $clear_logs = true ) {
public function delete_item( $request ) {
$events = wp_get_scheduled_events( Scheduled_Updates::PLUGIN_CRON_HOOK );

if ( ! isset( $events[ $request['schedule_id'] ] ) ) {
Expand All @@ -493,28 +493,14 @@ public function delete_item( $request, $clear_logs = true ) {
return new WP_Error( 'unschedule_event_error', __( 'Error during unschedule of the event.', 'jetpack-scheduled-updates' ), array( 'status' => 500 ) );
}

require_once ABSPATH . 'wp-admin/includes/update.php';

if ( wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
unset( $events[ $request['schedule_id'] ] );

// Find the plugins that are not part of any other schedule.
$plugins = $event->args;
foreach ( wp_list_pluck( $events, 'args' ) as $args ) {
$plugins = array_diff( $plugins, $args );
}

// Add the plugins that are no longer updated on a schedule to the auto-update list.
$auto_update_plugins = get_option( 'auto_update_plugins', array() );
$auto_update_plugins = array_unique( array_merge( $auto_update_plugins, $plugins ) );
usort( $auto_update_plugins, 'strnatcasecmp' );
update_option( 'auto_update_plugins', $auto_update_plugins );
}

// Delete logs
if ( $clear_logs ) {
Scheduled_Updates_Logs::clear( $request['schedule_id'] );
}
/**
* Fires when a scheduled update is deleted.
*
* @param string $id The ID of the schedule to delete.
* @param object $event The deleted event object.
* @param WP_REST_Request $request The request object.
*/
do_action( 'jetpack_scheduled_update_deleted', $request['schedule_id'], $event, $request );

return rest_ensure_response( true );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,13 +641,14 @@ public function test_update_item_with_status() {
$this->assertSame( 200, $result->get_status() );
$schedule_id = $result->get_data();

// Get the updated status
// Get the updated status.
$updated_status = Scheduled_Updates::get_scheduled_update_status( $schedule_id );

if ( $updated_status === false ) {
$this->fail( 'Scheduled_Updates::get_scheduled_update_status() returned false.' );
} else {
$this->assertIsArray( $updated_status, 'Scheduled_Updates::get_scheduled_update_status() should return an array.' );
// doing these null checks for the static analyzer
// doing these null checks for the static analyzer.
$this->assertSame( $timestamp, $updated_status['last_run_timestamp'] ?? null );
$this->assertSame( $status, $updated_status['last_run_status'] ?? null );

Expand Down Expand Up @@ -888,7 +889,7 @@ public function test_add_and_get_multiple_logs() {

$schedule_id = $this->create_test_schedule();

// Simulate 5 runs
// Simulate 5 runs.
for ( $i = 0;$i < 5;$i++ ) {
$request = new WP_REST_Request( 'PUT', '/wpcom/v2/update-schedules/' . $schedule_id . '/logs' );
$request->set_body_params(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: changed
Comment: Updated composer.lock.


0 comments on commit ae8815b

Please sign in to comment.