Skip to content

Commit e0a9919

Browse files
committed
feat(review, reply, gitlab integration): refactor code to achieve modularization, add review handle functionality, and modify reply functionality
1 parent 10aa662 commit e0a9919

File tree

12 files changed

+379
-26
lines changed

12 files changed

+379
-26
lines changed

app/gitlab_webhook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from flask import Blueprint, request, jsonify
2-
from webhook_processor.webhook_listener import webhook_listener
2+
from gitlab_integration.webhook_listener import webhook_listener
33

44
git = Blueprint('git', __name__)
55

File renamed without changes.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import requests
2+
from retrying import retry
3+
from config.config import *
4+
from utils.logger import log
5+
6+
class GitlabMergeRequestFetcher:
7+
def __init__(self, project_id, merge_request_iid):
8+
self.project_id = project_id
9+
self.iid = merge_request_iid
10+
11+
@retry(stop_max_attempt_number=3, wait_fixed=2000)
12+
def get_changes(self):
13+
"""
14+
Get the changes of the merge request
15+
:return: changes
16+
"""
17+
# URL for the GitLab API endpoint
18+
url = f"{gitlab_server_url}/api/v4/projects/{self.project_id}/merge_requests/{self.iid}/changes"
19+
20+
# Headers for the request
21+
headers = {
22+
"PRIVATE-TOKEN": gitlab_private_token
23+
}
24+
25+
# Make the GET request
26+
response = requests.get(url, headers=headers)
27+
28+
# Check if the request was successful
29+
if response.status_code == 200:
30+
return response.json()["changes"]
31+
else:
32+
return None
33+
34+
@retry(stop_max_attempt_number=3, wait_fixed=2000)
35+
def get_info(self):
36+
# URL for the GitLab API endpoint
37+
url = f"{gitlab_server_url}/api/v4/projects/{self.project_id}/merge_requests/{self.iid}"
38+
39+
# Headers for the request
40+
headers = {
41+
"PRIVATE-TOKEN": gitlab_private_token
42+
}
43+
44+
# Make the GET request
45+
response = requests.get(url, headers=headers)
46+
47+
# Check if the request was successful
48+
if response.status_code == 200:
49+
return response.json()
50+
else:
51+
return None

webhook_processor/webhook_listener.py renamed to gitlab_integration/webhook_listener.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
from flask import request, jsonify
55

6-
from app.gitlab_utils import get_merge_request_id, get_commit_change_file
6+
from app.gitlab_utils import get_merge_request_id, get_commit_change_file, get_merge_request_changes
7+
from gitlab_integration.gitlab_fetcher import GitlabMergeRequestFetcher
8+
from reply_module.reply import Reply
9+
from review_engine.review_engine import ReviewEngine
710
from service.chat_review import review_code_for_mr, review_code_for_add_commit
811
from utils.dingding import send_dingtalk_message_by_sign
912
from utils.logger import log
@@ -22,35 +25,44 @@ def handle_webhook(self):
2225
gitlab_payload = json.loads(gitlab_payload)
2326
log.info(f"🌈 :{gitlab_payload}")
2427
event_type = gitlab_payload.get('object_kind')
28+
return self.call_handle(gitlab_payload, event_type)
2529

30+
def call_handle(self, gitlab_payload, event_type):
31+
reply = Reply(gitlab_payload.get('project')['id'], gitlab_payload.get("object_attributes")["iid"])
2632
if event_type == 'merge_request':
27-
self.handle_merge_request(gitlab_payload)
33+
return self.handle_merge_request(gitlab_payload, reply)
2834
elif event_type == 'push':
29-
self.handle_push(gitlab_payload)
35+
return self.handle_push(gitlab_payload, reply)
3036
else:
31-
self.handle_other(gitlab_payload)
37+
return self.handle_other(gitlab_payload, reply)
3238

33-
def handle_merge_request(self, gitlab_payload):
39+
def handle_merge_request(self, gitlab_payload, reply):
3440
"""
3541
处理合并请求事件
3642
"""
3743
if gitlab_payload.get("object_attributes").get("state") == "opened" and gitlab_payload.get("object_attributes").get("merge_status") == "preparing":
3844
log.info("首次merge_request ", gitlab_payload)
3945
project_id = gitlab_payload.get('project')['id']
40-
merge_request_id = gitlab_payload.get("object_attributes")["iid"]
46+
merge_request_iid = gitlab_payload.get("object_attributes")["iid"]
47+
review_engine = ReviewEngine(reply)
48+
fetcher = GitlabMergeRequestFetcher(project_id, merge_request_iid)
4149

42-
thread = threading.Thread(target=review_code_for_mr, args=(project_id, merge_request_id, gitlab_payload))
50+
changes = fetcher.get_changes()
51+
info = fetcher.get_info()
52+
thread = threading.Thread(target=review_engine.handle_merge, args=(changes, info, gitlab_payload))
4353
thread.start()
4454

4555
return jsonify({'status': 'success'}), 200
56+
return jsonify({'status': 'do not need check'}), 200
4657

47-
def handle_push(self, gitlab_payload):
58+
def handle_push(self, gitlab_payload, reply):
4859
"""
4960
处理推送事件
5061
"""
5162
project_id = gitlab_payload.get('project')['id']
5263
merge_request_id = get_merge_request_id(gitlab_payload.get('ref').split("/")[-1], gitlab_payload.get("project_id"))
5364

65+
5466
if not merge_request_id:
5567
send_dingtalk_message_by_sign(
5668
f"Project_Name:{gitlab_payload['project']['name']}\n备注:分支 {gitlab_payload.get('ref')} 没有处于open状态的 Merge Request 不进行 Code Review。")
@@ -64,7 +76,7 @@ def handle_push(self, gitlab_payload):
6476

6577
return jsonify({'status': 'success'}), 200
6678

67-
def handle_other(self, gitlab_payload):
79+
def handle_other(self, gitlab_payload, reply):
6880
"""
6981
处理其他事件
7082
"""

reply_module/reply.py

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,34 @@ def __init__(self, project_id, merge_request_iid):
1010
self.project_id = project_id
1111
self.merge_request_iid = merge_request_iid
1212

13-
def add_reply(self, reply):
13+
def add_reply(self, reply_msg):
1414
# reply 格式检查:title, content 必选
15-
if 'title' not in reply or 'content' not in reply:
15+
if 'content' not in reply_msg:
1616
raise Exception('Reply format error, title and content are required.')
17-
if 'priority' in reply:
18-
if not isinstance(reply['priority'], int):
17+
if 'priority' in reply_msg:
18+
if not isinstance(reply_msg['priority'], int):
1919
raise Exception('Reply format error, priority should be an integer.')
20-
elif reply['priority'] == 0:
21-
self.send_single_message(reply)
20+
elif reply_msg['priority'] == 0:
21+
self.send_single_message(reply_msg)
2222
return
2323

2424
with self.lock: # 加锁
25-
self.replies.append(reply)
25+
self.replies.append(reply_msg)
2626

2727
def send(self):
2828
msg_list = {}
29+
main_msg = None
2930
with self.lock: # 加锁
3031
# 发送所有消息的逻辑
31-
for reply in self.replies:
32-
targets = [t.strip() for t in reply['target'].split(',')]
33-
if 'all' in targets:
34-
targets = ReplyFactory.get_all_targets()
35-
for target in targets:
36-
msg_list[target] = msg_list.get(target, '')
37-
msg_list[target] += f"## {reply['title']}\n\n{reply['content']}\n\n"
32+
for msg in self.replies:
33+
if msg['title'] == '__MAIN_REVIEW__':
34+
main_msg = msg
35+
continue
36+
self.__parse_msg(msg, msg_list)
37+
3838
self.replies = [] # 清空已发送的消息
39+
if main_msg:
40+
self.__parse_msg(main_msg, msg_list)
3941
ret = True
4042
for target, msg in msg_list.items():
4143
reply_target = ReplyFactory.get_reply_instance(target, self.project_id, self.merge_request_iid)
@@ -52,17 +54,34 @@ def send_single_message(self, reply):
5254
ret = True
5355
for target in targets:
5456
reply_target = ReplyFactory.get_reply_instance(target, self.project_id, self.merge_request_iid)
55-
ret &= reply_target.send(f"## {reply['title']}\n\n{reply['content']}\n\n")
57+
# 如果title不为__IGNORE__ or __MAIN_REVIEW__, 则发送带有标题的消息
58+
if 'title' not in reply or reply['title'] not in ['__IGNORE__', '__MAIN_REVIEW__']:
59+
ret &= reply_target.send(f"## {reply['title']}\n\n{reply['content']}\n\n")
60+
else:
61+
ret &= reply_target.send(reply['content'])
5662
return ret
5763

64+
def __parse_msg(self, msg, msg_list):
65+
targets = [t.strip() for t in msg['target'].split(',')]
66+
if 'all' in targets:
67+
targets = ReplyFactory.get_all_targets()
68+
for target in targets:
69+
msg_list[target] = msg_list.get(target, '')
70+
# 如果msg['title']不存在
71+
if 'title' not in msg or msg['title'] in ['__IGNORE__', '__MAIN_REVIEW__']:
72+
msg_list[target] = f"{msg['content']}\n\n" + msg_list[target]
73+
else:
74+
msg_list[target] += f"## {msg['title']}\n\n{msg['content']}\n\n"
75+
5876

5977
if __name__ == '__main__':
6078
reply = Reply(9885, 18)
6179
threads = []
6280
for i in range(10):
6381
threads.append(threading.Thread(target=reply.add_reply, args=(
6482
{'title': f'title{i}', 'content': f'content{i}', 'target': 'gitlab, dingtalk', 'priority': i % 3},)))
65-
83+
threads.append(threading.Thread(target=reply.add_reply, args=(
84+
{'title': '__IGNORE__', 'content': f'content{i}', 'target': 'gitlab, dingtalk', 'priority': i % 3},)))
6685
for thread in threads:
6786
thread.start()
6887
for thread in threads:

review_engine/__init__.py

Whitespace-only changes.

review_engine/handler/__init__.py

Whitespace-only changes.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import importlib
2+
import pkgutil
3+
4+
5+
6+
class ReviewHandle(object):
7+
def __init__(self):
8+
pass
9+
10+
def merge_handle(self, changes, merge_info, hook_info, reply):
11+
pass

0 commit comments

Comments
 (0)