Make WordPress Core

Changeset 25841


Ignore:
Timestamp:
10/18/2013 04:29:16 PM (11 years ago)
Author:
nacin
Message:

Notify administrators of successful, failed, and pending core updates.

Blocks future background updates after critical failures, but allow retries in certain situations. More in the ticket.

fixes #10787.

Location:
trunk/src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/about.php

    r25840 r25841  
    5656                $upgrader = new WP_Automatic_Updater;
    5757                $future_minor_update = (object) array(
    58                     'current'       => $wp_version . '.1-about.php',
    59                     'version'       => $wp_version . '.1-about.php',
     58                    'current'       => $wp_version . '.1.next.minor',
     59                    'version'       => $wp_version . '.1.next.minor',
    6060                    'php_version'   => $required_php_version,
    6161                    'mysql_version' => $required_mysql_version,
  • trunk/src/wp-admin/includes/class-wp-upgrader.php

    r25837 r25841  
    14381438            return false;
    14391439
     1440        $failure_data = get_site_option( 'auto_core_update_failed' );
     1441        if ( $failure_data ) {
     1442            // If this was a critical update failure, cannot update.
     1443            if ( ! empty( $failure_data['critical'] ) )
     1444                return false;
     1445
     1446            // Don't claim we can update on update-core.php if we have a non-critical failure logged.
     1447            if ( $wp_version == $failure_data['current'] && false !== strpos( $wp_version, '.1.next.minor' ) )
     1448                return false;
     1449
     1450            // Cannot update if we're retrying the same A to B update that caused a non-critical failure.
     1451            // Some non-critical failures do allow retries, like download_failed.
     1452            // 3.7.1 => 3.7.2 resulted in files_not_writable, if we are still on 3.7.1 and still trying to update to 3.7.2.
     1453            if ( empty( $failure_data['retry'] ) && $wp_version == $failure_data['current'] && $offered_ver == $failure_data['attempted'] )
     1454                return false;
     1455        }
     1456
    14401457        // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2
    14411458        if ( $current_is_development_version ) {
     
    16271644        // And does the user / plugins want it?
    16281645        // Plugins may filter on 'auto_update_plugin', and check the 2nd param, $item, to only enable it for certain Plugins/Themes
    1629         if ( ! apply_filters( 'auto_update_' . $type, $update, $item ) )
     1646        $update = apply_filters( 'auto_update_' . $type, $update, $item );
     1647
     1648        if ( ! $update ) {
     1649
     1650            // See if we need to notify users of a core update.
     1651            if ( 'core' == $type && ! empty( $item->notify_email ) ) {
     1652                $notify      = true;
     1653                $notified    = get_site_option( 'auto_core_update_notified' );
     1654
     1655                // Don't notify if we've already notified the same email address of the same version.
     1656                if ( $notified && $notified['email'] == get_site_option( 'admin_email' ) && $notified['version'] == $item->current )
     1657                    return false;
     1658
     1659                $this->send_email( 'manual', $item );
     1660            }
     1661
    16301662            return false;
     1663        }
    16311664
    16321665        // If it's a core update, are we actually compatible with its requirements?
     
    17281761     */
    17291762    function run() {
    1730         global $wpdb;
     1763        global $wpdb, $wp_version;
    17311764
    17321765        if ( ! is_main_network() || ! is_main_site() )
     
    18311864        }
    18321865
    1833         $this->send_debug_email();
     1866        // Send debugging email to all development installs.
     1867        if ( ! empty( $this->update_results ) ) {
     1868            $development_version = false !== strpos( $wp_version, '-' );
     1869            if ( apply_filters( 'automatic_updates_send_debug_email', $development_version ) )
     1870                $this->send_debug_email();
     1871
     1872            if ( ! empty( $this->update_results['core'] ) )
     1873                $this->after_core_update( $this->update_results['core'][0] );
     1874        }
    18341875
    18351876        // Clear the lock
     
    18371878    }
    18381879
     1880    /**
     1881     * If we tried to perform a core update, check if we should send an email,
     1882     * and if we need to avoid processing future updates.
     1883     */
     1884    protected function after_core_update( $update_result ) {
     1885        global $wp_version;
     1886
     1887        $core_update = $update_result->item;
     1888        $result      = $update_result->result;
     1889
     1890        if ( ! is_wp_error( $result ) ) {
     1891            $this->send_email( 'success', $core_update );
     1892            return;
     1893        }
     1894
     1895        $error_code = $result->get_error_code();
     1896
     1897        // Any of these WP_Error codes are critical failures, as in they occurred after we started to copy core files.
     1898        // We should not try to perform a background update again until there is a successful one-click update performed by the user.
     1899        $critical = false;
     1900        if ( $error_code === 'disk_full' || false !== strpos( $error_code, '__copy_dir' ) ) {
     1901            $critical = true;
     1902        } elseif ( $error_code === 'rollback_was_required' ) {
     1903            $error_data = $result->get_error_data();
     1904            if ( is_wp_error( $error_data['rollback'] ) )
     1905                $critical = true;
     1906        } elseif ( false !== strpos( $error_code, 'do_rollback' ) ) {
     1907            $critical = true;
     1908        }
     1909
     1910        if ( $critical ) {
     1911            update_site_option( 'auto_core_update_failed', array(
     1912                'attempted'  => $core_update->current,
     1913                'current'    => $wp_version,
     1914                'error_code' => $error_code,
     1915                'error_data' => $result->get_error_data(),
     1916                'timestamp'  => time(),
     1917                'critical'   => true,
     1918            ) );
     1919            $this->send_email( 'critical', $core_update, $result );
     1920            return;
     1921        }
     1922
     1923        /*
     1924         * Any other WP_Error code (like download_failed or files_not_writable) occurs before
     1925         * we tried to copy over core files. Thus, the failures are early and graceful.
     1926         *
     1927         * We should avoid trying to perform a background update again for the same version.
     1928         * But we can try again if another version is released.
     1929         *
     1930         * For certain 'transient' failures, like download_failed, we should allow retries.
     1931         * In fact, let's schedule a special update for an hour from now. (It's possible
     1932         * the issue could actually be on WordPress.org's side.) If that one fails, then email.
     1933         */
     1934        $send = true;
     1935        $transient_failures = array( 'incompatible_archive', 'download_failed', 'insane_distro' );
     1936        if ( in_array( $error_code, $transient_failures ) && ! get_site_option( 'auto_core_update_failed' ) ) {
     1937            wp_schedule_single_event( time() + HOUR_IN_SECONDS, 'wp_maybe_auto_update' );
     1938            $send = false;
     1939        }
     1940
     1941        $n = get_site_option( 'auto_core_update_notified' );
     1942        // Don't notify if we've already notified the same email address of the same version of the same notification type.
     1943        if ( $n && 'fail' == $n['type'] && $n['email'] == get_site_option( 'admin_email' ) && $n['version'] == $core_update->current )
     1944            $send = false;
     1945
     1946        update_site_option( 'auto_core_update_failed', array(
     1947            'attempted'  => $core_update->current,
     1948            'current'    => $wp_version,
     1949            'error_code' => $error_code,
     1950            'error_data' => $result->get_error_data(),
     1951            'timestamp'  => time(),
     1952            'retry'      => in_array( $error_code, $transient_failures ),
     1953        ) );
     1954
     1955        if ( $send )
     1956            $this->send_email( 'fail', $core_update, $result );
     1957    }
     1958
    18391959    protected function send_email( $type, $core_update, $result = null ) {
     1960        update_site_option( 'auto_core_update_notified', array(
     1961            'type'      => $type,
     1962            'email'     => get_site_option( 'admin_email' ),
     1963            'version'   => $core_update->current,
     1964            'timestamp' => time(),
     1965        ) );
     1966
    18401967        if ( ! apply_filters( 'automatic_updates_send_email', true, $type, $core_update, $result ) )
    18411968            return;
     
    19182045            $body .= __( 'We have some data that describes the error your site encountered.' );
    19192046            $body .= ' ' . __( 'Your hosting company, support forum volunteers, or a friendly developer may be able to use this information to help you:' );
    1920             $body .= "\n" . sprintf( __( "Error code: %s" ), $result->get_error_code() );
    1921             $body .= "\n" . $result->get_error_message();
    1922             $body .= "\n" . implode( ', ', (array) $result->get_error_data() );
     2047            $body .= "\n\n" . sprintf( __( "Error code: %s" ), $result->get_error_code() );
     2048            if ( $result->get_error_message() )
     2049                $body .= "\n" . $result->get_error_message();
     2050            if ( $result->get_error_data() )
     2051                $body .= "\n" . implode( ', ', (array) $result->get_error_data() );
    19232052            $body .= "\n";
    19242053        }
     
    19342063
    19352064    protected function send_debug_email() {
    1936         if ( empty( $this->update_results ) )
    1937             return;
    1938 
    19392065        $update_count = 0;
    19402066        foreach ( $this->update_results as $type => $updates )
     
    19862112            $body[] = '=============';
    19872113            $body[] = '';
    1988             $body[] = 'If you think these failures might be due to a bug in WordPress 3.7, could you report it?';
     2114            $body[] = 'This debugging email is sent when you are using a development version of WordPress.';
     2115            $body[] = '';
     2116            $body[] = 'If you think these failures might be due to a bug in WordPress, could you report it?';
    19892117            $body[] = ' * Open a thread in the support forums: http://wordpress.org/support/forum/alphabeta';
    19902118            $body[] = " * Or, if you're comfortable writing a bug report: http://core.trac.wordpress.org/";
  • trunk/src/wp-admin/includes/update-core.php

    r25831 r25841  
    898898    do_action( '_core_updated_successfully', $wp_version );
    899899
     900    // Clear the option that blocks auto updates after failures, now that we've been successful.
     901    delete_site_option( 'auto_core_update_failed' );
     902
    900903    return $wp_version;
    901904}
  • trunk/src/wp-admin/update-core.php

    r25835 r25841  
    151151            $upgrader = new WP_Automatic_Updater;
    152152            $future_minor_update = (object) array(
    153                 'current'       => $wp_version . '.1-update-core.php',
    154                 'version'       => $wp_version . '.1-update-core.php',
     153                'current'       => $wp_version . '.1.next.minor',
     154                'version'       => $wp_version . '.1.next.minor',
    155155                'php_version'   => $required_php_version,
    156156                'mysql_version' => $required_mysql_version,
  • trunk/src/wp-includes/update.php

    r25835 r25841  
    132132        }
    133133        $offer = (object) array_intersect_key( $offer, array_fill_keys( array( 'response', 'download', 'locale',
    134             'packages', 'current', 'version', 'php_version', 'mysql_version', 'new_bundled', 'partial_version' ), '' ) );
     134            'packages', 'current', 'version', 'php_version', 'mysql_version', 'new_bundled', 'partial_version', 'notify_email' ), '' ) );
    135135    }
    136136
Note: See TracChangeset for help on using the changeset viewer.