refactor: 整理脚本文件到 scripts 目录(任务 2.1/20)
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Woodpecker CI 自动触发诊断工具
|
||||
排查 CI 无法自动触发的可能原因
|
||||
"""
|
||||
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def diagnose_auto_trigger(config_path):
|
||||
"""诊断自动触发问题"""
|
||||
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
print("="*70)
|
||||
print("Woodpecker CI 自动触发诊断")
|
||||
print("="*70)
|
||||
|
||||
print("\n🔍 可能导致 CI 无法自动触发的原因:")
|
||||
print("-"*70)
|
||||
|
||||
reasons = [
|
||||
{
|
||||
"原因": "1. Webhook 未配置或配置错误",
|
||||
"检查": "Git 仓库设置 → Webhooks → 确认有指向 Woodpecker CI 的 Webhook",
|
||||
"解决": "添加 Webhook,URL 格式: http://woodpecker-server/hook"
|
||||
},
|
||||
{
|
||||
"原因": "2. Woodpecker CI 仓库未激活",
|
||||
"检查": "Woodpecker CI Web 界面 → 确认仓库已激活",
|
||||
"解决": "在 Woodpecker CI 中激活仓库"
|
||||
},
|
||||
{
|
||||
"原因": "3. 分支保护或限制",
|
||||
"检查": "Woodpecker CI 仓库设置 → 查看 'Trusted' 和 'Protected' 设置",
|
||||
"解决": "取消分支保护或添加受信任的分支"
|
||||
},
|
||||
{
|
||||
"原因": "4. 配置文件语法错误",
|
||||
"检查": "使用 yamllint 或在线 YAML 验证器检查配置文件",
|
||||
"解决": "修复 YAML 语法错误"
|
||||
},
|
||||
{
|
||||
"原因": "5. when 条件过于严格",
|
||||
"检查": "检查配置文件中的 when 条件",
|
||||
"解决": "确保 when 条件包含正确的分支和事件"
|
||||
},
|
||||
{
|
||||
"原因": "6. Woodpecker CI 全局配置限制",
|
||||
"检查": "检查 Woodpecker CI 的全局配置文件",
|
||||
"解决": "修改全局配置,允许自动触发"
|
||||
},
|
||||
{
|
||||
"原因": "7. Git 仓库权限问题",
|
||||
"检查": "确认 Woodpecker CI 有访问仓库的权限",
|
||||
"解决": "重新授权 Woodpecker CI 访问仓库"
|
||||
},
|
||||
{
|
||||
"原因": "8. 提交信息包含跳过关键词",
|
||||
"检查": "检查提交信息是否包含 [skip ci], [ci skip] 等",
|
||||
"解决": "避免在提交信息中使用跳过关键词"
|
||||
}
|
||||
]
|
||||
|
||||
for i, reason in enumerate(reasons, 1):
|
||||
print(f"\n{reason['原因']}")
|
||||
print(f" 检查: {reason['检查']}")
|
||||
print(f" 解决: {reason['解决']}")
|
||||
|
||||
# 检查配置文件中的 when 条件
|
||||
print("\n\n📋 当前配置的 when 条件:")
|
||||
print("-"*70)
|
||||
|
||||
for step_name, step_config in config.get('steps', {}).items():
|
||||
if not isinstance(step_config, dict):
|
||||
continue
|
||||
|
||||
when = step_config.get('when', {})
|
||||
if not when:
|
||||
continue
|
||||
|
||||
if isinstance(when, dict):
|
||||
events = when.get('event', [])
|
||||
branches = when.get('branch', [])
|
||||
if events or branches:
|
||||
print(f"\n步骤: {step_name}")
|
||||
if events:
|
||||
print(f" 事件: {events}")
|
||||
if branches:
|
||||
print(f" 分支: {branches}")
|
||||
elif isinstance(when, list):
|
||||
print(f"\n步骤: {step_name}")
|
||||
for condition in when:
|
||||
if isinstance(condition, dict):
|
||||
events = condition.get('event', [])
|
||||
branches = condition.get('branch', [])
|
||||
if events:
|
||||
print(f" 事件: {events}")
|
||||
if branches:
|
||||
print(f" 分支: {branches}")
|
||||
|
||||
print("\n\n💡 快速排查步骤:")
|
||||
print("="*70)
|
||||
print("1. 访问 Git 仓库设置 → Webhooks")
|
||||
print(" - 确认有 Woodpecker CI 的 Webhook")
|
||||
print(" - 查看 'Recent Deliveries' 是否有发送记录")
|
||||
print("\n2. 访问 Woodpecker CI Web 界面")
|
||||
print(" - 确认仓库已激活")
|
||||
print(" - 检查仓库设置中的 'Trusted' 选项")
|
||||
print("\n3. 查看提交记录")
|
||||
print(" - 确认提交信息不包含 [skip ci] 等关键词")
|
||||
print("\n4. 手动触发测试")
|
||||
print(" - 在 Woodpecker CI 中手动触发 Pipeline")
|
||||
print(" - 观察是否能够正常执行")
|
||||
|
||||
print("\n" + "="*70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
diagnose_auto_trigger(".woodpecker.yml")
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "=========================================="
|
||||
echo "CI/CD 问题诊断脚本"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
echo "📋 问题1: Git LFS 配置检查"
|
||||
echo "----------------------------------------"
|
||||
if command -v git-lfs &> /dev/null; then
|
||||
echo "✅ Git LFS 已安装"
|
||||
git lfs version
|
||||
else
|
||||
echo "❌ Git LFS 未安装"
|
||||
fi
|
||||
|
||||
if [ -f ".gitattributes" ]; then
|
||||
echo "✅ .gitattributes 文件存在"
|
||||
cat .gitattributes
|
||||
else
|
||||
echo "❌ .gitattributes 文件不存在(项目未使用LFS)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 问题2: 环境变量检查"
|
||||
echo "----------------------------------------"
|
||||
echo "当前环境变量:"
|
||||
echo " CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH:-未设置}"
|
||||
echo " CI_COMMIT_SHA: ${CI_COMMIT_SHA:-未设置}"
|
||||
echo " CI_COMMIT_MESSAGE: ${CI_COMMIT_MESSAGE:-未设置}"
|
||||
echo " CI_COMMIT_AUTHOR: ${CI_COMMIT_AUTHOR:-未设置}"
|
||||
echo " CI_PIPELINE_NUMBER: ${CI_PIPELINE_NUMBER:-未设置}"
|
||||
echo " CI_REPO_ID: ${CI_REPO_ID:-未设置}"
|
||||
|
||||
echo ""
|
||||
echo "📋 问题3: Woodpecker CI 配置验证"
|
||||
echo "----------------------------------------"
|
||||
if command -v python3 &> /dev/null; then
|
||||
echo "运行 Python 诊断脚本..."
|
||||
python3 diagnose-woodpecker.py 2>/dev/null || echo "诊断脚本执行失败"
|
||||
else
|
||||
echo "⚠️ Python3 未安装,跳过配置验证"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "诊断完成"
|
||||
echo "=========================================="
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "=== Woodpecker CI Webhook 诊断 ==="
|
||||
echo ""
|
||||
|
||||
echo "1. 检查 Forgejo Webhook 配置..."
|
||||
echo " Webhook URL: https://ci.f.novalon.cn/api/hook?access_token=..."
|
||||
echo " Content Type: application/json"
|
||||
echo " Trigger: push"
|
||||
echo ""
|
||||
|
||||
echo "2. 检查 Woodpecker CI 期望的 Header..."
|
||||
echo " X-Gitea-Event: push"
|
||||
echo " X-Gitea-Delivery: <uuid>"
|
||||
echo " X-Gitea-Signature: <signature>"
|
||||
echo ""
|
||||
|
||||
echo "3. 检查 Nginx 配置..."
|
||||
docker exec novalon-nginx cat /etc/nginx/conf.d/ci.f.novalon.cn.conf | grep -A 15 "location /api/"
|
||||
echo ""
|
||||
|
||||
echo "4. 测试 Webhook 接收..."
|
||||
echo " 发送测试 webhook..."
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Gitea-Event: push" \
|
||||
-H "X-Gitea-Delivery: test-123" \
|
||||
-d '{"ref":"refs/heads/test"}' \
|
||||
"https://ci.f.novalon.cn/api/hook?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb3JnZS1pZCI6IjEiLCJyZXBvLWZvcmdlLXJlbW90ZS1pZCI6IjEiLCJ0eXBlIjoiaG9vayJ9.gu3mi1VAQfGB3d9HcuwWmMAcf-0BmmvQyGjqdiC20dA" \
|
||||
-v 2>&1 | grep -E "(< HTTP|X-Gitea|hook)"
|
||||
echo ""
|
||||
|
||||
echo "5. 检查 Woodpecker CI 日志..."
|
||||
docker logs woodpecker-server --since 10s 2>&1 | grep -E "(hook|event|push)"
|
||||
echo ""
|
||||
|
||||
echo "=== 诊断完成 ==="
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Woodpecker CI 配置诊断工具
|
||||
检查配置文件中可能导致 CI 未触发的问题
|
||||
"""
|
||||
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def diagnose_woodpecker_config(config_path):
|
||||
"""诊断 Woodpecker CI 配置"""
|
||||
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
print("="*70)
|
||||
print("Woodpecker CI 配置诊断报告")
|
||||
print("="*70)
|
||||
|
||||
issues = []
|
||||
warnings = []
|
||||
|
||||
# 检查是否有 steps
|
||||
if 'steps' not in config:
|
||||
issues.append("❌ 缺少 'steps' 配置")
|
||||
else:
|
||||
print(f"\n✅ 找到 {len(config['steps'])} 个步骤")
|
||||
|
||||
# 检查每个步骤的 when 条件
|
||||
print("\n📋 步骤触发条件检查:")
|
||||
print("-" * 70)
|
||||
|
||||
for step_name, step_config in config.get('steps', {}).items():
|
||||
if not isinstance(step_config, dict):
|
||||
continue
|
||||
|
||||
when = step_config.get('when', {})
|
||||
|
||||
if not when:
|
||||
warnings.append(f"⚠️ 步骤 '{step_name}' 没有 when 条件,将始终执行")
|
||||
continue
|
||||
|
||||
# 检查 when 条件的格式
|
||||
if isinstance(when, list):
|
||||
print(f"\n步骤: {step_name}")
|
||||
print(f" when 条件格式: 列表(多个条件)")
|
||||
for i, condition in enumerate(when):
|
||||
if isinstance(condition, dict):
|
||||
events = condition.get('event', [])
|
||||
branches = condition.get('branch', [])
|
||||
print(f" 条件 {i+1}:")
|
||||
print(f" 事件: {events}")
|
||||
print(f" 分支: {branches}")
|
||||
elif isinstance(when, dict):
|
||||
print(f"\n步骤: {step_name}")
|
||||
print(f" when 条件格式: 字典(单个条件)")
|
||||
events = when.get('event', [])
|
||||
branches = when.get('branch', [])
|
||||
print(f" 事件: {events}")
|
||||
print(f" 分支: {branches}")
|
||||
|
||||
# 检查可能导致问题的配置
|
||||
print("\n\n🔍 潜在问题分析:")
|
||||
print("-" * 70)
|
||||
|
||||
# 检查是否有 skip_clone
|
||||
if config.get('skip_clone'):
|
||||
warnings.append("⚠️ skip_clone 设置为 true,可能影响代码获取")
|
||||
|
||||
# 检查 clone 配置
|
||||
clone_config = config.get('clone', {})
|
||||
if clone_config:
|
||||
print(f"\nClone 配置: {clone_config}")
|
||||
|
||||
# 检查 services
|
||||
services = config.get('services', {})
|
||||
if services:
|
||||
print(f"\n服务配置: {list(services.keys())}")
|
||||
|
||||
# 检查 workspace
|
||||
workspace = config.get('workspace', {})
|
||||
if workspace:
|
||||
print(f"\n工作区配置: {workspace}")
|
||||
|
||||
# 输出问题
|
||||
print("\n\n📊 诊断结果:")
|
||||
print("="*70)
|
||||
|
||||
if issues:
|
||||
print("\n❌ 发现的问题:")
|
||||
for issue in issues:
|
||||
print(f" {issue}")
|
||||
|
||||
if warnings:
|
||||
print("\n⚠️ 警告:")
|
||||
for warning in warnings:
|
||||
print(f" {warning}")
|
||||
|
||||
if not issues and not warnings:
|
||||
print("\n✅ 配置文件语法正确,未发现明显问题")
|
||||
|
||||
# 输出可能的原因
|
||||
print("\n\n🔍 CI 未触发的可能原因:")
|
||||
print("-" * 70)
|
||||
possible_reasons = [
|
||||
"1. Woodpecker CI 的 Webhook 未正确配置",
|
||||
"2. Git 仓库设置中禁用了该分支的 CI 触发",
|
||||
"3. Woodpecker CI 服务器未运行或配置错误",
|
||||
"4. 配置文件中的分支匹配规则与 Woodpecker CI 版本不兼容",
|
||||
"5. 需要在 Woodpecker CI 界面手动激活该仓库",
|
||||
"6. Woodpecker CI 的全局配置限制了某些分支",
|
||||
"7. 推送的提交信息触发了 CI 跳过(如包含 [skip ci])",
|
||||
]
|
||||
|
||||
for reason in possible_reasons:
|
||||
print(f" {reason}")
|
||||
|
||||
print("\n\n💡 建议的排查步骤:")
|
||||
print("-" * 70)
|
||||
suggestions = [
|
||||
"1. 检查 Woodpecker CI Web 界面,确认仓库已激活",
|
||||
"2. 检查 Git 仓库的 Webhook 设置",
|
||||
"3. 查看 Woodpecker CI 的日志",
|
||||
"4. 尝试手动触发 CI(如果支持)",
|
||||
"5. 检查 Woodpecker CI 的全局配置",
|
||||
"6. 创建一个简单的测试分支验证配置",
|
||||
]
|
||||
|
||||
for suggestion in suggestions:
|
||||
print(f" {suggestion}")
|
||||
|
||||
print("\n" + "="*70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
diagnose_woodpecker_config(".woodpecker.yml")
|
||||
Reference in New Issue
Block a user