IRC に issue 番号に反応する bot がいると捗る
IRC bot のはなし。
#123
みたいな文字列に反応して、
- github の issue のタイトル
- github の issue の URL
を返してくれる bot をつくったら思いの外便利だった。
#!/usr/bin/env perl use strict; use warnings; use utf8; use AnyEvent::IRC::Client; use AnyEvent; use Config::Pit; use Encode; use Furl; use HTTP::Request; use JSON::XS; use Log::Minimal; use App::Options( option => { nick => { type => 'string', default => 'issue-bot' }, channel => { type => 'string' }, join_message => { type => 'string', default => '' }, org_name => { type => 'string' }, project_name => { type => 'string' }, }, ); my %opts = %App::options; $Log::Minimal::PRINT = sub { my ($time, $type, $message, $trace, $raw_message) = @_; print STDERR "$time [$type] $message at $trace\n"; }; my $github = pit_get('github', require => { username => 'github username', password => 'github password', }); my $irc_conf = pit_get('irc', require => { host => 'irc host', port => 'irc port', password => 'irc password', }); my $json = JSON::XS->new->utf8; my $furl = Furl->new(); my $cv = AnyEvent->condvar; my $con = AnyEvent::IRC::Client->new(); $con->reg_cb( connect => sub { my ($con, $err) = @_; if (defined $err) { warnf "connection error: %s", $err; $cv->send(); } else { infof 'connected'; } } ); $con->reg_cb( registered => sub { infof 'registered'; if ($opts{join_message}) { $con->send_chan( $opts{channel}, 'PRIVMSG', $opts{channel}, $opts{join_message}, ); } } ); $con->reg_cb( disconnect => sub { infof 'disconnected'; $cv->broadcast(); } ); $con->reg_cb( publicmsg => sub { my ($con, $channel, $irc_message) = @_; return unless $irc_message->{command} eq 'PRIVMSG'; my @issue_nums = $irc_message->{params}[1] =~ /#([0-9]+)/g; return unless @issue_nums; for my $issue_num (@issue_nums) { my $message = retrieve_issue_info($issue_num); next unless $message; infof $message; send_message($con, $message); } } ); $con->enable_ssl(); $con->connect($irc_conf->{host}, $irc_conf->{port}, { nick => $opts{nick}, password => $irc_conf->{password}, }); $con->send_srv('JOIN', $opts{channel}); $cv->recv(); $con->disconnect(); sub retrieve_issue_info { my ($issue_num) = @_; my $url = sprintf 'https://api.github.com/repos/%s/%s/issues/%d', $opts{org_name}, $opts{project_name}, $issue_num; my $req = HTTP::Request->new( GET => $url ); $req->authorization_basic( $github->{username}, $github->{password}, ); my $res = $furl->request($req); if ($res->status != 200) { warnf '#%d %s', $issue_num, $res->content; return; } my $issue = $json->decode($res->content); return encode_utf8(sprintf( '#%d %s %s', $issue->{number}, $issue->{title}, $issue->{html_url}, )); } sub send_message { my ($con, $message) = @_; $con->send_chan( $opts{channel}, 'NOTICE', $opts{channel}, $message, ); }