Changeset 14930
- Timestamp:
- 06/03/2026 05:26:25 AM (4 months ago)
- Location:
- sites/trunk
- Files:
-
- 5 edited
-
trac.wordpress.org/conf/workflow-themes.ini (modified) (1 diff)
-
wordpress.org/public_html/wp-content/plugins/theme-directory/admin-edit.php (modified) (1 diff)
-
wordpress.org/public_html/wp-content/plugins/theme-directory/class-wporg-themes-upload.php (modified) (5 diffs)
-
wordpress.org/public_html/wp-content/plugins/theme-directory/jobs/class-trac-sync.php (modified) (3 diffs)
-
wordpress.org/public_html/wp-content/plugins/theme-directory/theme-directory.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/trac.wordpress.org/conf/workflow-themes.ini
r10636 r14930 77 77 approve_and_live.default = -40 78 78 79 # this is for automated ticket closing by themetracbot 80 new_no_review = new -> closed 79 # Automated approval of a theme update by themetracbot. Lands the ticket in the 80 # `approved` status (rather than closing it live) so the release-cooldown cron can 81 # promote it to live once the cooldown has elapsed. 82 new_no_review_delay = new -> approved 83 new_no_review_delay.name = approve and delay 84 new_no_review_delay.operations = set_owner_to_self 85 new_no_review_delay.permissions = TICKET_CREATE 86 new_no_review_delay.default = -41 87 88 # Automated marking-live by themetracbot, either straight from review or once the 89 # release cooldown on an `approved` ticket has elapsed (driven by the release-to-live cron). 90 new_no_review = new,approved -> closed 81 91 new_no_review.name = approve and mark 82 92 new_no_review.operations = set_resolution, set_owner_to_self -
sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/admin-edit.php
r14464 r14930 582 582 <select name="wporg_themes_status[<?php echo base64_encode( $version ); // base64 because version numbers don't work so well as parts of keys ?>]"> 583 583 <option value="new" <?php selected( $status, 'new' ); ?>><?php esc_html_e( 'New', 'wporg-themes' ); ?></option> 584 <?php if ( 'approved' === $status ) : ?> 585 <?php // `approved` is a transient Trac-driven pre-release state; only shown so the current value displays correctly. ?> 586 <option value="approved" selected><?php esc_html_e( 'Approved (pending release)', 'wporg-themes' ); ?></option> 587 <?php endif; ?> 584 588 <option value="live" <?php selected( $status, 'live' ); ?>><?php esc_html_e( 'Live', 'wporg-themes' ); ?></option> 585 589 <option value="old" <?php selected( $status, 'old' ); ?>><?php esc_html_e( 'Old', 'wporg-themes' ); ?></option> -
sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/class-wporg-themes-upload.php
r14771 r14930 1159 1159 if ( ! empty( $this->theme_post->_status ) ) { 1160 1160 1161 // Is this an update to an existing, approved theme? 1162 if ( 'live' === $this->theme_post->_status[ $this->theme_post->max_version ] ) { 1161 // Is this an update to an existing, approved theme? An 'approved' status 1162 // (live version still in release cooldown) counts as approved for ticket 1163 // priority — the previous live version is still being served. 1164 if ( in_array( $this->theme_post->_status[ $this->theme_post->max_version ], [ 'live', 'approved' ], true ) ) { 1163 1165 $this->trac_ticket->priority = 'theme update'; 1164 1166 … … 1297 1299 $trac_ticket_reporter = wp_get_current_user()->user_login ?? $this->author->user_login; 1298 1300 1299 // If there's a previous version and the most current version's status is `new`, we update. 1300 if ( 1301 ! empty( $this->theme_post->max_version ) && 1302 'new' == $this->theme_post->_status[ $this->theme_post->max_version ] 1303 ) { 1301 $prev_status = $this->theme_post->_status[ $this->theme_post->max_version ?? '' ] ?? ''; 1302 1303 /* 1304 * If the previous version is still on an open ticket — either awaiting review 1305 * (`new`) or approved and waiting out the release delay (`approved`) — update that 1306 * same ticket rather than opening a new one. Re-uploading resets the ticket's 1307 * changetime, so an approved update's release delay restarts from this upload and 1308 * the superseded version is simply demoted to `old`. 1309 */ 1310 if ( in_array( $prev_status, [ 'new', 'approved' ], true ) ) { 1304 1311 $ticket_id = (int) $this->theme_post->_ticket_id[ $this->theme_post->max_version ]; 1305 1312 $ticket = $this->trac->ticket_get( $ticket_id ); … … 1309 1316 $result = $this->trac->ticket_update( $ticket_id, $this->trac_ticket->description, array( 'summary' => $this->trac_ticket->summary, 'keywords' => implode( ' ', $this->trac_ticket->keywords ) ), true /* Trigger email notifications */ ); 1310 1317 $ticket_id = $result ? $ticket_id : false; 1318 1319 // Keep an approved update in the `approved` window; the release-to-live 1320 // cron promotes it once the delay (measured from this upload) elapses. 1321 if ( 'approved' === $prev_status ) { 1322 $this->version_status = 'approved'; 1323 } 1311 1324 } else { 1312 1325 $ticket_id = $this->trac->ticket_create( $this->trac_ticket->summary, $this->trac_ticket->description, array( … … 1331 1344 ) ); 1332 1345 1333 // Themes team auto-approves theme-updates , so mark the theme as live immediately.1334 // Note that this only applies to newticket creation, so it won't happen on themes with existing outstanding tickets.1346 // Themes team auto-approves theme-updates. Note that this only applies to new 1347 // ticket creation, so it won't happen on themes with existing outstanding tickets. 1335 1348 if ( $this->trac_ticket->priority == 'theme update' ) { 1336 $this->trac->ticket_update( $ticket_id, 'Theme Update for existing Live theme - automatically approved', array( 'action' => 'new_no_review' ), false ); 1337 1338 $this->trac_ticket->resolution = 'live'; 1339 $this->version_status = 'live'; 1349 $release_delay = wporg_themes_get_release_cooldown_delay( $this->theme_slug ); 1350 if ( $release_delay ) { 1351 // Land the update in the `approved` status; the release-to-live cron 1352 // promotes it to live once the cooldown elapses. The previous live 1353 // version continues to be served in the meantime. 1354 $delay_hours = (int) round( $release_delay / HOUR_IN_SECONDS ); 1355 $this->trac->ticket_update( $ticket_id, sprintf( 'Theme Update for existing Live theme - automatically approved, will be marked live in %dhrs.', $delay_hours ), array( 'action' => 'new_no_review_delay' ), false ); 1356 1357 $this->version_status = 'approved'; 1358 } else { 1359 // Cooldown disabled: mark the theme live immediately. 1360 $this->trac->ticket_update( $ticket_id, 'Theme Update for existing Live theme - automatically approved', array( 'action' => 'new_no_review' ), false ); 1361 1362 $this->trac_ticket->resolution = 'live'; 1363 $this->version_status = 'live'; 1364 } 1340 1365 } 1341 1366 … … 1562 1587 * - The theme is to be made live immediately. 1563 1588 * `wporg_themes_approve_version()` will send a "Congratulations! It's live!" shortly. 1589 * - The theme was auto-approved into the release cooldown. It's not awaiting 1590 * review, so the "new version uploaded" feedback email doesn't apply; the 1591 * "now live" email follows once the cooldown elapses. 1564 1592 * - No Trac ticket was created, so there's nothing to reference about where feedback is. 1565 1593 */ 1566 1594 if ( 1567 'live' === $this->version_status||1595 in_array( $this->version_status, [ 'live', 'approved' ], true ) || 1568 1596 ! $this->trac_ticket->id 1569 1597 ) { -
sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/jobs/class-trac-sync.php
r11175 r14930 21 21 */ 22 22 protected static $stati = [ 23 'new' => [23 'new' => [ 24 24 'status' => 'reopened', 25 25 ], 26 'live' => [ 26 'approved' => [ 27 // `approved` is an open Trac status (not a resolution): a reviewer has 28 // approved the ticket, or themetracbot auto-approved an update, and it's 29 // waiting out the release cooldown before being marked live. 30 'status' => 'approved', 31 ], 32 'live' => [ 27 33 'status' => 'closed', 28 34 'resolution' => 'live', 29 35 ], 30 'old' => [36 'old' => [ 31 37 'status' => 'closed', 32 38 'resolution' => 'not-approved', … … 51 57 $last_request = get_option( 'wporg-themes-last-trac-sync', strtotime( '-2 days' ) ); 52 58 update_option( 'wporg-themes-last-trac-sync', time() ); 59 60 // Migrate approved theme updates whose release delay has elapsed to live on Trac, 61 // so the sync below imports them as it would any other newly-live ticket. 62 self::release_to_live( $trac ); 53 63 54 64 foreach ( self::$stati as $new_status => $args ) { … … 77 87 } 78 88 89 $current_status = wporg_themes_get_version_status( $theme_id, $version ); 90 79 91 /* 80 * Bail if the the theme has the wrong status. 81 * 82 * For approved and rejected themes, we bail if the current status is not 83 * 'new' That can happen when there are additional ticket updates (like 84 * comments) after the ticket was closed. 85 * 86 * For reopened tickets we bail if the version is already marked as 'new'. 87 * This should only be the case if the ticket was closed and reopened before 88 * this script was able to sync the closed status. 92 * Skip if the version is already in the target status. This is the common 93 * case for additional ticket activity (e.g. comments) after a ticket has 94 * reached a resolved state. 89 95 */ 90 $current_status = wporg_themes_get_version_status( $theme_id, $version ); 91 if ( ( 'new' !== $new_status && 'new' !== $current_status ) || ( 'new' === $new_status && 'new' === $current_status ) ) { 96 if ( $current_status === $new_status ) { 92 97 continue; 93 98 } 94 99 95 // We don't need to set an already approved live version to live again. 96 if ( 'live' === $current_status && 'live' === $new_status ) { 97 continue; 100 /* 101 * Only act on transitions that make sense in the directory's lifecycle 102 * (new -> approved -> live, with branches to old or back to new). This 103 * guards against ticket activity that arrives out of order or after the 104 * version has already moved on. 105 */ 106 switch ( $new_status ) { 107 case 'new': 108 // Reopened: always sync back to 'new' from any resolved state. 109 break; 110 111 case 'approved': 112 // Newly approved (reviewer or auto-approved update): only valid 113 // coming from 'new'. 114 if ( 'new' !== $current_status ) { 115 continue 2; 116 } 117 break; 118 119 case 'live': 120 // Going live: straight from review (approve_and_live / new_no_review, 121 // current 'new') or out of the release cooldown (current 'approved', 122 // via the release-to-live cron or a reviewer force-release on Trac). 123 if ( ! in_array( $current_status, [ 'new', 'approved' ], true ) ) { 124 continue 2; 125 } 126 break; 127 128 case 'old': 129 // Rejected during review: only valid coming from 'new'. 130 if ( 'new' !== $current_status ) { 131 continue 2; 132 } 133 break; 98 134 } 99 135 100 136 wporg_themes_update_version_status( $theme_id, $version, $new_status ); 101 137 } 138 } 139 } 140 141 /** 142 * Migrates auto-approved theme updates out of the release delay, on Trac. 143 * 144 * Finds `theme update` tickets that have been in the `approved` status for at least 145 * the theme's release cooldown delay (wporg_themes_get_release_cooldown_delay()) and 146 * closes them as resolution=live. That's the only change made here — cron_trigger()'s 147 * normal sync, which runs straight after, imports the now-live ticket into WordPress 148 * like any other. 149 * 150 * Scoped to the `theme update` priority on purpose: first-time theme submissions also 151 * pass through the `approved` status, but a trusted reviewer marks those live by hand, 152 * so they should not be promoted on a timer. 153 * 154 * @param \Trac $trac An authenticated Trac client. 155 */ 156 public static function release_to_live( $trac ) { 157 /* 158 * Auto-approved theme updates currently in the `approved` status. We check each 159 * ticket's changetime in PHP rather than filtering server-side, so a quirk in 160 * Trac's date-range query syntax can't silently strand themes in the delay. 161 */ 162 $tickets = (array) $trac->ticket_query( add_query_arg( [ 163 'status' => 'approved', 164 'priority' => 'theme update', 165 'order' => 'changetime', 166 ] ) ); 167 168 foreach ( $tickets as $ticket_id ) { 169 $ticket = $trac->ticket_get( $ticket_id ); 170 171 // Skip if the ticket was force-released or reopened since the query. 172 if ( ! $ticket || 'approved' !== ( $ticket['status'] ?? '' ) ) { 173 continue; 174 } 175 176 // Resolve the theme slug so the release delay can be filtered per-theme. 177 $theme_slug = get_post_field( 'post_name', self::get_theme_id( $ticket_id ) ); 178 $cutoff = time() - wporg_themes_get_release_cooldown_delay( $theme_slug ); 179 180 // Only once the release delay, measured from the ticket's changetime, has elapsed. 181 $changed = $ticket[2] instanceof \IXR_Date ? $ticket[2]->getTimestamp() : strtotime( (string) $ticket[2] ); 182 if ( ! $changed || $changed > $cutoff ) { 183 continue; 184 } 185 186 // Close as live. Pass the concurrency token we just read to avoid a second 187 // ticket.get; cron_trigger()'s sync then imports it as a newly-live version. 188 $trac->ticket_update( 189 $ticket_id, 190 'Marking live.', 191 [ 192 'action' => 'new_no_review', 193 '_ts' => $ticket['_ts'], 194 ], 195 false 196 ); 102 197 } 103 198 } -
sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/theme-directory.php
r14590 r14930 43 43 44 44 define( 'WPORG_THEMES_E2E_REPO', 'WordPress/theme-review-e2e' ); 45 46 /** 47 * Delay between a theme version being approved (by a reviewer on Trac, or via the 48 * auto-approval path for theme updates) and it becoming the live version served to 49 * sites by the themes API. Approved versions are held in Trac's `approved` status and 50 * migrated to live by the theme_directory_trac_sync cron once this delay elapses (see 51 * Trac_Sync::release_to_live()); the previous live version (if any) continues to be 52 * served in the meantime. Mitigates supply-chain risks by giving scanners and humans a 53 * window to flag bad releases. Reviewers can bypass the delay with Trac's `approve and 54 * mark` / `mark this theme` actions, which close the ticket as live immediately. 55 * 56 * Defers to the shared WPORG_PLUGIN_THEME_RELEASE_DELAY constant when it's defined 57 * so the plugin and theme directories can be tuned (or disabled) in lockstep from a 58 * single override point. 59 * 60 * Defaults to 0 (cooldown disabled, versions go live immediately) for now; this will be 61 * raised once the surrounding workflow is ready. Can be pre-defined in global config to 62 * override the default. 63 */ 64 if ( ! defined( 'WPORG_THEMES_RELEASE_COOL_DOWN_DELAY' ) ) { 65 define( 'WPORG_THEMES_RELEASE_COOL_DOWN_DELAY', defined( 'WPORG_PLUGIN_THEME_RELEASE_DELAY' ) ? WPORG_PLUGIN_THEME_RELEASE_DELAY : 0 ); 66 } 67 68 /** 69 * Returns the release cooldown delay, in seconds, for a theme. 70 * 71 * The WPORG_THEMES_RELEASE_COOL_DOWN_DELAY constant provides the default, which is then 72 * passed through the `wporg_themes_release_cooldown_delay` filter so the delay can be 73 * shortened, extended, or removed (return 0 to disable the cooldown) on a per-theme basis. 74 * The theme slug is passed to the filter when it is known. 75 * 76 * @param string $theme_slug The slug of the theme being acted upon, if known. 77 * @return int Delay in seconds. 0 disables the cooldown (the version goes live immediately). 78 */ 79 function wporg_themes_get_release_cooldown_delay( $theme_slug = '' ) { 80 /** 81 * Filters the release cooldown delay for a theme. 82 * 83 * Return 0 to disable the cooldown (the approved version goes live immediately), or a 84 * larger/smaller number of seconds to lengthen or shorten the delay for this theme. 85 * 86 * @param int $delay The default delay in seconds (WPORG_THEMES_RELEASE_COOL_DOWN_DELAY). 87 * @param string $theme_slug The slug of the theme being acted upon, or '' when not known. 88 */ 89 return (int) apply_filters( 'wporg_themes_release_cooldown_delay', WPORG_THEMES_RELEASE_COOL_DOWN_DELAY, $theme_slug ); 90 } 45 91 46 92 /** … … 401 447 * Handles updating the status of theme versions. 402 448 * 403 * @param int $post_id Post ID.404 * @param string $current_version The theme version to update.405 * @param string $new_status The status to update the current version to.449 * @param int $post_id Post ID. 450 * @param string $current_version The theme version to update. 451 * @param string $new_status The status to update the current version to. 406 452 * @return int|bool Meta ID if the key didn't exist, true on successful update, 407 453 * false on failure. … … 424 470 case 'new': 425 471 case 'live': 472 case 'approved': 426 473 // Discard all previous versions with that status. 427 474 foreach ( array_keys( $meta, $new_status ) as $version ) {
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)