mirror of
https://gh.wpcy.net/https://github.com/WordPress/wordpress.org.git
synced 2026-04-30 06:42:28 +08:00
git-svn-id: https://meta.svn.wordpress.org/sites/trunk@11099 74240141-8908-4e6f-9713-ba540dce6ec7
169 lines
5.2 KiB
PHP
169 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace Dotorg\Slack\Trac;
|
|
|
|
class Bot {
|
|
const default_trac = 'core';
|
|
|
|
static private $default_tracs = array(
|
|
'#themereview' => 'themes',
|
|
'#bbpress' => 'bbpress',
|
|
'#buddypress' => 'buddypress',
|
|
'#glotpress' => 'glotpress',
|
|
'#meta' => 'meta',
|
|
'#outreach' => false,
|
|
);
|
|
|
|
// Channels that are primarily GitHub issues, where digit-only tickets should not be expanded.
|
|
static protected $github_channels = array(
|
|
'#core-editor',
|
|
);
|
|
|
|
protected $parsed = array();
|
|
|
|
// We want to post to Trac no more than once per two hours, and to Slack no more than once every 10 minutes.
|
|
// After 5 minutes for Slack, show a link only and extend it the redundancy.
|
|
private $redundant_time = array( 'slack' => 600, 'trac' => 7200 );
|
|
// After 5 minutes for Slack, show a link only. Extend the redundany check.
|
|
const slack_repost_link = 300;
|
|
|
|
private $avoid_redundancy = false;
|
|
|
|
function __construct( $post_data ) {
|
|
$this->post_data = $post_data;
|
|
}
|
|
|
|
function get_channel() {
|
|
return '#' . $this->post_data['channel_name'];
|
|
}
|
|
|
|
function get_thread() {
|
|
return $this->post_data['thread_ts'] ?? false;
|
|
}
|
|
|
|
function parse() {
|
|
$this->parse_tickets( $this->post_data['text'] );
|
|
$this->parse_commits( $this->post_data['text'] );
|
|
return $this->parsed;
|
|
}
|
|
|
|
function parse_tickets( $text ) {
|
|
$digits = Trac::get_digit_capture();
|
|
$ticket_tracs = '?<trac>' . Trac::get_regex();
|
|
$tickets = array();
|
|
|
|
// If the channel is GitHub centric, require the trac to be suffixed like #1234-core
|
|
$require_trac = in_array( $this->get_channel(), self::$github_channels, true );
|
|
$require_trac = $require_trac ? '' : '?'; // regex optional.
|
|
|
|
preg_match_all( "/(?:\s|^|\()#(?<id>$digits)(?:\-($ticket_tracs)){$require_trac}\b/", $text, $tickets, PREG_SET_ORDER );
|
|
|
|
// Always match trac-prefixed Tickets
|
|
preg_match_all( "/(?:\s|^|\()#($ticket_tracs)(?<id>$digits)\b/", $text, $tickets_alt, PREG_SET_ORDER );
|
|
|
|
// Always match full URI's
|
|
preg_match_all( "~https?://($ticket_tracs).trac.wordpress.org/ticket/(?<id>$digits)~", $text, $tickets_url, PREG_SET_ORDER );
|
|
|
|
foreach ( $tickets_url as &$ticket ) {
|
|
$ticket['url'] = true;
|
|
}
|
|
$tickets = array_merge( $tickets, $tickets_alt, $tickets_url );
|
|
$this->finish_parsing( 'ticket', $tickets );
|
|
}
|
|
|
|
function parse_commits( $text ) {
|
|
$digits = Trac::get_digit_capture();
|
|
$commit_tracs = '?<trac>' . Trac::get_regex();
|
|
preg_match_all( "/\br(?<id>$digits)(?:\-($commit_tracs))?\b/", $text, $revisions, PREG_SET_ORDER );
|
|
preg_match_all( "/\[($commit_tracs)?(?<id>$digits)\]/", $text, $commits, PREG_SET_ORDER );
|
|
preg_match_all( "/\[(?<id>$digits)-($commit_tracs)\]/", $text, $commits_alt, PREG_SET_ORDER );
|
|
// Edge case: Doesn't handle the design changesets. I don't care.
|
|
preg_match_all( "~https?://($commit_tracs).trac.wordpress.org/changeset/(?<id>$digits)~", $text, $changesets_url, PREG_SET_ORDER );
|
|
|
|
foreach ( $changesets_url as &$changeset ) {
|
|
$changeset['url'] = true;
|
|
}
|
|
|
|
$commits = array_merge( $commits, $commits_alt, $revisions, $changesets_url );
|
|
$this->finish_parsing( 'commit', $commits );
|
|
}
|
|
|
|
function finish_parsing( $type, $items ) {
|
|
foreach ( $items as $item ) {
|
|
$trac = $this->parse_trac( $item );
|
|
if ( ! $trac ) {
|
|
continue;
|
|
}
|
|
|
|
if ( $type === 'ticket' && ! $trac->has_tickets() ) {
|
|
continue;
|
|
} elseif ( $type === 'commit' && ! $trac->has_commits() ) {
|
|
continue;
|
|
}
|
|
|
|
unset( $item[0], $item[1], $item[2] );
|
|
$trac = $trac->get_slug();
|
|
|
|
if ( ! isset( $this->parsed[ $trac ][ $type ] ) ) {
|
|
$this->parsed[ $trac ][ $type ] = array( $item );
|
|
} elseif ( ! in_array( $item['id'], self::array_column( $this->parsed[ $trac ][ $type ], 'id' ) ) ) {
|
|
$this->parsed[ $trac ][ $type ][] = $item;
|
|
}
|
|
}
|
|
}
|
|
|
|
static function array_column( $array, $column ) {
|
|
$results = array();
|
|
foreach ( $array as $item ) {
|
|
$results[] = $item[ $column ];
|
|
}
|
|
return $results;
|
|
}
|
|
|
|
function parse_trac( $item ) {
|
|
if ( ! empty( $item['trac'] ) ) {
|
|
return Trac::get( $item['trac'] );
|
|
}
|
|
|
|
$channel = $this->get_channel();
|
|
if ( ! empty( self::$default_tracs[ $channel ] ) ) {
|
|
return Trac::get( self::$default_tracs[ $channel ] );
|
|
} elseif ( isset( self::$default_tracs[ $channel ] ) ) {
|
|
return false;
|
|
}
|
|
|
|
list( $channel_namespace ) = explode( '-', $channel, 2 );
|
|
if ( ! empty( self::$default_tracs[ $channel_namespace ] ) ) {
|
|
return Trac::get( self::$default_tracs[ $channel_namespace ] );
|
|
} elseif ( isset( self::$default_tracs[ $channel_namespace ] ) ) {
|
|
return false;
|
|
}
|
|
|
|
return Trac::get( self::default_trac );
|
|
}
|
|
|
|
// Redundancy functions
|
|
|
|
function avoid_redundancy() {
|
|
$this->avoid_redundancy = true;
|
|
wp_cache_init();
|
|
}
|
|
|
|
function is_redundant( $realm, $trac, $type, $id ) {
|
|
if ( ! $this->avoid_redundancy ) {
|
|
return false;
|
|
}
|
|
return wp_cache_get( $this->redundancy_key( $realm, $trac, $type, $id ), 'tracslack' );
|
|
}
|
|
|
|
function set_redundancy( $realm, $trac, $type, $id ) {
|
|
if ( ! $this->avoid_redundancy ) {
|
|
return;
|
|
}
|
|
wp_cache_set( $this->redundancy_key( $realm, $trac, $type, $id ), time(), 'tracslack', $this->redundant_time[ $realm ] );
|
|
}
|
|
|
|
function redundancy_key( $realm, $trac, $type, $id ) {
|
|
return sprintf( 'chan:%s:%s:%s:%s:%d', $this->get_channel(), $realm, $trac, $type, $id );
|
|
}
|
|
}
|