App-RoboBot

 view release on metacpan or  search on metacpan

lib/App/RoboBot/Plugin/API/Github.pm  view on Meta::CPAN

=head3 Description

Removes the watcher for the given Github project in the current channel. If the
same project is being watched in other channels as well, it will need to be
removed from them separately.

=head3 Usage

<project url>

=head3 Examples

    (github-unwatch https://github.com/jsime/robobot)

=head2 github-list

=head3 Description

Displays the list of Github projects being watched in the current channel.

=cut

has '+commands' => (
    default => sub {{
        'github-watch' => { method      => 'add_repo_watcher',
                            description => 'Adds a watcher event for this channel, subscribing to commits, issues, and pull requests to the named Github repository.',
                            usage       => '<repo url>', },

        'github-unwatch' => { method      => 'remove_repo_watcher',
                              description => 'Removes a watcher for the named Github repository on this channel.',
                              usage       => '<repo url>', },

        'github-list' => { method      => 'list_repo_watchers',
                           description => 'Lists the Github repositories currently being watched for this channel.',
                           usage       => '' },
    }},
);

has 'watcher' => (
    is => 'rw',
);

has 'ua' => (
    is      => 'rw',
    isa     => 'LWP::UserAgent',
    default => sub {
        my $ua = LWP::UserAgent->new;
        $ua->agent('App::RoboBot');
        $ua->timeout(5);
        return $ua;
    },
);

sub init {
    my ($self, $bot) = @_;

    # Kick off the watcher with a short delay for the first check, to give the
    # bot a little time to settle into things before firing off notifications
    # in channels.
    $self->watcher(
        AnyEvent->timer(
            after => 30,
            cb    => sub { $self->_run_watcher($bot) },
        )
    );
}

sub list_repo_watchers {
    my ($self, $message, $command, $rpl) = @_;

    unless ($message->has_channel) {
        $message->response->raise('Only channels may have Github repository watchers.');
        return;
    }

    my $res = $self->bot->config->db->do(q{
        select r.repo_id, r.owner_name, r.repo_name
        from github_repos r
            join github_repo_channels c on (c.repo_id = r.repo_id)
        where c.channel_id = ?
        order by r.owner_name asc, r.repo_name asc
    }, $message->channel->id);

    if ($res && $res->count > 0) {
        $message->response->push(sprintf('%d Github %s being watched in this channel:', $res->count, ($res->count == 1 ? 'repository is' : 'repositories are')));

        while ($res->next) {
            $message->response->push(sprintf('https://github.com/%s/%s', $res->{'owner_name'}, $res->{'repo_name'}));
        }
    } else {
        $message->response->push('There are no Github repositories being watched for this channel.');
    }

    return;
}

sub add_repo_watcher {
    my ($self, $message, $command, $rpl, @repo_urls) = @_;

    unless ($message->has_channel) {
        $message->response->raise('Cannot add Github repository watchers without a channel.');
        return;
    }

    REPO:
    foreach my $url (@repo_urls) {
        $url = $self->clean_repo_url($url);
        my ($owner_name, $repo_name) = $self->get_repo_parts($url);

        unless (defined $owner_name && defined $repo_name) {
            $message->response->raise('"%s" does not appear to be a valid Github repository URL.', $url);
            next REPO;
        }

        my $repo = $self->bot->config->db->do(q{
            select repo_id
            from github_repos
            where lower(owner_name) = lower(?) and lower(repo_name) = lower(?)
        }, $owner_name, $repo_name);

        unless ($repo && $repo->next) {

lib/App/RoboBot/Plugin/API/Github.pm  view on Meta::CPAN

            $self->bot->config->plugins->{'github'}{'token'}
        );
    }

    my $response = $self->ua->request($req);

    return unless $response->is_success;

    my $json;
    eval {
        $json = decode_json($response->decoded_content);
    };

    return if $@;
    return $json;
}

sub _run_watcher {
    my ($self, $bot) = @_;

    # Ensure that we only get repositories that are currently associated with
    # channels, to suppress pointless API calls. Also, limit the results to
    # those repos which have either a NULL polled_at (newly-watched repos that
    # we've not yet checked) or those with a polled_at in the past (allows API
    # calling method to set a polled_at in the future to delay our next check
    # in the event of errors or API usage limits).
    my $repos = $bot->config->db->do(q{
        select r.repo_id, r.owner_name, r.repo_name, r.last_pr, r.last_issue,
            to_char(coalesce(r.polled_at, now() - interval '5 min') at time zone 'UTC','YYYY-MM-DD"T"HH24:MI:SS"Z"') as polled_at,
            count(distinct(c.id)) as num_channels, array_agg(c.id) as channels
        from github_repos r
            join github_repo_channels rc on (rc.repo_id = r.repo_id)
            join channels c on (c.id = rc.channel_id)
        where r.polled_at is null or r.polled_at < now() - interval '10 seconds'
        group by r.repo_id, r.owner_name, r.repo_name, r.polled_at, r.last_pr, r.last_issue
    });

    if ($repos) {
        while ($repos->next) {
            my @notices = $self->get_repo_notices($repos);

            next unless @notices > 0;

            foreach my $channel_id (@{$repos->{'channels'}}) {
                my $channel = App::RoboBot::Channel->find_by_id($self->bot, $channel_id);
                next unless defined $channel;

                my $response = App::RoboBot::Response->new(
                    network => $channel->network,
                    channel => $channel,
                    bot     => $bot,
                );

                $response->push(@notices);
                $response->send;
            }
        }
    }

    $self->watcher(
        AnyEvent->timer(
            after => 90,
            cb    => sub { $self->_run_watcher($bot) },
        )
    );
}

__PACKAGE__->meta->make_immutable;

1;



( run in 0.780 second using v1.01-cache-2.11-cpan-adec679a428 )