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

一、需求描述

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

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

二、了解企业微信的api

2.1 api相关参考资料

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

  • 企业微信api(https://work.weixin.qq.com/api/doc#90000/90003/90556)
  • 微信企业号开发者中心(https://qydev.weixin.qq.com/wiki/index.php?title=消息类型及数据格式)

没有更多的消息,企业微信发消息的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" : "
2016年9月26日
恭喜你抽中iPhone 7一台,领奖码:xxxx
请于2016年10月10日前联系行政同事领取
"
, "url":"http://www.baidu.com", "btntxt":"更多" }

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

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

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

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

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

jenkins_users.xml的格式如下:



    
        欧阳鹏
        000001
    
    
        员工2
        000002
    
    
        员工3
        000003
    
    
        员工4
        000004
    
    
        员工4
        000005
    

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" : "
2016年9月26日
恭喜你抽中iPhone 7一台,领奖码:xxxx
请于2016年10月10日前联系行政同事领取
", "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 = """
  • %(TITLE)s
  • 构建信息
  • ------------------------
  • %(TIME)s
  • ------------------------
  • 用户名 :%(USER)s
  • 任务名 :%(PROJECT_NAME)s
  • 分支名 :%(GIT_BRANCH)s
  • 构建编号 :第%(BUILD_NUMBER)s次构建
  • GIT SHA1 :%(GIT_COMMIT)s
  • 构建日志 :%(BUILD_URL)sconsole
  • FTP归档地址如下所示:(用户名:xxxx 密码:xxxx)
  • ftp://ftp的ip地址/project/AndroidPhone/%(PROJECT_NAME)s/%(FTP_TIME)s-git-%(GIT_COMMIT)s-build-%(BUILD_NUMBER)s
  • 静态代码分析报告
  • Android Lint 报告 : %(BUILD_URL)sandroidLintResult
  • FindBugs 报告 :%(BUILD_URL)sfindbugsResult
  • 发送企业微信信息给 :%(WEICHAT_RECEIVERS)s
  • """
    % 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的环境变量无法读取

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

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

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

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

    • 参数名
      参数名为 WEICHAT_RECEIVERS,

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

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

    • 描述

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

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

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

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

    # 进入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】 然后点击右上角的 红色叉号,直接删除邮件发送模块
    【Jenkins学习 】如何编写Python脚本来调用企业微信的api通知企业微信成员关于Jenkins的编译结果?_第5张图片

    4.5 配置FTP地址

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

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

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

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

    五、执行Jenkins任务

    5.1 执行jenkins

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

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

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

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

    5.2 执行完毕

    发送给单个用户

    【Jenkins学习 】如何编写Python脚本来调用企业微信的api通知企业微信成员关于Jenkins的编译结果?_第9张图片
    1、当jenkins项目执行完毕之后,就会自动发送消息给企业微信
    【Jenkins学习 】如何编写Python脚本来调用企业微信的api通知企业微信成员关于Jenkins的编译结果?_第10张图片

    2、在你的企业微信中,会收到 【门户君】发送给你的消息,如下所示。
    【Jenkins学习 】如何编写Python脚本来调用企业微信的api通知企业微信成员关于Jenkins的编译结果?_第11张图片

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

    发送给多个用户

    配置发送给多个用户

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

    编译过程中
    【Jenkins学习 】如何编写Python脚本来调用企业微信的api通知企业微信成员关于Jenkins的编译结果?_第13张图片

    多人接收到该消息

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

    六、总结

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

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

    • 【Linux学习】如何编写Shell脚本调用企业微信api来发消息给企业微信成员?
      https://blog.csdn.net/qq446282412/article/details/86495251

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


    你可能感兴趣的:(#,Jenkins,#,Python学习进阶之旅,jenkins,python,企业微信,jenkins,python,企业微信,shell)