final-vibevault-template/.autograde/post_comment.py

156 lines
4.7 KiB
Python
Raw Normal View History

2025-12-01 22:12:02 +08:00
#!/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())