26aa13b5a4
ci/woodpecker/push/woodpecker Pipeline is running
优化内容: - Lint、Type Check、Security Scan并行执行 - Unit Tests使用depends_on等待所有检查完成 - 添加npm缓存配置 - 修复shared-mocks.tsx的ESLint错误 预期效果: - 串行时间: 30s + 40s + 20s = 90s - 并行时间: max(30s, 40s, 20s) = 40s - 节省时间: 50s (55.6%改善)
184 lines
6.5 KiB
Python
Executable File
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)
|