Files
novalon-website/scripts/monitoring/ralph-loop.py
T

184 lines
6.5 KiB
Python
Executable File

#!/usr/bin/env python3
import subprocess
import time
import json
from pathlib import Path
class RalphLoop:
def __init__(self, max_iterations=10):
self.max_iterations = max_iterations
self.current_iteration = 0
self.pipeline_url = "https://ci.f.novalon.cn/repos/1/pipeline/31"
self.commit_sha = "1e10118"
self.branch = "release/v1.0.0"
def log(self, message, level="INFO"):
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] [{level}] {message}")
def run_command(self, cmd, check=True):
self.log(f"执行命令: {cmd}")
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if check and result.returncode != 0:
self.log(f"命令失败: {result.stderr}", "ERROR")
return None
return result.stdout.strip()
def check_pipeline_status(self):
self.log("="*70)
self.log(f"迭代 #{self.current_iteration} / {self.max_iterations}")
self.log("="*70)
self.log(f"Pipeline URL: {self.pipeline_url}")
self.log(f"Commit SHA: {self.commit_sha}")
self.log(f"Branch: {self.branch}")
self.log("\n📋 请手动检查Pipeline状态:")
self.log(f" {self.pipeline_url}")
return input("\nPipeline状态 (pass/fail/running): ").strip().lower()
def identify_failure(self):
self.log("\n🔍 识别失败步骤...")
self.log("请查看Pipeline页面,输入失败的步骤名称")
self.log("常见步骤:")
self.log(" - lint")
self.log(" - type-check")
self.log(" - security-scan")
self.log(" - unit-tests")
self.log(" - e2e-standard")
self.log(" - e2e-deep")
self.log(" - build-image")
self.log(" - deploy-production")
self.log(" - notify-wechat-success")
self.log(" - notify-wechat-failure")
return input("\n失败步骤名称: ").strip()
def analyze_failure(self, step_name):
self.log(f"\n🔬 分析失败原因: {step_name}")
failure_patterns = {
"lint": {
"possible_causes": [
"ESLint配置问题",
"代码格式不符合规范",
"未使用的变量或导入"
],
"fix_commands": [
"npm run lint -- --fix",
"npm run lint 2>&1 | head -50"
]
},
"type-check": {
"possible_causes": [
"TypeScript类型错误",
"类型定义缺失",
"类型不匹配"
],
"fix_commands": [
"npm run type-check 2>&1 | head -50"
]
},
"unit-tests": {
"possible_causes": [
"测试用例失败",
"测试覆盖率不足",
"测试环境配置问题"
],
"fix_commands": [
"npm run test:coverage:check 2>&1 | tail -100"
]
},
"notify-wechat-success": {
"possible_causes": [
"脚本权限问题",
"环境变量未传递",
"Webhook URL错误"
],
"fix_commands": [
"chmod +x scripts/notify-wechat.sh",
"cat scripts/notify-wechat.sh"
]
}
}
if step_name in failure_patterns:
pattern = failure_patterns[step_name]
self.log("\n可能原因:")
for i, cause in enumerate(pattern["possible_causes"], 1):
self.log(f" {i}. {cause}")
self.log("\n诊断命令:")
for cmd in pattern["fix_commands"]:
self.log(f" $ {cmd}")
else:
self.log("⚠️ 未知步骤,请手动分析")
return input("\n输入修复描述(或'skip'跳过): ").strip()
def implement_fix(self, step_name, fix_description):
if fix_description.lower() == 'skip':
self.log("跳过修复")
return False
self.log(f"\n🔧 实施修复: {step_name}")
self.log(f"修复描述: {fix_description}")
self.log("\n请执行以下操作:")
self.log(" 1. 修复代码或配置")
self.log(" 2. 测试修复效果")
self.log(" 3. 提交更改")
input("\n修复完成后按Enter继续...")
# 提交修复
self.log("\n提交修复...")
commit_msg = f"fix: 修复{step_name}步骤失败\n\n{fix_description}"
self.run_command(f'git add -A')
self.run_command(f'git commit -m "{commit_msg}"')
self.run_command(f'git push origin {self.branch}')
self.log("✅ 修复已提交并推送")
return True
def run(self):
self.log("🚀 Ralph Loop 启动")
self.log("目标: 修复Pipeline直到通过")
self.log(f"最大迭代次数: {self.max_iterations}")
while self.current_iteration < self.max_iterations:
self.current_iteration += 1
status = self.check_pipeline_status()
if status == "pass":
self.log("\n✅ Pipeline已通过!")
self.log("Ralph Loop完成。")
return True
elif status == "running":
self.log("\n⏳ Pipeline正在运行,等待...")
time.sleep(30)
continue
elif status == "fail":
step_name = self.identify_failure()
fix_description = self.analyze_failure(step_name)
if self.implement_fix(step_name, fix_description):
self.log("\n⏳ 等待Pipeline重新执行...")
time.sleep(10)
else:
self.log("\n⚠️ 未实施修复,继续下一次迭代")
else:
self.log(f"\n❌ 无效状态: {status}")
self.log("\n⚠️ 达到最大迭代次数")
self.log("Pipeline仍未通过,请手动检查")
return False
if __name__ == "__main__":
ralph = RalphLoop(max_iterations=10)
success = ralph.run()
exit(0 if success else 1)