Skip to content

Commit 775c872

Browse files
author
sunminghui
committed
优化消息通知代码
1 parent f64f4db commit 775c872

File tree

8 files changed

+151
-148
lines changed

8 files changed

+151
-148
lines changed

api.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import atexit
22
import json
33
import os
4+
import re
45
import traceback
56
from datetime import datetime
67
from multiprocessing import Process
@@ -117,16 +118,16 @@ def handle_webhook():
117118
if not gitlab_url:
118119
repository = data.get('repository')
119120
if not repository:
120-
return jsonify({'message': 'Missing GitLab URL'}), 400
121+
return jsonify({'message': 'Missing GitLab URL'}), 400
121122
homepage = repository.get("homepage")
122123
if not homepage:
123-
return jsonify({'message': 'Missing GitLab URL'}), 400
124+
return jsonify({'message': 'Missing GitLab URL'}), 400
124125
try:
125126
parsed_url = urlparse(homepage)
126127
gitlab_url = f"{parsed_url.scheme}://{parsed_url.netloc}/"
127128
except Exception as e:
128129
return jsonify({"error": f"Failed to parse homepage URL: {str(e)}"}), 400
129-
130+
130131
# 优先从环境变量获取,如果没有,则从请求头获取
131132
gitlab_token = os.getenv('GITLAB_ACCESS_TOKEN') or request.headers.get('X-Gitlab-Token')
132133
# 如果gitlab_token为空,返回错误
@@ -143,34 +144,40 @@ def handle_webhook():
143144
process = Process(target=__handle_merge_request_event, args=(data, gitlab_token, gitlab_url))
144145
process.start()
145146
# 立马返回响应
146-
return jsonify({'message': f'Request received(object_kind={object_kind}), will process asynchronously.'}), 200
147+
return jsonify(
148+
{'message': f'Request received(object_kind={object_kind}), will process asynchronously.'}), 200
147149
elif object_kind == "push":
148150
# 创建一个新进程进行异步处理
149151
process = Process(target=__handle_push_event, args=(data, gitlab_token, gitlab_url))
150152
process.start()
151153
# 立马返回响应
152-
return jsonify({'message': f'Request received(object_kind={object_kind}), will process asynchronously.'}), 200
154+
return jsonify(
155+
{'message': f'Request received(object_kind={object_kind}), will process asynchronously.'}), 200
153156
else:
154157
error_message = f'Only merge_request and push events are supported (both Webhook and System Hook), but received: {object_kind}.'
155158
logger.error(error_message)
156159
return jsonify(error_message), 400
157160
else:
158161
return jsonify({'message': 'Invalid data format'}), 400
159162

160-
def transform_gitlab_url(url):
161-
# 去掉 http:// 或 https://
162-
if url.startswith("http://"):
163-
url = url[len("http://"):]
164-
elif url.startswith("https://"):
165-
url = url[len("https://"):]
166-
167-
if url.endswith('/'):
168-
url = url[:-1]
169-
170-
# 替换 . 和 / 为 _
171-
transformed_url = url.replace('.', '_').replace('/', '_')
172-
173-
return transformed_url
163+
164+
def slugify_url(original_url: str) -> str:
165+
"""
166+
将原始URL转换为适合作为文件名的字符串,其中非字母或数字的字符会被替换为下划线,举例:
167+
slugify_url("http://example.com/path/to/repo/") => example_com_path_to_repo
168+
slugify_url("https://gitlab.com/user/repo.git") => gitlab_com_user_repo_git
169+
"""
170+
# Remove URL scheme (http, https, etc.) if present
171+
original_url = re.sub(r'^https?://', '', original_url)
172+
173+
# Replace non-alphanumeric characters (except underscore) with underscores
174+
target = re.sub(r'[^a-zA-Z0-9]', '_', original_url)
175+
176+
# Remove trailing underscore if present
177+
target = target.rstrip('_')
178+
179+
return target
180+
174181

175182
def __handle_push_event(webhook_data: dict, gitlab_token: str, gitlab_url: str):
176183
try:
@@ -200,7 +207,6 @@ def __handle_push_event(webhook_data: dict, gitlab_token: str, gitlab_url: str):
200207
# 将review结果提交到Gitlab的 notes
201208
handler.add_push_notes(f'Auto Review Result: \n{review_result}')
202209

203-
url_base = transform_gitlab_url(gitlab_url)
204210

205211
event_manager['push_reviewed'].send(PushReviewEntity(
206212
project_name=webhook_data['project']['name'],
@@ -210,7 +216,7 @@ def __handle_push_event(webhook_data: dict, gitlab_token: str, gitlab_url: str):
210216
commits=commits,
211217
score=score,
212218
review_result=review_result,
213-
gitlab_url = url_base,
219+
gitlab_url_slug = slugify_url(gitlab_url),
214220
))
215221

216222
except Exception as e:
@@ -258,7 +264,6 @@ def __handle_merge_request_event(webhook_data: dict, gitlab_token: str, gitlab_u
258264
# 将review结果提交到Gitlab的 notes
259265
handler.add_merge_request_notes(f'Auto Review Result: \n{review_result}')
260266

261-
url_base = transform_gitlab_url(gitlab_url)
262267
# dispatch merge_request_reviewed event
263268
event_manager['merge_request_reviewed'].send(
264269
MergeRequestReviewEntity(
@@ -271,7 +276,7 @@ def __handle_merge_request_event(webhook_data: dict, gitlab_token: str, gitlab_u
271276
score=CodeReviewer.parse_review_score(review_text=review_result),
272277
url=webhook_data['object_attributes']['url'],
273278
review_result=review_result,
274-
gitlab_url = url_base,
279+
gitlab_url_slug = slugify_url(gitlab_url),
275280
)
276281
)
277282

@@ -283,6 +288,7 @@ def __handle_merge_request_event(webhook_data: dict, gitlab_token: str, gitlab_u
283288
im_notifier.send_notification(content=error_message)
284289
logger.error('出现未知错误: %s', error_message)
285290

291+
286292
def filter_changes(changes: list):
287293
'''
288294
过滤数据,只保留支持的文件类型以及必要的字段信息

biz/entity/review_entity.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class MergeRequestReviewEntity:
22
def __init__(self, project_name: str, author: str, source_branch: str, target_branch: str, updated_at: int,
3-
commits: list, score: float, url: str, review_result: str, gitlab_url: str):
3+
commits: list, score: float, url: str, review_result: str, gitlab_url_slug: str):
44
self.project_name = project_name
55
self.author = author
66
self.source_branch = source_branch
@@ -10,7 +10,7 @@ def __init__(self, project_name: str, author: str, source_branch: str, target_br
1010
self.score = score
1111
self.url = url
1212
self.review_result = review_result
13-
self.gitlab_url = gitlab_url
13+
self.gitlab_url_slug = gitlab_url_slug
1414

1515
@property
1616
def commit_messages(self):
@@ -20,15 +20,15 @@ def commit_messages(self):
2020

2121
class PushReviewEntity:
2222
def __init__(self, project_name: str, author: str, branch: str, updated_at: int, commits: list, score: float,
23-
review_result: str, gitlab_url: str):
23+
review_result: str, gitlab_url_slug: str):
2424
self.project_name = project_name
2525
self.author = author
2626
self.branch = branch
2727
self.updated_at = updated_at
2828
self.commits = commits
2929
self.score = score
3030
self.review_result = review_result
31-
self.gitlab_url = gitlab_url
31+
self.gitlab_url_slug = gitlab_url_slug
3232

3333
@property
3434
def commit_messages(self):

biz/event/event_manager.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def on_merge_request_reviewed(mr_review_entity: MergeRequestReviewEntity):
3232
{mr_review_entity.review_result}
3333
"""
3434
im_notifier.send_notification(content=im_msg, msg_type='markdown', title='Merge Request Review',
35-
project_name=mr_review_entity.project_name, url_base=mr_review_entity.gitlab_url)
35+
project_name=mr_review_entity.project_name,
36+
gitlab_url_slug=mr_review_entity.gitlab_url_slug)
3637

3738
# 记录到数据库
3839
ReviewService().insert_mr_review_log(mr_review_entity)
@@ -58,7 +59,8 @@ def on_push_reviewed(entity: PushReviewEntity):
5859
if entity.review_result:
5960
im_msg += f"#### AI Review 结果: \n {entity.review_result}\n\n"
6061
im_notifier.send_notification(content=im_msg, msg_type='markdown',
61-
title=f"{entity.project_name} Push Event", project_name=entity.project_name, url_base=entity.gitlab_url)
62+
title=f"{entity.project_name} Push Event", project_name=entity.project_name,
63+
gitlab_url_slug=entity.gitlab_url_slug)
6264

6365
# 记录到数据库
6466
ReviewService().insert_push_review_log(entity)

biz/utils/im/dingtalk.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ def __init__(self, webhook_url=None):
1616
self.enabled = os.environ.get('DINGTALK_ENABLED', '0') == '1'
1717
self.default_webhook_url = webhook_url or os.environ.get('DINGTALK_WEBHOOK_URL')
1818

19-
def _get_webhook_url(self, project_name=None, url_base=None):
19+
def _get_webhook_url(self, project_name=None, gitlab_url_slug=None):
2020
"""
2121
获取项目对应的 Webhook URL
2222
:param project_name: 项目名称
23+
:param gitlab_url_slug: 由 gitlab 项目的 url 转换而来的 slug
2324
:return: Webhook URL
2425
:raises ValueError: 如果未找到 Webhook URL
2526
"""
@@ -30,17 +31,17 @@ def _get_webhook_url(self, project_name=None, url_base=None):
3031
else:
3132
raise ValueError("未提供项目名称,且未设置默认的钉钉 Webhook URL。")
3233

33-
# 遍历所有环境变量(忽略大小写),找到项目对应的 Webhook URL
34-
target_key = f"DINGTALK_WEBHOOK_URL_{project_name.upper()}"
35-
for env_key, env_value in os.environ.items():
36-
if env_key.upper() == target_key:
37-
return env_value # 找到匹配项,直接返回
38-
39-
# url_base 优先级次之
40-
target_key_url_base = f"WECOM_WEBHOOK_URL_{url_base.upper()}"
34+
# 构造目标键
35+
target_key_project = f"DINGTALK_WEBHOOK_URL_{project_name.upper()}"
36+
target_key_url_slug = f"DINGTALK_WEBHOOK_URL_{gitlab_url_slug.upper()}"
37+
38+
# 遍历环境变量
4139
for env_key, env_value in os.environ.items():
42-
if target_key_url_base !=None and env_key.upper() == target_key_url_base:
43-
return env_value # 找到匹配项,直接返回
40+
env_key_upper = env_key.upper()
41+
if env_key_upper == target_key_project:
42+
return env_value # 找到项目名称对应的 Webhook URL,直接返回
43+
if env_key_upper == target_key_url_slug:
44+
return env_value # 找到 GitLab URL 对应的 Webhook URL,直接返回
4445

4546
# 如果未找到匹配的环境变量,降级使用全局的 Webhook URL
4647
if self.default_webhook_url:
@@ -49,13 +50,13 @@ def _get_webhook_url(self, project_name=None, url_base=None):
4950
# 如果既未找到匹配项,也没有默认值,抛出异常
5051
raise ValueError(f"未找到项目 '{project_name}' 对应的钉钉Webhook URL,且未设置默认的 Webhook URL。")
5152

52-
def send_message(self, content: str, msg_type='text', title='通知', is_at_all=False, project_name=None, url_base = None):
53+
def send_message(self, content: str, msg_type='text', title='通知', is_at_all=False, project_name=None, gitlab_url_slug = None):
5354
if not self.enabled:
5455
logger.info("钉钉推送未启用")
5556
return
5657

5758
try:
58-
post_url = self._get_webhook_url(project_name=project_name, url_base=url_base)
59+
post_url = self._get_webhook_url(project_name=project_name, gitlab_url_slug=gitlab_url_slug)
5960
headers = {
6061
"Content-Type": "application/json",
6162
"Charset": "UTF-8"

biz/utils/im/feishu.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def __init__(self, webhook_url=None):
1414
self.default_webhook_url = webhook_url or os.environ.get('FEISHU_WEBHOOK_URL', '')
1515
self.enabled = os.environ.get('FEISHU_ENABLED', '0') == '1'
1616

17-
def _get_webhook_url(self, project_name=None, url_base=None):
17+
def _get_webhook_url(self, project_name=None, gitlab_url_slug=None):
1818
"""
1919
获取项目对应的 Webhook URL
2020
:param project_name: 项目名称
@@ -28,17 +28,17 @@ def _get_webhook_url(self, project_name=None, url_base=None):
2828
else:
2929
raise ValueError("未提供项目名称,且未设置默认的 飞书 Webhook URL。")
3030

31-
# 遍历所有环境变量(忽略大小写),找到项目对应的 Webhook URL
32-
target_key = f"FEISHU_WEBHOOK_URL_{project_name.upper()}"
33-
for env_key, env_value in os.environ.items():
34-
if env_key.upper() == target_key:
35-
return env_value # 找到匹配项,直接返回
36-
37-
# url_base 优先级次之
38-
target_key_url_base = f"WECOM_WEBHOOK_URL_{url_base.upper()}"
31+
# 构造目标键
32+
target_key_project = f"FEISHU_WEBHOOK_URL_{project_name.upper()}"
33+
target_key_url_slug = f"FEISHU_WEBHOOK_URL_{gitlab_url_slug.upper()}"
34+
35+
# 遍历环境变量
3936
for env_key, env_value in os.environ.items():
40-
if target_key_url_base !=None and env_key.upper() == target_key_url_base:
41-
return env_value # 找到匹配项,直接返回
37+
env_key_upper = env_key.upper()
38+
if env_key_upper == target_key_project:
39+
return env_value # 找到项目名称对应的 Webhook URL,直接返回
40+
if env_key_upper == target_key_url_slug:
41+
return env_value # 找到 GitLab URL 对应的 Webhook URL,直接返回
4242

4343
# 如果未找到匹配的环境变量,降级使用全局的 Webhook URL
4444
if self.default_webhook_url:
@@ -47,7 +47,7 @@ def _get_webhook_url(self, project_name=None, url_base=None):
4747
# 如果既未找到匹配项,也没有默认值,抛出异常
4848
raise ValueError(f"未找到项目 '{project_name}' 对应的 Feishu Webhook URL,且未设置默认的 Webhook URL。")
4949

50-
def send_message(self, content, msg_type='text', title=None, is_at_all=False, project_name=None, url_base=None):
50+
def send_message(self, content, msg_type='text', title=None, is_at_all=False, project_name=None, gitlab_url_slug=None):
5151
"""
5252
发送飞书消息
5353
:param content: 消息内容
@@ -61,7 +61,7 @@ def send_message(self, content, msg_type='text', title=None, is_at_all=False, pr
6161
return
6262

6363
try:
64-
post_url = self._get_webhook_url(project_name=project_name, url_base=url_base)
64+
post_url = self._get_webhook_url(project_name=project_name, gitlab_url_slug=gitlab_url_slug)
6565
if msg_type == 'markdown':
6666
data = {
6767
"msg_type": "interactive",

biz/utils/im/im_notifier.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,26 @@
33
from biz.utils.im.wecom import WeComNotifier
44

55

6-
def send_notification(content, msg_type='text', title="通知", is_at_all=False, project_name=None, url_base=None):
6+
def send_notification(content, msg_type='text', title="通知", is_at_all=False, project_name=None, gitlab_url_slug=None):
77
"""
88
发送通知消息到配置的平台(钉钉和企业微信)
99
:param content: 消息内容
1010
:param msg_type: 消息类型,支持text和markdown
1111
:param title: 消息标题(markdown类型时使用)
1212
:param is_at_all: 是否@所有人
13-
:param url_base: gitlab服务器的url地址 http://www.gitlab.com 传递进来自动移除http和https,转换成 www_gitlab_com
13+
:param gitlab_url_slug: 由gitlab服务器的url地址(如:http://www.gitlab.com)转换成的slug格式,如: www_gitlab_com
1414
"""
1515
# 钉钉推送
1616
notifier = DingTalkNotifier()
1717
notifier.send_message(content=content, msg_type=msg_type, title=title, is_at_all=is_at_all,
18-
project_name=project_name, url_base=url_base)
18+
project_name=project_name, gitlab_url_slug=gitlab_url_slug)
1919

2020
# 企业微信推送
2121
wecom_notifier = WeComNotifier()
2222
wecom_notifier.send_message(content=content, msg_type=msg_type, title=title, is_at_all=is_at_all,
23-
project_name=project_name, url_base=url_base)
23+
project_name=project_name, gitlab_url_slug=gitlab_url_slug)
2424

2525
# 飞书推送
2626
feishu_notifier = FeishuNotifier()
2727
feishu_notifier.send_message(content=content, msg_type=msg_type, title=title, is_at_all=is_at_all,
28-
project_name=project_name, url_base=url_base)
28+
project_name=project_name, gitlab_url_slug=gitlab_url_slug)

0 commit comments

Comments
 (0)