#!/bin/bash set -e WOODPECKER_FILE=".woodpecker.yml" echo "==========================================" echo "Woodpecker CI 配置本地验证工具" echo "==========================================" echo "" # 检查文件是否存在 if [ ! -f "$WOODPECKER_FILE" ]; then echo "❌ 错误: $WOODPECKER_FILE 文件不存在" exit 1 fi echo "✅ 文件存在: $WOODPECKER_FILE" echo "" # 1. YAML 语法检查 echo "1️⃣ YAML 语法检查" echo "----------------------------------------" if command -v python3 &> /dev/null; then if python3 -c "import yaml; yaml.safe_load(open('$WOODPECKER_FILE'))" 2>&1; then echo "✅ YAML 语法正确" else echo "❌ YAML 语法错误" exit 1 fi else echo "⚠️ Python3 未安装,跳过 YAML 语法检查" fi echo "" # 2. 检查必需的字段 echo "2️⃣ 检查必需字段" echo "----------------------------------------" python3 << 'PYTHON_SCRIPT' import yaml import sys with open('.woodpecker.yml', 'r') as f: config = yaml.safe_load(f) errors = [] warnings = [] # 检查 steps if 'steps' not in config: errors.append("缺少 'steps' 字段") else: steps = config['steps'] if not steps: errors.append("'steps' 不能为空") else: for step_name, step_config in steps.items(): # 检查 image if 'image' not in step_config: errors.append(f"步骤 '{step_name}' 缺少 'image' 字段") # 检查 commands if 'commands' not in step_config: warnings.append(f"步骤 '{step_name}' 没有 'commands' 字段") # 检查 when 条件 if 'when' in step_config: when = step_config['when'] if 'branch' in when: print(f" ✅ 步骤 '{step_name}' 有分支条件: {when['branch']}") if 'event' in when: print(f" ✅ 步骤 '{step_name}' 有事件条件: {when['event']}") # 检查 workspace if 'workspace' in config: print(f" ✅ workspace 配置: {config['workspace']}") # 检查 clone if 'clone' in config: print(f" ✅ clone 配置: {config['clone']}") if errors: print("\n❌ 错误:") for error in errors: print(f" - {error}") sys.exit(1) if warnings: print("\n⚠️ 警告:") for warning in warnings: print(f" - {warning}") print("\n✅ 所有必需字段检查通过") PYTHON_SCRIPT if [ $? -ne 0 ]; then exit 1 fi echo "" # 3. 检查镜像是否存在 echo "3️⃣ 检查镜像格式" echo "----------------------------------------" python3 << 'PYTHON_SCRIPT' import yaml import re with open('.woodpecker.yml', 'r') as f: config = yaml.safe_load(f) steps = config.get('steps', {}) image_pattern = re.compile(r'^[a-z0-9\-_./]+(?::[a-z0-9\-_.]+)?$') for step_name, step_config in steps.items(): image = step_config.get('image', '') if image: # 检查镜像格式 if image.startswith('*'): # YAML anchor,跳过 print(f" ℹ️ 步骤 '{step_name}' 使用 YAML anchor: {image}") elif image_pattern.match(image): print(f" ✅ 步骤 '{step_name}' 镜像格式正确: {image}") else: print(f" ⚠️ 步骤 '{step_name}' 镜像格式可能有问题: {image}") print("\n✅ 镜像格式检查完成") PYTHON_SCRIPT echo "" # 4. 检查环境变量和 secrets echo "4️⃣ 检查环境变量和 secrets" echo "----------------------------------------" python3 << 'PYTHON_SCRIPT' import yaml with open('.woodpecker.yml', 'r') as f: config = yaml.safe_load(f) steps = config.get('steps', {}) secrets_used = set() for step_name, step_config in steps.items(): env = step_config.get('environment', {}) if isinstance(env, dict): for key, value in env.items(): if isinstance(value, dict) and 'from_secret' in value: secret_name = value['from_secret'] secrets_used.add(secret_name) print(f" 🔐 步骤 '{step_name}' 使用 secret: {secret_name}") if secrets_used: print(f"\n📋 需要配置的 secrets:") for secret in sorted(secrets_used): print(f" - {secret}") print("\n⚠️ 请确保在 Woodpecker CI 中配置了这些 secrets") else: print(" ℹ️ 没有使用 secrets") print("\n✅ 环境变量检查完成") PYTHON_SCRIPT echo "" # 5. 检查 when 条件的逻辑 echo "5️⃣ 检查 when 条件逻辑" echo "----------------------------------------" python3 << 'PYTHON_SCRIPT' import yaml with open('.woodpecker.yml', 'r') as f: config = yaml.safe_load(f) steps = config.get('steps', {}) steps_with_conditions = [] steps_without_conditions = [] for step_name, step_config in steps.items(): if 'when' in step_config: steps_with_conditions.append(step_name) else: steps_without_conditions.append(step_name) if steps_with_conditions: print(f" ✅ 有条件执行的步骤 ({len(steps_with_conditions)}):") for step in steps_with_conditions: print(f" - {step}") if steps_without_conditions: print(f"\n ⚠️ 无条件执行的步骤 ({len(steps_without_conditions)}):") for step in steps_without_conditions: print(f" - {step}") print("\n 💡 建议: 大部分步骤应该有 when 条件,避免不必要的执行") print("\n✅ when 条件检查完成") PYTHON_SCRIPT echo "" # 6. 模拟执行顺序 echo "6️⃣ 模拟执行顺序" echo "----------------------------------------" python3 << 'PYTHON_SCRIPT' import yaml with open('.woodpecker.yml', 'r') as f: config = yaml.safe_load(f) steps = config.get('steps', {}) print(" 📋 步骤执行顺序:") for i, (step_name, step_config) in enumerate(steps.items(), 1): image = step_config.get('image', 'N/A') when = step_config.get('when', {}) conditions = [] if 'branch' in when: branches = when['branch'] if isinstance(branches, list): conditions.append(f"branch: {', '.join(branches)}") else: conditions.append(f"branch: {branches}") if 'event' in when: events = when['event'] if isinstance(events, list): conditions.append(f"event: {', '.join(events)}") else: conditions.append(f"event: {events}") if 'status' in when: statuses = when['status'] if isinstance(statuses, list): conditions.append(f"status: {', '.join(statuses)}") else: conditions.append(f"status: {statuses}") condition_str = f" [{', '.join(conditions)}]" if conditions else "" print(f" {i}. {step_name}{condition_str}") print(f" 镜像: {image}") print("\n✅ 执行顺序分析完成") PYTHON_SCRIPT echo "" echo "==========================================" echo "✅ 所有检查完成!" echo "==========================================" echo "" echo "💡 提示:" echo " - 如果所有检查都通过,配置文件基本正确" echo " - 建议使用 Woodpecker CLI 进行本地测试:" echo " woodpecker-cli exec .woodpecker.yml" echo " - 或者使用 Docker:" echo " docker run --rm -v \$(pwd):/woodpecker/src -w /woodpecker/src woodpeckerci/woodpecker-cli:latest exec .woodpecker.yml" echo ""