我怎么可以提醒Skype的聊天室与詹金斯建状态? [英] How can I alert Skype chatrooms with Jenkins build status?

查看:138
本文介绍了我怎么可以提醒Skype的聊天室与詹金斯建状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的公司使用Skype的通信,而且我希望能够当詹金斯构建失败(当它恢复得)将警报发送到Skype的聊天室。

Our company uses Skype for communications, and I'd like to be able to send alerts to Skype chatrooms when a Jenkins build fails (and when it recovers too).

我怎样才能做到这一点?

How can I do this?

推荐答案

我做这个使用 Sk​​ype的公共API

我所做的就是写一个使用 Sk​​ypeAPI CPAN模块的Perl脚本处理与Skype通信。这是一个有点笨拙,因为脚本需要到正在运行的Skype桌面上运行。我在我自己的桌面它总是反正上运行它,但是这并不意味着机器人似乎是'我'对我们团队的其他成员。

What I did was write a Perl script which uses the SkypeAPI CPAN module to handle the communications with Skype. It's a little clunky, as the script needs to run on a desktop which is running Skype. I run it on my own desktop which is always on anyway, but this does mean the bot appears to be 'me' to the rest of our team.

最终的结果是太棒了 - 每当詹金斯打造的变化状态,机器人将消息发送到已通过键入*警报注册的任何利益的Skype聊天。此外,任何开发人员可以看到并通过键入*詹金斯分享最新的构建状态

The end result is fantastic - whenever a jenkins build changes state, the bot sends a message to any Skype chats which have registered an interest by typing *alert. Additionally, any developer can see and share the latest build status by typing *jenkins

现在,SkypeAPI模块是pretty基础。它具有在检查来自Skype客户端新事件监听()方法的消息循环,睡了一会儿,如果有没有。

Now, the SkypeAPI module is pretty basic. It has a message loop in the listen() method which checks for new events from the Skype client, and sleeps for a moment if there none.

我希望我的脚本来挂接到这个循环,这样我可以有我的机器人定期检查詹金斯RSS提要,所以我做了以下修改SkypeAPI.pm我曾与ActiveState的包管理器安装后:

I wanted my script to hook into this loop so that I could have my bot periodically check Jenkins RSS feed, so I made the following modifications to SkypeAPI.pm after I had installed it with the ActiveState package manager:

我宣布新的财产'闲人'连同现有的属性...

I declared new property 'idler' along with the existing properties...

__PACKAGE__->mk_accessors(
  qw/api handler_list stop_listen idler/
);

我添加设置一个'闲人'回调该模块调用,而不是睡觉的方法

I added a method to set an 'idler' callback which the module will call instead of sleeping

sub register_idler {
    my $self = shift;
    my $ref_sub = shift;
    $self->idler($ref_sub);
}

最后,我修改的消息循环调用惰如果设置

Finally I modified the message loop to call the idler if set

sub listen {
    my $self = shift;

    my $idler=$self->idler();

    $self->stop_listen(0);
    while (!$self->stop_listen) {
        my $message;
        {
            lock @message_list;
            $message = shift @message_list;
        }
        if (not defined $message) {
            if ($idler)
            {
                $self->idler->($self);
            }
            else
            {
                sleep 0.1;             
            }
            next;
        }
        for my $id (sort keys %{$self->handler_list}) {
            $self->handler_list->{$id}->($self, $message);
        }
    }
}

步骤2 - 写一个脚本机器人

现在该模块是多了几分干练,它只是一个写一个脚本来充当机器人的问题。这里是我的 - 我已经从我原来做了一些修改,因为它包含其他不相关的功能,但它应该给你一个起点

Step 2 - write a robot script

Now the module is a little more capable, it's just a matter of writing a script to act as a bot. Here's mine - I've made a few edits from my original as it contained other irrelevant functionality, but it should give you a starting point.

所有从属模块可以安装与ActiveState的包管理

All of the dependant modules can be installed with the ActiveState package manager.

use strict;
use SkypeAPI;
use LWP::Simple;
use Data::Dumper;
use dirtyRSS;
use Time::Local 'timegm';
use Math::Round;
use Storable;

#CHANGE THIS - where to get jenkins status from
my $jenkinsRss='http://username:password@jenkins.example.com/rssLatest';

my %commands=(
    'jenkins'   =>\&cmdJenkins,
    'alert'     =>\&cmdAlert,
    'noalert'   =>\&cmdNoAlert,
    'help'      =>\&cmdHelp,
);

my $helpMessage=<<HELP;
Who asked for help? Here's all the other special commands I know...

  *jenkins - show status of our platform tests
  *alert - add this room to get automatic notification of build status
  *noalert - cancel notifcations
  *help - displays this message
HELP


#status for jenkins tracking
my %builds;
my $lastJenkinsCheck=0;
my $alertRoomsFile='alert.rooms';
my $alertRooms={};

#store jenkins state
checkJenkins();

#because that was our first fetch, we'll have flagged everything as changed
#but it hasn't really, so we reset those flags
resetJenkinsChangeFlags();

#remember rooms we're supposed to alert
loadAlertRooms();

#attach to skype and enter message loop
my $skype = SkypeAPI->new();
my $attached=$skype->attach();
$skype->register_handler(\&onEvent);
$skype->register_idler(\&onIdle);
$skype->listen();

exit;

#here are the command handlers
sub cmdJenkins
{
    my ($chatId, $args)=@_;

    my $message="";
    foreach my $build (keys(%builds))
    {
        $message.=formatBuildMessage($build)."\n";

        #reset changed flag - we've just show the status
        $builds{$build}->{'changed'}=0;
    }

    chatmessage($chatId, $message);
}

sub cmdAlert
{
    my ($chatId, $args)=@_;
    addChatroomToAlerts($chatId,1);
}

sub cmdNoAlert
{
    my ($chatId, $args)=@_;
    addChatroomToAlerts($chatId,0);
}

sub cmdHelp
{
    my ($chatId, $args)=@_;
    chatmessage($chatId, $helpMessage);
}






#simple helper to transmit a message to a specific chatroom
sub chatmessage
{
    my ($chatId, $message)=@_;
    my $commandstr="CHATMESSAGE $chatId $message";
    my $command = $skype->create_command( { string => $commandstr}  );
    $skype->send_command($command);
}


#refreshes our copy of jenkins state, and will flag any builds
#which have changed state since the last check
sub checkJenkins{

    my $xml = get($jenkinsRss);
    my $tree = parse($xml);
    my $items=$tree->{'channel'}->[0]->{'item'};

    foreach my $item (@{$items})
    {
        my $title=$item->{'title'};
        my $link=$item->{'link'};
        my $built=$item->{'lastbuilddate'};

        #print Dumper($item);

        if ($title=~m/^(.*?) #(\d+)\s*(.*)$/)
        {
            my $build=$1;
            my $buildnumber=$2;
            my $status=$3;
            #print "$build\n$buildnumber\n$status\n$link\n$built\n\n";    

            #build in progress, ignore

            if (!exists($builds{$build}))
            {
                $builds{$build}={};
                $builds{$build}->{'status'}='';
                $builds{$build}->{'changed'}=0;
            }

            $builds{$build}->{'name'}=$build;

            if ($status eq '(?)')
            {
                $builds{$build}->{'in_progress'}=1;
                next; #don't update until complete
            }
            else
            {
                $builds{$build}->{'in_progress'}=0;
            }

            #is this status different to last status?
            if ($builds{$build}->{'status'} ne $status)
            {
                $builds{$build}->{'changed'}=1;
            }

            $builds{$build}->{'status'}=$status;
            $builds{$build}->{'build_number'}=$buildnumber;
            $builds{$build}->{'link'}=$link;
            $builds{$build}->{'built'}=$built;

        }
    }
    #print Dumper(\%builds);


}

#generates a string suitable for displaying build status in skype
sub formatBuildMessage
{
    my ($build)=@_;
    my $status=$builds{$build}->{'status'};

    my $smiley=":)";
    if ($status=~m/broken/)
    {
        $smiley="(devil)";

    }
    elsif ($status=~m/\?/)
    {
         #this means the build is being retested, we should skip it
         $smiley=":|";
    }

    my $message='';

    if ($builds{$build}->{'in_progress'})
    {
       $message=":| $build - rebuild in progress..."
    }
    else
    {

        my ($y,$mon,$d,$h,$m,$s) = $builds{$build}->{'built'} =~ m/(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z/;
        my $time = timegm($s,$m,$h,$d,$mon-1,$y);
        my $age=time()-$time;

        my $mins=round($age/60);
        my $hrs=round($age/3600);
        my $days=round($age/86400);

        my $niceage;
        if ($mins<=2)
        {
            $niceage="a few moments ago";
        }
        elsif ($mins<120)
        {
             $niceage="$mins minutes ago";
        }
        elsif ($hrs<48)
        {
             $niceage="$hrs hours ago";
        }
        else
        {
            $niceage="$days days ago";
        }

        $message="$smiley $build last built $niceage $status";
    }
    return $message;
}

#forget any changes we've flagged
sub resetJenkinsChangeFlags
{
   foreach my $build (keys(%builds))
   {
       $builds{$build}->{'changed'}=0;
   }
}

#checks for builds which have changed state. Can be called
#often, it will only kick in if 60 seconds have elapsed since
#last check
sub checkForJenkinsChanges
{
    my $now=time();
    if (($now-$lastJenkinsCheck) < 60)
    {
        #no need, we fetched it recently
        return;
    }

    checkJenkins();

    my $message='';

    foreach my $build (keys(%builds))
    {
        if ($builds{$build}->{'changed'})
        {
            $builds{$build}->{'changed'}=0;
            $message.=formatBuildMessage($build)."\n";
        }

    }

    if (length($message))
    {
        foreach my $chatId (keys(%$alertRooms))
        {
            chatmessage($chatId, $message);
        }
    }

    $lastJenkinsCheck=$now;
}

#adds or removes a room from the alerts
sub addChatroomToAlerts
{
    my($chatId, $add)=@_;
    if ($add)
    {
        if (exists($alertRooms->{$chatId}))
        {
            chatmessage($chatId, "/me says this room is already getting alerts");
        }
        else
        {
            $alertRooms->{$chatId}=1;
            chatmessage($chatId, "/me added this chatroom to jenkins alerts");
        }
    }
    else
    {
        delete($alertRooms->{$chatId});
        chatmessage($chatId, "/me removed this chatroom from jenkins alerts");
    }

    store $alertRooms, $alertRoomsFile;
}   

sub loadAlertRooms
{
    if (-e  $alertRoomsFile)
    {
        $alertRooms = retrieve( $alertRoomsFile);
    }
}


# Skype event handler
sub onEvent {
    my $skype = shift;
    my $msg = shift;
    #my $command = $skype->create_command( { string => "GET USERSTATUS"}  );
    #print $skype->send_command($command) , "\n";

    #print "handler: $msg\n";

    #an inbound chat message is either
    #MESSAGE 13021257 STATUS RECEIVED (from others)
    #MESSAGE 13021257 STATUS SENT (from us)

    if ($msg =~ m/MESSAGE (\d+) STATUS (SEND|RECEIVED)/)
    {
        my $msgId=$1;

        #get message body
        my $commandstr="GET CHATMESSAGE $msgId BODY";
        my $command = $skype->create_command( { string => $commandstr}  );
        my $output=$skype->send_command($command);


        #if its a message for us...
        if ($output =~ m/MESSAGE $msgId BODY \*([^\s]*)\s*(.*)/i)
        {
            my $botcmd=$1;
            my $botargs=$2;

            $commandstr="GET CHATMESSAGE $msgId CHATNAME";
            $command = $skype->create_command( { string => $commandstr}  );
            $output=$skype->send_command($command);

            if ($output =~ m/MESSAGE $msgId CHATNAME (.*)/)
            {
                my $chatId=$1;
                if (exists($commands{$botcmd}))
                {
                    $commands{$botcmd}->($chatId, $botargs);
                }
                else
                {
                    chatmessage($chatId, "/me suggests trying *help as the robot didn't understand *$botcmd");
                }    
            }
        }
    }
}



#skype idle handler
#Note - SkypeAPI.pm was modified to support this
sub onIdle {
    my $skype = shift;
    checkForJenkinsChanges();
    sleep 0.1;             
}

步骤3 - 运行僵尸

如果您保存这个作为robot.pl,只要打开控制台窗口和 perl的robot.pl 应该得到它运行。 Skype将询问您是否perl.exe所在应该被允许与其通信,一旦你确认,你是好去!

Step 3 - Run the bot

If you've saved this as robot.pl, just open a console window and perl robot.pl should get it running. Skype will ask you if perl.exe should be allowed to communicate with it, and once you confirm that, you're good to go!

进入一个团队聊天室,然后键入 *詹金斯为最新的总结版本,并注册的空间的生成更改警报*警报

Go into a team chatroom and type *jenkins for an summary of latest builds, and register the room for alerts of build changes with *alert

完美:)

这篇关于我怎么可以提醒Skype的聊天室与詹金斯建状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆