Files
playbook/tests/templates/validate_python_templates.sh
T

330 lines
9.4 KiB
Bash

#!/usr/bin/env sh
# Python 模板验证脚本
set -eu
echo "========================================"
echo "🐍 Python 模板验证"
echo "========================================"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PLAYBOOK_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
TEMPLATES_DIR="$PLAYBOOK_ROOT/templates/python"
VALIDATION_PASSED=0
VALIDATION_FAILED=0
ERRORS_FILE="/tmp/python_template_validation_errors.txt"
REPORT_FILE="$SCRIPT_DIR/python_validation_report.txt"
> "$ERRORS_FILE"
> "$REPORT_FILE"
echo "📁 模板目录: $TEMPLATES_DIR"
echo ""
# ============================================
# 辅助函数
# ============================================
validate_file_exists() {
local file="$1"
local description="$2"
if [ -f "$file" ]; then
echo " ✅ $description: $(basename "$file")"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
return 0
else
echo " ❌ $description: $(basename "$file") - 文件不存在"
echo "文件不存在: $file" >> "$ERRORS_FILE"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
return 1
fi
}
validate_toml_syntax() {
local file="$1"
local description="$2"
if ! command -v python3 >/dev/null 2>&1; then
echo " ⚠️ $description: 跳过(Python3 未安装)"
return 0
fi
if python3 << EOF
import sys
try:
import tomli
except ImportError:
try:
import tomllib as tomli
except ImportError:
import toml as tomli
try:
with open("$file", "rb") as f:
tomli.load(f)
sys.exit(0)
except Exception as e:
print(f"TOML 语法错误: {e}", file=sys.stderr)
sys.exit(1)
EOF
then
echo " ✅ $description: TOML 语法正确"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
return 0
else
echo " ❌ $description: TOML 语法错误"
echo "TOML 语法错误: $file" >> "$ERRORS_FILE"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
return 1
fi
}
validate_required_sections() {
local file="$1"
local sections="$2"
for section in $sections; do
if grep -q "^\[$section\]" "$file"; then
echo " ✓ 包含 [$section] 配置"
else
echo " ✗ 缺少 [$section] 配置"
echo "缺少配置节: $section in $file" >> "$ERRORS_FILE"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
done
}
# ============================================
# 验证 pyproject.toml
# ============================================
echo "🔍 验证 pyproject.toml"
PYPROJECT="$TEMPLATES_DIR/pyproject.toml"
if validate_file_exists "$PYPROJECT" "pyproject.toml"; then
# 验证 TOML 语法
validate_toml_syntax "$PYPROJECT" "pyproject.toml"
# 验证必要的配置节
echo " 📋 检查必要配置节:"
validate_required_sections "$PYPROJECT" "tool.black tool.isort tool.pytest.ini_options"
# 验证 black 配置
if grep -q "line-length = 80" "$PYPROJECT"; then
echo " ✓ black line-length 配置正确"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
else
echo " ✗ black line-length 配置缺失或不正确"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
# 验证 isort 配置
if grep -q "profile = \"google\"" "$PYPROJECT"; then
echo " ✓ isort profile 配置正确"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
else
echo " ✗ isort profile 配置缺失或不正确"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
fi
echo ""
# ============================================
# 验证 .flake8
# ============================================
echo "🔍 验证 .flake8"
FLAKE8="$TEMPLATES_DIR/.flake8"
if validate_file_exists "$FLAKE8" ".flake8"; then
# 验证 [flake8] 节
if grep -q "^\[flake8\]" "$FLAKE8"; then
echo " ✓ 包含 [flake8] 配置"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
# 验证 max-line-length
if grep -q "^max-line-length" "$FLAKE8"; then
echo " ✓ 配置了 max-line-length"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
else
echo " ✗ 缺少 max-line-length 配置"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
# 验证 extend-ignore
if grep -q "^extend-ignore" "$FLAKE8" || grep -q "^ignore" "$FLAKE8"; then
echo " ✓ 配置了错误忽略规则"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
fi
else
echo " ✗ 缺少 [flake8] 配置节"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
fi
echo ""
# ============================================
# 验证 .pylintrc
# ============================================
echo "🔍 验证 .pylintrc"
PYLINTRC="$TEMPLATES_DIR/.pylintrc"
if validate_file_exists "$PYLINTRC" ".pylintrc"; then
# 验证关键配置节
for section in "MASTER" "MESSAGES CONTROL" "FORMAT"; do
if grep -qi "^\[$section\]" "$PYLINTRC"; then
echo " ✓ 包含 [$section] 配置"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
else
echo " ✗ 缺少 [$section] 配置"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
done
# 验证 max-line-length
if grep -q "^max-line-length" "$PYLINTRC"; then
echo " ✓ 配置了 max-line-length"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
fi
fi
echo ""
# ============================================
# 验证 .pre-commit-config.yaml
# ============================================
echo "🔍 验证 .pre-commit-config.yaml"
PRECOMMIT="$TEMPLATES_DIR/.pre-commit-config.yaml"
if validate_file_exists "$PRECOMMIT" ".pre-commit-config.yaml"; then
# 验证 YAML 语法
if command -v yamllint >/dev/null 2>&1; then
if yamllint -d relaxed "$PRECOMMIT" >/dev/null 2>&1; then
echo " ✓ YAML 语法正确"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
else
echo " ✗ YAML 语法错误"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
fi
# 验证包含 pre-commit hooks
if grep -q "^repos:" "$PRECOMMIT"; then
echo " ✓ 包含 repos 配置"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
# 检查常用 hooks
for hook in "black" "isort" "flake8"; do
if grep -q "$hook" "$PRECOMMIT"; then
echo " ✓ 配置了 $hook hook"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
fi
done
fi
fi
echo ""
# ============================================
# 验证 .editorconfig
# ============================================
echo "🔍 验证 .editorconfig"
EDITORCONFIG="$TEMPLATES_DIR/.editorconfig"
if validate_file_exists "$EDITORCONFIG" ".editorconfig"; then
# 验证包含 root 标记
if grep -q "^root = true" "$EDITORCONFIG"; then
echo " ✓ 包含 root = true"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
fi
# 验证 Python 配置节
if grep -q "^\[\*.py\]" "$EDITORCONFIG" || grep -q "^\[*.py\]" "$EDITORCONFIG"; then
echo " ✓ 包含 Python 文件配置"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
fi
fi
echo ""
# ============================================
# 验证 VSCode 配置
# ============================================
echo "🔍 验证 .vscode/settings.json"
VSCODE_SETTINGS="$TEMPLATES_DIR/.vscode/settings.json"
if validate_file_exists "$VSCODE_SETTINGS" "settings.json"; then
# 验证 JSON 语法
if command -v python3 >/dev/null 2>&1; then
if python3 -m json.tool "$VSCODE_SETTINGS" >/dev/null 2>&1; then
echo " ✓ JSON 语法正确"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
else
echo " ✗ JSON 语法错误"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
fi
# 验证 Python 相关配置
if grep -q "python" "$VSCODE_SETTINGS"; then
echo " ✓ 包含 Python 配置"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
fi
fi
echo ""
# ============================================
# 生成验证报告
# ============================================
echo "========================================"
echo "📊 验证结果统计"
echo "========================================"
echo "✅ 通过: $VALIDATION_PASSED"
echo "❌ 失败: $VALIDATION_FAILED"
echo "📈 通过率: $(awk "BEGIN {printf \"%.1f\", ($VALIDATION_PASSED * 100.0) / ($VALIDATION_PASSED + $VALIDATION_FAILED)}")%"
echo ""
# 写入报告文件
{
echo "Python 模板验证报告"
echo "===================="
echo ""
echo "验证时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "模板目录: $TEMPLATES_DIR"
echo ""
echo "统计结果:"
echo " 通过: $VALIDATION_PASSED"
echo " 失败: $VALIDATION_FAILED"
echo " 通过率: $(awk "BEGIN {printf \"%.1f\", ($VALIDATION_PASSED * 100.0) / ($VALIDATION_PASSED + $VALIDATION_FAILED)}")%"
echo ""
if [ -s "$ERRORS_FILE" ]; then
echo "错误详情:"
cat "$ERRORS_FILE"
fi
} > "$REPORT_FILE"
echo "📄 详细报告: $REPORT_FILE"
echo "========================================"
# 清理临时文件
rm -f "$ERRORS_FILE"
# 返回结果
if [ "$VALIDATION_FAILED" -eq 0 ]; then
echo "✅ 所有 Python 模板验证通过"
exit 0
else
echo "❌ Python 模板验证失败 ($VALIDATION_FAILED 个错误)"
exit 1
fi