最近公司将RTX更新为了企业微信,并且准备将之前的OA邮箱之类的都废弃掉了。而之前我们的Jenkins编译结果都是通过发送到OA邮箱来进行通知的,因此后面OA邮箱被废弃掉的话,那么我们就无法收到Jenkins的编译结果了。
因此我们得想其他办法来通知相关人员关于Jenkins的编译结果。和公司负责企业微信推广的同事聊了聊之后,发现可以通过企业微信提供的api来进行开发,然后实现将Jenkins的编译结果通过企业微信来发送消息。
在腾讯,能够看到的信息如下
- 企业微信api(https://work.weixin.qq.com/api/doc#90000/90003/90556)
- 微信企业号开发者中心(https://qydev.weixin.qq.com/wiki/index.php?title=消息类型及数据格式)
没有更多的消息,企业微信发消息的api和微信企业号发送的有点类似,大致看下即可。
公司负责企业微信推广的同事对企业微信发送消息的api进行了再次封装,然后发送了一篇api文档给我,大致如下:
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"
}
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":"更多"
}
]
}
}
POST: http://ip地址:8000/api/wechat/text
{
"toUser" : "工号1|工号2....",
"agentId" : 0,
"content":"xxxxxx"
}
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脚本和一个jenkins账号和企业微信工号的配置文件,如下所示
上面的python脚本在执行的时候,会将Jenkins账户转换为企业微信的工号,这个转换过程是通过读取Jenkins账户对应的企业微信的工号映射表jenkins_users.xml来进行的。
jenkins_users.xml的格式如下:
欧阳鹏
000001
员工2
000002
员工3
000003
员工4
000004
员工4
000005
#!/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脚本进行调用,具体怎么调用,继续看下面的内容。
【构建环境】中 勾选【Set jenkins user build variables】,不然jenkins的环境变量无法读取
在【General】中,添加一个【参数构建化过程】,增加一个参数,如下所示:
参数名
参数名为 WEICHAT_RECEIVERS,
默认值
默认值为要发送给企业微信的人员列表,
可以是一个列表,用 | 分隔符分开即可,比如
员工1|员工2|员工3|员工4|欧阳鹏|员工5|员工6|员工7
也可以只写一个人,比如欧阳鹏
要发送给企业微信的人员列表
如下图所示,在 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}
【构建后操作】–>【Editable Email Notification】 然后点击右上角的 红色叉号,直接删除邮件发送模块
【构建后操作】–>【Send build artifacts over FTP 】
配置地址为 下面的内容,因为脚本中是读取这个地址的
AndroidPhone/${JOB_NAME}/'yyyy-MM-dd-HH-mm-ss-'git-${GIT_COMMIT}-build-${BUILD_NUMBER}
1、因为添加了 动态参数化构建,所以点击这个 【Build with Parameters】进行构建
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
☞ [email protected]
如果本文对您有所帮助,欢迎您扫码下图所示的支付宝和微信支付二维码对本文进行打赏。