如何向 Skype 聊天室发出 Jenkins 构建状态警报?

2024-01-20

我们公司使用 Skype 进行通信,我希望能够在 Jenkins 构建失败(以及恢复时)时向 Skype 聊天室发送警报。

我怎样才能做到这一点?


我已经使用了Skype 公共 API http://developer.skype.com/accessories

我所做的是编写一个 Perl 脚本,它使用SkypeAPI http://search.cpan.org/~laomoi/SkypeAPI-0.08/lib/SkypeAPI.pmCPAN模块处理与Skype的通信。它有点笨重,因为该脚本需要在运行 Skype 的桌面上运行。我在自己的桌面上运行它,该桌面始终处于开启状态,但这确实意味着该机器人对于我们团队的其他成员来说似乎就是“我”。

最终结果非常棒 - 每当 jenkins 构建更改状态时,机器人都会向任何通过输入 *alert 注册了兴趣的 Skype 聊天发送消息。此外,任何开发人员都可以通过输入 *jenkins 查看并共享最新的构建状态

第 1 步 - 扩展 SkypeAPI 模块

现在,SkypeAPI 模块非常基本。它的listen()方法中有一个消息循环,用于检查来自Skype客户端的新事件,如果没有,则休眠一会儿。

我希望我的脚本能够挂接到这个循环中,以便我的机器人能够定期检查 Jenkins RSS 提要,因此在使用 ActiveState 包管理器安装 SkypeAPI.pm 后,我对它进行了以下修改:

我宣布新财产“闲置者”以及现有财产......

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

我添加了一个方法来设置“闲置者”回调,模块将调用该回调而不是休眠

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

最后,我修改了消息循环以调用空闲程序(如果设置)

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 步 - 编写机器人脚本

现在该模块的功能更强大了,只需编写一个脚本来充当机器人即可。这是我的 - 我对原始版本进行了一些编辑,因为它包含其他不相关的功能,但它应该为您提供一个起点。

所有依赖模块都可以使用 ActiveState 包管理器安装。

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:[email protected] /cdn-cgi/l/email-protection/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 步 - 运行机器人

如果您已将其另存为 robots.pl,只需打开一个控制台窗口并perl robot.pl应该让它运行。 Skype 会询问您是否允许 perl.exe 与其通信,一旦您确认,就可以开始了!

进入团队聊天室并输入*jenkins获取最新版本的摘要,并注册房间以获取版本更改的警报*alert

完美的 :)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何向 Skype 聊天室发出 Jenkins 构建状态警报? 的相关文章

  • 如何在 NodeJS 中允许表单数据

    我最近创建了一个接受文件的 API 我正在尝试使用 Postman 测试 API 如果我使用发出帖子请求x wwww form urlencoded身体类型 一切正常 我得到了所有预期的数据 唯一的问题是它不允许发送文件 如果我使用form
  • 如何从 Jenkins 管道中的函数返回“allOf”的值

    我们有一个 Jenkins 管道设置 使用 Jenkinsfile 来定义不同构建需要做什么 在我们的很多阶段 当我们要发布版本时 我们需要完成一些工作 但如果不打算发布版本 则可以跳过这些工作 目前我们有这样的代码 when allOf
  • 解锁 Jenkins - 如何

    我已经使用 putty 从 Windows 系统在我的 ec2 实例上安装了 jenkins 当我尝试通过网络访问 jenkins 时 我使用 var lib jenkins secrets initialAdminPassword 解锁
  • 无法在 Angular 10 中的“pdf-viewer”=>“ng2-pdf-viewer”中显示 blob url

    我有一个 API 它将上传的文件作为 blob 返回 当我尝试绑定时src如果使用 blob URL 则它不会显示任何内容 但是 当我尝试绑定直接 URL 时 它可以显示 PDF 文件 这是我下面给出的代码 我的 TS 代码 downloa
  • Powershell Invoke-Command 远程手动工作,但不能通过 Jenkins

    我遇到了一个非常奇怪的情况 即从 Windows Server 2012 R2 手动运行相同的命令时可以工作 但从同一服务器上运行的 Jenkins 从属进程无法工作 首先 手动运行的输出 管理 PowerShell 窗口 PS C Use
  • 如何在 Jenkins 中安排构建?

    如何安排 Jenkins 构建 使其只能在每天的特定时间进行构建 例如下午 4 点开始 0 16 1 7 我理解为 每个月周一到周日下午 0 分钟 下午 4 点 但是它每分钟都会构建 如果有任何建议 我将不胜感激 谢谢 Update 请阅读
  • 彭博开放 API

    彭博开放 API最近宣布 http www computerworlduk com news it business 3334375 bloomberg market data api made public 这只是彭博软件开发工具包 ht
  • Twitter 的推文按钮有回调吗?

    有没有办法在 Twitter 的推文按钮上注册回调 我希望能够跟踪我网站上的哪些特定用户在 Twitter 上发布了链接 我无法添加 onClick 事件 因为它是跨域 iFrame 还有其他想法吗 我见过一种方法 https stacko
  • 如何在 Django Rest 框架中编写“删除”操作的测试

    我正在为 Django Rest Framework API 编写测试 我一直在测试 删除 我对 创建 的测试工作正常 这是我的测试代码 import json from django urls import reverse from re
  • Booking.com酒店管理API

    我拥有一家酒店 并在 booking com 上查看了 API 因为我想创建自己的前端界面来更新我的酒店房价 房间数 以及通过该 API 上传图片 更新酒店描述 然而 我唯一能找到的是一个 API 供联营公司以一定的价格获取特定位置的酒店等
  • Jenkins 和 Github 不使用 SSH 密钥

    我已将 Jenkins 设置为从 Github 上的私有存储库中提取特定作业 尽管我已经生成了私钥 公钥并将其作为部署密钥添加到 github 但 Jenkins 似乎并未使用 SSH 密钥 当我从 Jenkins 用户进行 git clo
  • 在docker容器中运行Jenkins有什么优势

    我发现了很多关于如何运行你的博客Jenkins in Docker但没有人真正解释这样做的好处 这是我发现的唯一原因 使用 Docker 的理由 https twasink net 2016 08 01 setting up a jenki
  • JW Player javaScript API 不工作

    我使用 jwplayer version 5 10 2295 和浏览器 chrome 25 My code jwplayer container setup file path width 300px height 100px autost
  • 使用 PHP 和 OAuth 访问 SkyDrive

    我想使用 PHP 访问 skyDrive 我想检索文件和文件夹列表 下载 上传和删除文件 我有一个 microsoft dev clientID 和 clientSecret 有人可以帮助我开始使用 OAuth 连接到 skyDrive 并
  • 注册期间现有电子邮件的 422 或 409 状态代码

    我正在构建 RESTful API 遇到了一种情况 在用户注册期间 如果电子邮件已存在 则在422 and 409哪个http响应代码有意义 我浏览过类似的one https stackoverflow com questions 9269
  • Web 应用程序使用 API 来完成一切?

    我即将开始为我的公司规划一个内部项目管理工具 API 一直让我疑惑 首先创建 API 并使用这些 API 调用构建实际站点而不是实施两次 是否会被视为不好的做法 效率太低 让我知道你的想法 我完全同意开发 API 将为您提供解耦的架构 并且
  • 使用 Instagram Basic Display API 时出现“无效平台应用程序”错误

    我正在尝试使用 Instagram Basic 显示 API 但是当我发布授权代码以获取访问令牌时 我不断收到以下错误 error type OAuthException 代码 400 error message 平台应用无效 我正在遵循此
  • 如何让 Jenkins、Sonar 和 JaCoCo 插件在 Eclipse Tycho 插件项目(或者 Cobertura)中协同工作?

    我的设置是 詹金斯 1 448 声纳2 13 詹金斯声纳插件 1 72 Sonar 的 MySql 数据库 我有以下项目 Eclipse 插件项目 使用Maven 多个模块 父级 Maven 项目 源插件项目 测试片段项目 一个简单的 JU
  • 在 jenkins 中运行 Maven 项目时出现 java.lang.reflect.InitationTargetException

    这是堆栈跟踪树 我在 Jenkins 中运行我的 Maven 项目时得到的 我不明白我的代码有什么问题 也许是因为 Jenkins 中的一些插件 lt JENKINS REMOTING CAPACITY gt channel started
  • 简单、安全的API认证系统

    我有一个简单的 REST JSON API 供其他网站 应用程序访问我网站的一些数据库 通过 PHP 网关 基本上该服务的工作原理如下 调用 example com fruit orange 服务器返回有关橙子的 JSON 信息 问题是 我

随机推荐

  • Angular 2 + Material:无法使用带有第二个参数“text”、“card”等的map-get

    使用 Angular 2 4 Material 我需要自定义组件的主题 我首先尝试使用内置调色板 但不断收到 错误 未定义 仅当将 primary accent 或 warn 作为第二个参数传递给map get 时 它才有效 样式 scss
  • 为什么包含 -fPIC 来编译静态库会导致运行时出现分段错误?

    我正在使用 g 编译 C 静态库并使用 fPIC 选项 我必须使用 fPIC 选项 因为最终该库将与其他静态库链接以形成动态库 当我在本地测试静态库时 如果不包含 fPIC 选项 它可以完全正常工作 但是 一旦我使用 fPIC 编译库 我就
  • WPF 中的作物变换?

    WPF 允许使用以下子类Transform http msdn microsoft com en us library system windows media transform aspx缩放 ScaleTransform http ms
  • ng-include 编译为注释

    我有一个角度应用程序 想要在模板中添加其他内容作为 div ng include 似乎是一个完美的选择 在main html中 div div src div div 在 module html 中 div class module h1
  • 在 Visual Studio 2013 中找不到“置于前面”和“发送到后面”选项

    我是 Visual Studio 2013 的新手 我使用带有两个面板的单一表单 其中第二个面板堆叠在第一个面板的顶部 我无法切换到第一个面板 我搜索过谷歌 也在这里寻找答案 他们都建议使用 置于前面 和 发送到后面 选项 但我在任何地方都
  • 如何获取React Native GoogleSignIn的accessToken?

    我无法获取 accessToken 我需要在后端 api 中使用它 当我尝试这个时 googleLogin gt GoogleSignin signIn then data gt console log TEST JSON stringif
  • 如何使用 PHP 异常来定义重定向?

    我一直被教导在编程中使用异常可以从引发错误的对象中抽象出错误处理 看着PHP手册 http www php net manual en reserved exceptions php 看来PHP有一个Exception类和一个ErrorEx
  • 用字符串填充表格视图

    我已阅读 API 和示例 但无法理解如何填充表格视图 假设我有一个两列字符串数组 String 其中包含 名称 值 对 我现在只想创建一个表格视图 它在两列中显示数据 在第一列中显示原始数组中所有行的名称 在第二列中显示值 我尝试了什么 什
  • MySQL远程连接【不正常】

    我无法从外部访问 mysql 我认为这是 mysql 或防火墙的东西或 mysql 中的某些特权 我已经尝试执行互联网上的步骤 我将逐步介绍该过程 以举例说明我正在做的事情 并为其他遇到同样问题的人提供教程 我在用着 ubuntu serv
  • pyinstaller可执行文件的差异更新(修改嵌入的PYZ-00.pyz)

    我计划创建一个巨大的可执行目录并将其安装在某些设备上 想象一下 后来我发现我的 python 模块中有一个错误 有没有办法只传输 复制修改后的字节码 并用新的字节码替换原始字节码 我想这样做的原因是 在我的上下文中 带宽非常昂贵 我想远程修
  • 大型项目没有 PHP?为什么不? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我读过一些帖子 人们指出 没有建议 没有讨论 没有提供 PHP 不应该用于大型项目 作为一名主要的 PHP 开发人员 我问两个问题 大型项目 的
  • 带有 pod 标签的 Prometheus kubelet 指标 [关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 我想弄清楚如何使用 prometheus stack 将 pod 标签从 kubelet 指标获取到指标标签 在我们的环境中 我们需要
  • 在 C 中调用函数时的序列点和未定义/未指定的行为

    我试图确定我对 C 中序列点的理解 只是想检查一些东西 目前 我认为 1 是未定义的 而 2 只是未指定的 因为在 2 中 在评估参数后存在序列点g and h 所以我们不修改i序列点之间两次 但是参数的求值顺序f仍然未指定 我的理解正确吗
  • 为什么我的 Azure 存储帐户上的队列域丢失?

    我已使用以下设置在 Azure 上成功创建存储帐户 部署 资源管理器 类型 通用 标准 复制 ZRS 在 Azure 门户上 我可以看到 Blob 服务 如果单击它 我可以在 blob 域下创建 blob 容器 https 帐户名称 blo
  • Javascript字典性能问题

    现在我有以下 javascript 字典 var a a SVG343 1942 a UAL534 2153 右边的数字代表时间 键是唯一的 ID 我想让 id 成为键 因为它们是唯一的 我的问题是给出一个时间找到对应的id 我要如何做到这
  • 将外部域名连接到AWS S3网站

    我想在 Amazon S3 上托管一个静态网站 创建了相关的存储桶 测试它们正常 现在我已经在 EuroDNS 注册了一个域名 www gopropel io 我找不到如何将其连接到我的 AWS S3 存储桶 我需要创建路由 53 托管区域
  • Flutter Firebase Messaging 无法创建服务 io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService

    我正在尝试在 Flutter 应用程序中使用 Firebase Messaging 我遵循包装上的所有说明 在我的 pubspec yaml 中 我有这些包 dependencies flutter sdk flutter firebase
  • 当元素的父元素溢出时,使元素宽度拉伸以适合其子元素:auto;

    在这个简化的示例中 我有一个书柜 书架上放着书籍 书架是具有定义宽度的最外面的元素 书架上的书应该从左到右排列 没有包装 书架应该拉伸其宽度以显示书架上的所有书籍 所有书架的宽度必须相同 即最宽书架的宽度 My HTML div class
  • 保护 Raven 数据库的安全

    我正在尝试将 RavenDB 的访问权限限制为只有一名用户 更改设置以保护数据库后 我仍然可以访问 RavenDB 管理工作室 但我不确定为什么 我将 RavenDB 作为 Windows 服务运行 并且使用构建 573 这是我的 Rave
  • 如何向 Skype 聊天室发出 Jenkins 构建状态警报?

    我们公司使用 Skype 进行通信 我希望能够在 Jenkins 构建失败 以及恢复时 时向 Skype 聊天室发送警报 我怎样才能做到这一点 我已经使用了Skype 公共 API http developer skype com acce