1 Webhook
Webhook是一种基于HTTP的回调函数,可在两个应用编程接口(API)之间实现轻量级的事件驱动通信。客户端向服务器API提供唯一URL,并指定它想要知道的事件。设置webhook后,客户端不再需要轮询服务器;发生指定的事件时,服务器会自动将相关的有效负载发送到客户端的Webhook URL。
Webhook可以是实现自动化的重要一环,而且实现简单(仅一次http请求,可以嵌到任何地方),国内飞书、钉钉和企业微信等都支持Webhook推送消息。
以上是好处,那么坏处就是http请求的参数不统一,就是因为它太简单了,没有协议规范,一个平台一个样,比如在某平台上消息叫做"msg",在其它平台可能就是"message"或"text"。因而想要真正发挥Webhook的作用,需要搭建一个自己的Webhook解析处理服务,好在这并不复杂。本文将以Github Webhook为例,基于Flask进行解析并推送到企业微信。
然而,如果您没有高度自定义的需求,且仅想使用Github Webhook而不使用其它平台的,可以使用Dingling,它可以将GIthub Webhook转发到企业微信。DIngling只支能推送Markdown格式的消息(不能在微信中直接查看)是我放弃它的原因。
2 CloudFlare Webhook
CloudFlare Webhook 的消息体非常简单,如下:
1
|
{"text":"CloudFlare简直是业界良心!"}
|
使用Flask解析,并将消息转发到企业微信:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
from flask import Flask, request, jsonify,abort
import requests
from config import config
app = Flask(__name__)
@app.route('/cloudflare', methods=['POST'])
def cloudflare():
if request.method == 'POST':
print(request.json)
text = request.json['text']
data = {
"msgtype": "text",
"text": {
"content": text
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_3'], json=data)
print(r.json())
return 'success', 200
else:
abort(400)
if __name__ == '__main__':
app.run(port=5700,host='0.0.0.0',debug=True)
|
将Flask进程部署到服务器上,并在Cloudflare上填写地址,如下图
保存并测试之后,应该就能在企业微信中收到一条简短的测试消息了。
3 Github Webhook
如果说CloudFlare的Webhook是一条简短的消息,那么Github恨不得把整个网站的信息全都传给你,参数有几十个,但是没有一句是自然语言,因而需要根据自己的需求解析。下段代码的逻辑是先判断事件类型,再根据事件类型提取需要的信息转发出去。下面解析的内容包括push,release,issue,pull等行为。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
@app.route('/github', methods=['POST'])
def github():
githubEvent = request.headers['x-github-event']
if githubEvent == 'push':
respority = request.json['repository']['name']
branch = request.json['ref'].split('/')[-1]
commits = request.json['commits']
for commit in commits:
author = commit['author']['name']
message = commit['message']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人提交了代码\n分支:{branch}\n作者:{author}\n提交信息:{message}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
return 'success', 200
if githubEvent == 'issues':
action = request.json['action']
if action == 'opened':
respority = request.json['repository']['name']
issue = request.json['issue']
title = issue['title']
body = issue['body']
user = issue['user']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人提交了 issue\n标题:{title}\n内容:{body}\n提交者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
if action == 'closed':
respority = request.json['repository']['name']
issue = request.json['issue']
title = issue['title']
body = issue['body']
user = issue['user']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人关闭了 issue\n标题:{title}\n内容:{body}\n提交者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
if action == 'reopened':
respority = request.json['repository']['name']
issue = request.json['issue']
title = issue['title']
body = issue['body']
user = issue['user']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人重新打开了 issue\n标题:{title}\n内容:{body}\n提交者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
return 'success', 200
if githubEvent == 'pull_request':
action = request.json['action']
if action == 'opened':
respority = request.json['repository']['name']
pull_request = request.json['pull_request']
title = pull_request['title']
body = pull_request['body']
user = pull_request['user']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人提交了 pull request\n标题:{title}\n内容:{body}\n提交者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
if action == 'closed':
respority = request.json['repository']['name']
pull_request = request.json['pull_request']
title = pull_request['title']
body = pull_request['body']
user = pull_request['user']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人关闭了 pull request\n标题:{title}\n内容:{body}\n提交者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
if action == 'reopened':
respority = request.json['repository']['name']
pull_request = request.json['pull_request']
title = pull_request['title']
body = pull_request['body']
user = pull_request['user']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人重新打开了 pull request\n标题:{title}\n内容:{body}\n提交者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
return 'success', 200
if githubEvent == 'release':
action = request.json['action']
if action == 'published':
respority = request.json['repository']['name']
release = request.json['release']
tag_name = release['tag_name']
body = release['body']
user = release['author']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人发布了 release\n版本:{tag_name}\n内容:{body}\n发布者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
return 'success', 200
if githubEvent == 'ping':
data = {
"msgtype": "text",
"text": {
"content": "github webhook test"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'], json=data)
return 'success', 200
if githubEvent == 'create':
ref_type = request.json['ref_type']
if ref_type == 'branch':
respority = request.json['repository']['name']
branch = request.json['ref']
user = request.json['sender']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人创建了分支\n分支:{branch}\n创建者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
json=data)
if ref_type == 'tag':
respority = request.json['repository']['name']
tag = request.json['ref']
user = request.json['sender']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人创建了 tag\ntag:{tag}\n创建者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
json=data)
return 'success', 200
if githubEvent == 'delete':
ref_type = request.json['ref_type']
if ref_type == 'branch':
respority = request.json['repository']['name']
branch = request.json['ref']
user = request.json['sender']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人删除了分支\n分支:{branch}\n删除者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
json=data)
if ref_type == 'tag':
respority = request.json['repository']['name']
tag = request.json['ref']
user = request.json['sender']['login']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人删除了 tag\ntag:{tag}\n删除者:{user}"
}
}
r = requests.post('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
json=data)
return 'success', 200
if githubEvent == 'pull_request_review':
action = request.json['action']
if action == 'submitted':
respority = request.json['repository']['name']
pull_request = request.json['pull_request']
title = pull_request['title']
body = pull_request['body']
user = pull_request['user']['login']
review = request.json['review']
state = review['state']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人提交了 pull request review\n标题:{title}\n内容:{body}\n提交者:{user}\n状态:{state}"
}
}
r = requests.post(
'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
json=data)
return 'success', 200
if githubEvent == 'pull_request_review_comment':
action = request.json['action']
if action == 'created':
respority = request.json['repository']['name']
pull_request = request.json['pull_request']
title = pull_request['title']
body = pull_request['body']
user = pull_request['user']['login']
comment = request.json['comment']
comment_body = comment['body']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人提交了 pull request review comment\n标题:{title}\n内容:{body}\n提交者:{user}\n内容:{comment_body}"
}
}
r = requests.post(
'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
json=data)
return 'success', 200
# if githubEvent == 'check_run':
# action = request.json['action']
# if action == 'created':
# respority = request.json['repository']['name']
# check_run = request.json['check_run']
# name = check_run['name']
# conclusion = check_run['conclusion']
# data = {
# "msgtype": "text",
# "text": {
# "content": f"{respority} 有人提交了 check run\n名称:{name}\n状态:{conclusion}"
# }
# }
# r = requests.post(
# 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
# json=data)
# return 'success', 200
if githubEvent == 'check_suite':
action = request.json['action']
if action == 'completed':
respority = request.json['repository']['name']
check_suite = request.json['check_suite']
conclusion = check_suite['conclusion']
data = {
"msgtype": "text",
"text": {
"content": f"{respority} 有人提交了 check suite\n状态:{conclusion}"
}
}
r = requests.post(
'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='+config['API_KEY_2'],
json=data)
return 'success', 200
|
配置好服务端和Github,可在历史记录中查看详细的推送信息。
4 参考文档
Github官方文档