Files
ewoooc/scripts/code_review.py
ogt a96306fba2 Fix Telegram bot natural language communication issue
- Install python-telegram-bot dependency
- Start Telegram bot service successfully
- Confirm correct group ID (MOMO PRO - small shrimp group)
- Bot now running with all commands and button interface functional
- Natural language processing restored with keyword matching

Fixes issue where Telegram group could not communicate using natural language.
2026-04-22 14:27:50 +08:00

301 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# ================= MOMO 系統 - Aider Code Review 自動化腳本 =================
# 功能:程式完成後自動觸發 Aider 進行 Code Review
# 作者AI Assistant
# 版本1.0
# =======================================================================
import argparse
import os
import subprocess
import sys
from datetime import datetime
from pathlib import Path
# 導入工具類
try:
from scripts.code_review_utils import CodeReviewLogger, CodeReviewConfig, CodeReviewValidator, GitHelper
except ImportError:
# 嘗試直接導入當在scripts目錄中執行時
try:
from code_review_utils import CodeReviewLogger, CodeReviewConfig, CodeReviewValidator, GitHelper
except ImportError:
print("❌ 無法導入工具類,請確保 code_review_utils.py 存在")
sys.exit(1)
class AiderCodeReview:
def __init__(self, project_root=None):
self.project_root = Path(project_root) if project_root else Path(__file__).parent.parent
# 初始化工具類
self.logger = CodeReviewLogger(self.project_root)
self.config = CodeReviewConfig(self.project_root)
self.validator = CodeReviewValidator()
self.git_helper = GitHelper(self.project_root)
# 檢查Git倉庫
if not self.git_helper.is_git_repository():
self.logger.warning("當前目錄不是Git倉庫某些功能可能無法使用")
# 檢查Aider路徑
self.aider_path = self.config.get("aider.path", "/Users/ooo/.local/bin/aider")
if not Path(self.aider_path).exists():
self.logger.error(f"Aider 路徑不存在: {self.aider_path}")
def log_review(self, message):
"""記錄Code Review日誌保持向後兼容"""
self.logger.info(message)
def get_changed_files(self, git_diff_filter="ACM"):
"""獲取Git中變更的檔案"""
try:
# 使用GitHelper獲取變更檔案
all_changed = self.git_helper.get_changed_files(
diff_filter=git_diff_filter,
use_staged=self.config.get("git.use_staged", True)
)
# 過滤允許的檔案類型
allowed_extensions = self.config.get("file_filters.allowed_extensions",
['.py', '.js', '.ts', '.jsx', '.tsx', '.html', '.css'])
filtered_files = []
for file_path in all_changed:
if any(file_path.endswith(ext) for ext in allowed_extensions):
# 檢查檔案是否存在且大小合理
abs_path = self.project_root / file_path
if abs_path.exists() and abs_path.is_file():
file_size = abs_path.stat().st_size
max_size = self.config.get("file_filters.max_file_size", 10485760)
if file_size <= max_size:
filtered_files.append(file_path)
else:
self.logger.warning(f"檔案過大,跳過: {file_path} ({file_size} bytes)")
else:
self.logger.warning(f"檔案不存在,跳過: {file_path}")
return filtered_files
except Exception as e:
self.logger.error("獲取變更檔案失敗", e)
return []
def run_aider_review(self, files=None, review_type="basic"):
"""執行Aider Code Review"""
if not files:
files = self.get_changed_files()
if not files:
self.log_review("📝 沒有需要Review的檔案")
return True
# 驗證Review類型
if not self.validator.validate_review_type(review_type):
self.logger.error(f"無效的Review類型: {review_type}")
return False
# 驗證檔案
valid_files = self.validator.validate_files(files, self.project_root)
if not valid_files:
self.logger.error("沒有有效的檔案可以Review")
return False
# 構建Aider命令
cmd = [self.aider_path]
# 從配置獲取Review類型對應的訊息
review_message = self.config.get(f"review_types.{review_type}.message")
if not review_message:
self.logger.error(f"找不到Review類型 {review_type} 的配置")
return False
# 添加Aider參數
if self.config.get("aider.auto_yes", False):
cmd.append("--yes")
if self.config.get("aider.no_git", True):
cmd.append("--no-git")
cmd.extend(["--message", review_message])
# 添加要review的檔案
cmd.extend(valid_files)
self.log_review(f"🔍 開始Code Review - 類型: {review_type}, 檔案: {', '.join(valid_files)}")
try:
# 設置環境變數
env = os.environ.copy()
env["PYTHONPATH"] = str(self.project_root)
# 執行Aider
timeout = self.config.get("aider.timeout", 600)
result = subprocess.run(
cmd,
cwd=self.project_root,
capture_output=True,
text=True,
env=env,
timeout=timeout
)
if result.returncode == 0:
self.log_review("✅ Code Review 完成")
# 保存Review結果
self.save_review_result(valid_files, result.stdout, review_type)
return True
else:
self.logger.error(f"Code Review 失敗: {result.stderr}")
return False
except subprocess.TimeoutExpired:
self.logger.error("Code Review 超時")
return False
except Exception as e:
self.logger.error("Code Review 異常", e)
return False
def save_review_result(self, files, output, review_type):
"""保存Review結果到檔案"""
try:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
safe_review_type = self.validator.sanitize_filename(review_type)
result_file = self.project_root / "logs" / f"review_{safe_review_type}_{timestamp}.md"
content = f"""# Code Review 報告
**時間**: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
**類型**: {review_type}
**檔案**: {', '.join(files)}
**Aider版本**: {self.aider_path}
## Review 結果
```
{output}
```
## 執行資訊
- **專案根目錄**: {self.project_root}
- **檔案數量**: {len(files)}
- **Review類型**: {review_type}
- **執行時間**: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
---
*由 Aider 自動生成 - MOMO 系統 Code Review*
"""
with open(result_file, "w", encoding="utf-8") as f:
f.write(content)
self.log_review(f"📄 Review結果已保存: {result_file}")
except Exception as e:
self.logger.error("保存Review結果失敗", e)
def review_specific_files(self, file_paths, review_type="basic"):
"""Review指定的檔案"""
try:
# 驗證Review類型
if not self.validator.validate_review_type(review_type):
self.logger.error(f"無效的Review類型: {review_type}")
return False
# 驗證並處理檔案路徑
valid_files = self.validator.validate_files(file_paths, self.project_root)
if not valid_files:
self.logger.error("沒有有效的檔案可以Review")
return False
return self.run_aider_review(valid_files, review_type)
except Exception as e:
self.logger.error("Review指定檔案失敗", e)
return False
def main():
try:
parser = argparse.ArgumentParser(
description="MOMO系統 Aider Code Review 自動化工具",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
使用範例:
%(prog)s --auto # 自動Review暫存檔案
%(prog)s --files app.py routes/*.py # Review指定檔案
%(prog)s --type security --auto # 安全檢查暫存檔案
%(prog)s --project-root /path/to/project # 指定專案根目錄
"""
)
parser.add_argument("--files", "-f", nargs="+",
help="指定要Review的檔案支援相對路徑和絕對路徑")
parser.add_argument("--type", "-t", choices=["basic", "security", "performance"],
default="basic", help="Review類型 (預設: basic)")
parser.add_argument("--project-root", "-p",
help="專案根目錄路徑(預設: 自動偵測)")
parser.add_argument("--auto", "-a", action="store_true",
help="自動Review暫存的檔案 (Git staged files)")
parser.add_argument("--verbose", "-v", action="store_true",
help="顯示詳細輸出")
parser.add_argument("--dry-run", action="store_true",
help="僅顯示將要Review的檔案不實際執行")
args = parser.parse_args()
# 初始化Code Review工具
reviewer = AiderCodeReview(args.project_root)
if args.verbose:
reviewer.logger.info(f"🔧 使用專案根目錄: {reviewer.project_root}")
reviewer.logger.info(f"🔧 Aider 路徑: {reviewer.aider_path}")
success = False
if args.dry_run:
# 乾運行模式
if args.auto:
files = reviewer.get_changed_files()
reviewer.logger.info(f"🔍 將Review的暫存檔案: {', '.join(files)}")
elif args.files:
valid_files = reviewer.validator.validate_files(args.files, reviewer.project_root)
reviewer.logger.info(f"🔍 將Review的指定檔案: {', '.join(valid_files)}")
else:
files = reviewer.get_changed_files()
reviewer.logger.info(f"🔍 將Review的變更檔案: {', '.join(files)}")
success = True
elif args.auto:
# 自動Review暫存的檔案
reviewer.logger.info("🚀 開始自動Review暫存檔案...")
success = reviewer.run_aider_review(review_type=args.type)
elif args.files:
# Review指定檔案
reviewer.logger.info(f"🚀 開始Review指定檔案: {', '.join(args.files)}")
success = reviewer.review_specific_files(args.files, args.type)
else:
# Review所有變更檔案
reviewer.logger.info("🚀 開始Review所有變更檔案...")
success = reviewer.run_aider_review(review_type=args.type)
if success:
reviewer.logger.info("✅ Code Review 流程完成")
sys.exit(0)
else:
reviewer.logger.error("❌ Code Review 流程失敗")
sys.exit(1)
except KeyboardInterrupt:
print("\n⚠️ 用戶中斷操作")
sys.exit(130)
except Exception as e:
print(f"❌ 程式執行錯誤: {e}")
if "--verbose" in sys.argv or "-v" in sys.argv:
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()