【Jenkins学习 】如何编写Python脚本来调用企业微信的api通知企业微信成员关于Jenkins的编译结果?

一、需求描述

最近公司将RTX更新为了企业微信,并且准备将之前的OA邮箱之类的都废弃掉了。而之前我们的Jenkins编译结果都是通过发送到OA邮箱来进行通知的,因此后面OA邮箱被废弃掉的话,那么我们就无法收到Jenkins的编译结果了。

因此我们得想其他办法来通知相关人员关于Jenkins的编译结果。和公司负责企业微信推广的同事聊了聊之后,发现可以通过企业微信提供的api来进行开发,然后实现将Jenkins的编译结果通过企业微信来发送消息。

二、了解企业微信的api

2.1 api相关参考资料

在腾讯,能够看到的信息如下

没有更多的消息,企业微信发消息的api和微信企业号发送的有点类似,大致看下即可。

2.2 公司封装的企业微信发消息的api文档

公司负责企业微信推广的同事对企业微信发送消息的api进行了再次封装,然后发送了一篇api文档给我,大致如下:

2.2.1 请求接口步骤

  • 1 获取apid与Secret
    请联系公司内部推广企业微信的同事,可得到调用所需的ClientId与Secret

  • 2 获取token的api
    请求api

	POST: http://ip地址:8000/connect/token
	{
		client_id:步骤1中获得,
		client_secret:步骤1中获得,
		grant_type:"client_credentials",
		scope:"ApiGateway"
	}

注:body使用x-www-form-urlencoded

返回的内容

	返回内容:
	{
		"access_token":"",
		"expires_in": 3600,
		"token_type":"Bearer"
	}
  • 3 使用步骤2中得到的Bearer Token请求资源.

2.2.2 请求接口步骤发送微信消息接口说明

    1. 发送图文信息
POST: http://ip地址:8000/api/wechat/news
{
   "toUser" : "工号1|工号2....",
   "agentId" : 0,
   "news" : {
       "articles" : [
           {
               "title" : "中秋节礼品领取",
               "description" : "今年中秋节公司有豪礼相送",
               "url" : "URL",
               "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png",
               "btntxt":"更多"
           }
        ]
   }
}
    1. 发送文本消息
POST: http://ip地址:8000/api/wechat/text
{
   "toUser" : "工号1|工号2....",
   "agentId" : 0,
   "content":"xxxxxx"
}
    1. 文本卡片消息
POST: http://ip地址:8000/api/wechat/textcard

{
   "toUser" : "工号1|工号2....",
   "agentId" : 0,
   "title" : "领奖通知",
   "description" : "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>",
   "url":"http://www.baidu.com",
   "btntxt":"更多"
   
}

三、编写python脚本来调用企业微信api

在你的项目中,加入一个python脚本和一个jenkins账号和企业微信工号的配置文件,如下所示

在这里插入图片描述

3.1 编写Jenkins账户对应的企业微信的工号映射表

上面的python脚本在执行的时候,会将Jenkins账户转换为企业微信的工号,这个转换过程是通过读取Jenkins账户对应的企业微信的工号映射表jenkins_users.xml来进行的。

jenkins_users.xml的格式如下:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<users>
    <user>
        <name>欧阳鹏</name>
        <wechat>000001</wechat>
    </user>
    <user>
        <name>员工2</name>
        <wechat>000002</wechat>
    </user>
    <user>
        <name>员工3</name>
        <wechat>000003</wechat>
    </user>
    <user>
        <name>员工4</name>
        <wechat>000004</wechat>
    </user>
    <user>
        <name>员工4</name>
        <wechat>000005</wechat>
    </user>
</users>

3.2 python脚本 xutils.py 内容如下

#!/usr/bin/python2.7  
# -*- coding: utf-8 -*-

import json
import os
import sys
import time
import urllib
import urllib2
import xml.dom.minidom

reload(sys)
sys.setdefaultencoding('utf-8')

ISOTIMEFORMAT = "%Y-%m%d-%H%M"

TIMEFORMAT = "%Y-%m-%d %H:%M:%S"

# %Y 四位数的年份表示(000-9999)
# %m 月份(01-12)
# %d 月内中的一天(0-31)
FTP_TIMEFORMAT = "%Y-%m-%d"

def getNowTimeForFTP():
    nowtime = time.strftime(FTP_TIMEFORMAT, time.localtime(time.time()))
    return nowtime

def getNowTimeFormat():
    nowtime = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
    return nowtime


def getNowTime():
    nowtime = time.strftime(TIMEFORMAT, time.localtime(time.time()))
    return nowtime

class XTCMessage:
    """ ESB接入说明  企业微信接口对接
    1.获取apid与Secret,请联系系统管理部架构及IT可得到调用所需的ClientId与Secret
    2.获取token
        POST: http://ip地址/connect/token
        {
            client_id:步骤1中获得,
            client_secret:步骤1中获得,
            grant_type:"client_credentials",
            scope:"ApiGateway"
        }
        注:body使用x-www-form-urlencoded

        返回内容:
        {
            "access_token":"",
            "expires_in": 3600,
            "token_type":"Bearer"
        }
    3.使用步骤2中得到的Bearer Token请求资源.
    """

    def __init__(self):
        self.access_token = ''

    auth_data = {"client_id": "xxxxxxxxx", "client_secret": "xxxxxxxxx",
                 "grant_type": "client_credentials", "scope": "ApiGateway"}
    auth_url = 'http://ip地址:8000/connect/token'

    # x-www-form-urlencoded
    def __post_xwwwformurlencoded(self, url, body_value):
        body_value = urllib.urlencode(body_value)
        request = urllib2.Request(url, body_value)
        response = urllib2.urlopen(request)
        print response.getcode()
        print response.geturl()
        ret = response.read()
        return ret

    def login(self):
        data = self.__post_xwwwformurlencoded(self.auth_url, self.auth_data)
        json_data = json.loads(data)
        self.access_token = 'Bearer ' + json_data['access_token']
        return

    # x-www-form-urlencoded
    def __post(self, url, body, token):
        request = urllib2.Request(url)
        request.add_header('Content-TYPE', 'application/json')
        request.add_header('Authorization', self.access_token)
        response = urllib2.urlopen(request, json.dumps(body))
        print response.getcode()
        print response.geturl()
        ret = response.read()
        return ret

    def send_text(self, users, message):
        msg_text_url = 'http://ip地址:8000/api/wechat/text'
        """  发送文本消息
        POST: http://ip地址/api/wechat/text
        {
           "toUser" : "工号1|工号2",
           "agentId" : 0,
           "content":"xxxxxx"
        }
        """
        data = {"toUser": users, "agentId": 0, "content": message}
        print('send_text():url = %s  ,data = %s' % (msg_text_url, data))
        self.__post(msg_text_url, data, self.access_token)

    def send_card(self, users, title, detail, link='http://www.baidu.com'):
        """  发送图文信息
        POST: http://ip地址/api/wechat/textcard
        {
           "toUser" : "工号1|工号2....",
           "agentId" : 0,
           "title" : "领奖通知",
           "description" : "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>",
           "url":"http://www.baidu.com",
           "btntxt":"更多"
        }
        """
        msg_card_url = 'http://ip地址:8000/api/wechat/textcard'
        data = {"toUser": users, "agentId": 0, "title": title, "description": detail, "url": link}
        print('send_card():url = %s  ,data = %s' % (msg_card_url, data))
        self.__post(msg_card_url, data, self.access_token)

    def send_news(self, users, title, detail, url, picurl):
        """  发送图文信息
        POST: http://ip地址/api/wechat/news
        {
           "toUser" : "工号1|工号2....",
           "agentId" : 0,
           "news" : {
               "articles" : [
                   {
                       "title" : "中秋节礼品领取",
                       "description" : "今年中秋节公司有豪礼相送",
                       "url" : "URL",
                       "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png",
                       "btntxt":"更多"
                   }
                ]
           }
        }
        """
        msg_news_url = 'http://ip地址:8000/api/wechat/news'
        data = {"toUser": users, "agentId": 0, "news": {
            "articles": [{"title": title, "description": detail, "url": url, "picUrl": picurl}]}}
        print('send_news():url = %s  ,data = %s' % (msg_news_url, data))
        self.__post(msg_news_url, data, self.access_token)


def call_xtcmessager(argv):
    xtcmsger = XTCMessage()
    xtcmsger.login()
    if len(argv) == 3:
        xtcmsger.send_text(argv[1], argv[2])
    elif len(argv) == 5:
        xtcmsger.send_card(argv[1], argv[2], argv[3], argv[4])
    elif len(argv) == 6:
        xtcmsger.send_news(argv[1], argv[2], argv[3], argv[4], argv[5])
    else:
        print('error: parameter wrong!')
        print(argv)

class Jenkins():
    def __init__(self):
        self.argv = []

    def get_wechat(self, fname, username):
        """
            获取jenkins用户名对应的企业微信的工号 ,比如:jenkins用户名   【欧阳鹏】对应的工号是【0000001】
            参数:
                   fname 配置文件名
                   username:Jenins用户名
       """
        if os.path.exists(fname):
            # filecontent = XmlReader.read_content(self,fname)
            # if None != filecontent:
            # dom = xml.dom.minidom.parseString(filecontent)
            dom = xml.dom.minidom.parse(fname)
            collection = dom.documentElement
            users = collection.getElementsByTagName("user")

            for idx in range(0, len(users)):
                user = users[idx]

                name = user.getElementsByTagName('name')[0].childNodes[0].data
                wechat = user.getElementsByTagName('wechat')[0].childNodes[0].data

                if username == name:
                    return wechat

        print('wechat of user ' + username + ' can not be found!')
        return ''

    def sendmessage(self, title, job_name, build_number, branch, user, git_commit, build_url,
                    weichat_receivers):
        """
             发送jenkins编译消息给企业微信
              参数:
                    title 提醒标题
                    job_name:Jenins任务名
                    build_number: Jenins编译次数
                    branch: git分支
                    user: Jenins编译触发者
                    git_commit: git commit sha1码
                    build_url: Jenins编译的url地址
                    weichat_receivers:企业微信接收者 , 比如:"欧阳鹏|员工2"  用 | 分隔
        """
        self.argv.append('vrix')

        message = """		
				  <li><font color="#0B610B">%(TITLE)s</font><li>
				  <li><font color="#0B610B">构建信息</font><li>
				  <li>------------------------<li>
				  <li>%(TIME)s<li>
				  <li>------------------------<li>
				  <li>用户名&nbsp;:%(USER)s</li>
				  <li>任务名&nbsp;:%(PROJECT_NAME)s</li>
				  <li>分支名&nbsp;:%(GIT_BRANCH)s</li>
				  <li>构建编号&nbsp;:第%(BUILD_NUMBER)s次构建</li>
				  <li>GIT&nbsp;SHA1&nbsp;:%(GIT_COMMIT)s</li>
				  <li>构建日志&nbsp;:<a href="%(BUILD_URL)sconsole">%(BUILD_URL)sconsole</a></li>
				  <li>FTP归档地址如下所示:(用户名:xxxx 密码:xxxx)</li>
				  <li>ftp://ftp的ip地址/project/AndroidPhone/%(PROJECT_NAME)s/%(FTP_TIME)s-git-%(GIT_COMMIT)s-build-%(BUILD_NUMBER)s<li>
				  <li>静态代码分析报告</li>
				  <li>Android Lint 报告&nbsp;: <a href="%(BUILD_URL)sandroidLintResult">%(BUILD_URL)sandroidLintResult </a></li>
			      <li>FindBugs 报告&nbsp;:<a href="%(BUILD_URL)sfindbugsResult">%(BUILD_URL)sfindbugsResult </a></li>
			      <li>发送企业微信信息给&nbsp;:%(WEICHAT_RECEIVERS)s</li>
			""" % dict(
            TITLE=title,
            TIME=getNowTime(),
            USER=user,
            GIT_BRANCH=branch,
            PROJECT_NAME=job_name,
            BUILD_NUMBER=build_number,
            GIT_COMMIT=git_commit,
            BUILD_URL=build_url,
            WEICHAT_RECEIVERS=weichat_receivers,
            FTP_TIME = getNowTimeForFTP()
        )
        # 最终要发送的企业微信user拼接列表
        wechat_receiver_users_string = ''
        # 分隔外面传进来的  企业微信接收者
        weichat_receivers_list = weichat_receivers.split('|')
        for weichat_receiver_user in weichat_receivers_list:
            wechat_user = self.get_wechat('jenkins_users.xml', weichat_receiver_user)
            print('Jenkins user:' + weichat_receiver_user + " weichat user_number:" + wechat_user)
            if wechat_user == '':
                print('Jenkins user:' + weichat_receiver_user + " weichat user_number is null")
            else:
                #  拼接成格式:   "工号1|工号2"
                wechat_receiver_users_string = wechat_receiver_users_string + wechat_user + "|"


        if wechat_receiver_users_string != '':
            print('-----------send msg to user ' + wechat_receiver_users_string)
            self.argv.append(wechat_receiver_users_string)
            self.argv.append(message)
        else:
            print('-----------send to vrix')
            # 默认发送给 00001  如果要加人的话  用 | 分开
            # self.argv.append('工号1|工号1')
            self.argv.append('00001')
            self.argv.append(message)
        call_xtcmessager(self.argv)


def call_jenkins(argv):
    """
         发送jenkins编译消息给企业微信
         参数:
                    title 提醒标题
                    jobname:Jenins任务名
                    build_number: Jenins编译次数
                    branch: git分支
                    user: Jenins编译触发者
                    git_commit: git commit sha1码
                    build_url: Jenins编译的url地址
    """
    job_name = argv[2]
    build_number = argv[3]
    branch = argv[4]
    user = argv[5]
    git_commit = argv[6]
    build_url = argv[7]
    weichat_receivers = argv[8]

    jenkins = Jenkins()
    jenkins.sendmessage('---Jenkins 构建提醒----', job_name, build_number, branch, user, git_commit,
                        build_url, weichat_receivers)


if __name__ == "__main__":
    if len(sys.argv) > 1:
        print(sys.argv)
        if sys.argv[1] == 'jenkins':
            print('--- jenkins')
            call_jenkins(sys.argv)
        else:
            call_xtcmessager(sys.argv)
    else:
        print('usage:')
        print('测试  python xutils.py "00001|00002" \"hello world!\" ')
        print('测试  Jenkins的话   python xutils.py jenkins ${JOB_NAME} ${BUILD_NUMBER} ${GIT_BRANCH} ${BUILD_USER} ${JOB_DESCRIPTION} ${GIT_COMMIT} ${CAUSE} ${BUILD_URL} ${PROJECT_URL} ${WEICHAT_RECEIVERS} ')

该脚本在jenkins的任务中,通过shell脚本进行调用,具体怎么调用,继续看下面的内容。

四 、配置jenkins的任务

4.1 勾选【Set jenkins user build variables】

【构建环境】中 勾选【Set jenkins user build variables】,不然jenkins的环境变量无法读取

在这里插入图片描述

4.2 添加一个【参数构建化过程】

在【General】中,添加一个【参数构建化过程】,增加一个参数,如下所示:

在这里插入图片描述

  • 参数名
    参数名为 WEICHAT_RECEIVERS,

  • 默认值
    默认值为要发送给企业微信的人员列表,

可以是一个列表,用 | 分隔符分开即可,比如 员工1|员工2|员工3|员工4|欧阳鹏|员工5|员工6|员工7
也可以只写一个人,比如欧阳鹏

  • 描述

要发送给企业微信的人员列表

4.3 增加一个构建过程 【Execute Shell】

如下图所示,在 jenkins的具体任务中,【构建】最后加入一个【Execute shell】,然后复制脚本进入即可

在这里插入图片描述

# 进入workspace
cd ${WORKSPACE}
# 执行python脚本,发送编译结果给企业微信
python xutils.py jenkins ${JOB_NAME} ${BUILD_NUMBER} ${GIT_BRANCH} ${BUILD_USER} ${JOB_DESCRIPTION} ${GIT_COMMIT} ${CAUSE} ${BUILD_URL} ${PROJECT_URL} ${WEICHAT_RECEIVERS}

4.4 删除原来的发送邮件到OA的模块,因为已经没意义了。

【构建后操作】–>【Editable Email Notification】 然后点击右上角的 红色叉号,直接删除邮件发送模块
在这里插入图片描述

4.5 配置FTP地址

【构建后操作】–>【Send build artifacts over FTP 】

配置地址为 下面的内容,因为脚本中是读取这个地址的

AndroidPhone/${JOB_NAME}/'yyyy-MM-dd-HH-mm-ss-'git-${GIT_COMMIT}-build-${BUILD_NUMBER}

在这里插入图片描述

五、执行Jenkins任务

5.1 执行jenkins

1、因为添加了 动态参数化构建,所以点击这个 【Build with Parameters】进行构建

在这里插入图片描述

2、点击之后,会让你修改 要通知的企业微信的人员列表,如果不修改的话,直接点击【开始构建】,如果要修改的话,请按提示的格式来即可。

在这里插入图片描述

5.2 执行完毕

发送给单个用户

在这里插入图片描述
1、当jenkins项目执行完毕之后,就会自动发送消息给企业微信
在这里插入图片描述

2、在你的企业微信中,会收到 【门户君】发送给你的消息,如下所示。
在这里插入图片描述

如上所示,ftp的地址直接打印出来了,这样就可以直接方便提测,直接复制地址即可。

发送给多个用户

配置发送给多个用户

在这里插入图片描述

编译过程中
在这里插入图片描述

多人接收到该消息

在这里插入图片描述

六、总结

使用到的技术有:Python、Shell、XML、Jenkins,大家可以了解了解!

关于使用shell脚本实现该功能的,可以参考下面的链接:


作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:https://blog.csdn.net/qq446282412/article/details/86361318
☞ 本人QQ: 3024665621
☞ QQ交流群: 123133153
github.com/ouyangpeng
oypcz@foxmail.com
如果本文对您有所帮助,欢迎您扫码下图所示的支付宝和微信支付二维码对本文进行打赏。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

字节卷动

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值