156 lines
4.7 KiB
Python
156 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
发送评论到 Gitea PR
|
||
|
||
从环境变量读取配置,发送评论到指定的 PR
|
||
支持在 Markdown 评论中嵌入 JSON 数据,便于后续结构化提取
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import json
|
||
import requests
|
||
from datetime import datetime
|
||
|
||
|
||
def create_comment_with_metadata(summary, commit_sha, comment_type='grade', metadata=None):
|
||
"""
|
||
创建包含元数据的评论内容
|
||
|
||
Parameters
|
||
----------
|
||
summary : str
|
||
人类可读的 Markdown 格式总结
|
||
commit_sha : str
|
||
提交 SHA
|
||
comment_type : str
|
||
评论类型 ('grade', 'llm', 'combined')
|
||
metadata : dict, optional
|
||
结构化的成绩数据,将嵌入为 JSON
|
||
|
||
Returns
|
||
-------
|
||
str
|
||
完整的评论内容(Markdown + JSON)
|
||
"""
|
||
commit_short = commit_sha[:7] if commit_sha else 'unknown'
|
||
|
||
# 根据类型设置标题和图标
|
||
if comment_type == 'llm':
|
||
title = "🤖 LLM 简答题评分结果"
|
||
footer = "*此评论由 Gitea Actions 自动生成(使用 DeepSeek API) | Commit: `{}`*"
|
||
elif comment_type == 'combined':
|
||
title = "📊 综合评分结果"
|
||
footer = "*此评论由 Gitea Actions 自动生成 | Commit: `{}`*"
|
||
else:
|
||
title = "🤖 自动评分结果"
|
||
footer = "*此评论由 Gitea Actions 自动生成 | Commit: `{}`*"
|
||
|
||
# 构建评论
|
||
parts = [
|
||
f"## {title}",
|
||
"",
|
||
summary,
|
||
""
|
||
]
|
||
|
||
# 如果提供了元数据,嵌入 JSON
|
||
if metadata:
|
||
# 确保元数据包含版本和时间戳
|
||
if 'version' not in metadata:
|
||
metadata['version'] = '1.0'
|
||
if 'timestamp' not in metadata:
|
||
metadata['timestamp'] = datetime.now().isoformat()
|
||
|
||
# 使用 Markdown 代码块嵌入 JSON(更可靠,Gitea 会保留)
|
||
# 放在评论末尾,对学生不太显眼
|
||
json_str = json.dumps(metadata, ensure_ascii=False, indent=2)
|
||
parts.extend([
|
||
"",
|
||
"---",
|
||
"",
|
||
"<!-- GRADE_METADATA -->",
|
||
"```json",
|
||
json_str,
|
||
"```",
|
||
""
|
||
])
|
||
|
||
parts.extend([
|
||
footer.format(commit_short)
|
||
])
|
||
|
||
return "\n".join(parts)
|
||
|
||
|
||
def main():
|
||
# 从环境变量读取配置
|
||
api_url = os.environ.get('API_URL', '')
|
||
repo = os.environ.get('REPO', '')
|
||
pr_number = os.environ.get('PR_NUMBER', '')
|
||
token = os.environ.get('GITEA_TOKEN', '')
|
||
summary = os.environ.get('SUMMARY', '')
|
||
commit_sha = os.environ.get('COMMIT_SHA', '')
|
||
comment_type = os.environ.get('COMMENT_TYPE', 'grade')
|
||
|
||
# 可选:从环境变量读取 JSON 元数据
|
||
metadata_str = os.environ.get('GRADE_METADATA', '')
|
||
metadata = None
|
||
if metadata_str:
|
||
try:
|
||
metadata = json.loads(metadata_str)
|
||
except json.JSONDecodeError as e:
|
||
print(f"Warning: Failed to parse GRADE_METADATA: {e}", file=sys.stderr)
|
||
|
||
# 验证必需参数
|
||
if not all([api_url, repo, pr_number, token, summary]):
|
||
print("Error: Missing required environment variables", file=sys.stderr)
|
||
print(f"API_URL: {api_url}", file=sys.stderr)
|
||
print(f"REPO: {repo}", file=sys.stderr)
|
||
print(f"PR_NUMBER: {pr_number}", file=sys.stderr)
|
||
print(f"GITEA_TOKEN: {'set' if token else 'not set'}", file=sys.stderr)
|
||
print(f"SUMMARY: {'set' if summary else 'not set'}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
# 构建评论内容(包含元数据)
|
||
comment_body = create_comment_with_metadata(
|
||
summary=summary,
|
||
commit_sha=commit_sha,
|
||
comment_type=comment_type,
|
||
metadata=metadata
|
||
)
|
||
|
||
# 构建 API URL
|
||
comment_url = f"{api_url}/repos/{repo}/issues/{pr_number}/comments"
|
||
|
||
# 发送请求
|
||
headers = {
|
||
"Authorization": f"token {token}",
|
||
"Content-Type": "application/json"
|
||
}
|
||
|
||
data = {"body": comment_body}
|
||
|
||
try:
|
||
print(f"Posting comment to: {comment_url}")
|
||
if metadata:
|
||
print("✓ Comment includes structured metadata")
|
||
response = requests.post(comment_url, headers=headers, json=data, timeout=30)
|
||
response.raise_for_status()
|
||
print("✅ Comment posted successfully to PR")
|
||
return 0
|
||
except requests.exceptions.Timeout:
|
||
print("⚠️ Request timeout", file=sys.stderr)
|
||
return 1
|
||
except requests.exceptions.HTTPError as e:
|
||
print(f"⚠️ HTTP error: {e}", file=sys.stderr)
|
||
print(f"Response: {response.text}", file=sys.stderr)
|
||
return 1
|
||
except Exception as e:
|
||
print(f"⚠️ Failed to post comment: {e}", file=sys.stderr)
|
||
return 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|