playbook/.gitea/workflows/test.yml

519 lines
18 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: 🧪 Playbook 测试套件
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch: # 允许手动触发
concurrency:
group: test-${{ github.repository }}-${{ github.ref }}
cancel-in-progress: true
# ==========================================
# 🔧 配置区域 - 测试参数
# ==========================================
env:
# ===== 测试环境配置 =====
# 测试工作目录
WORKSPACE_DIR: "/home/workspace"
TEST_WORKSPACE: "/home/workspace/playbook-test"
jobs:
# ==========================================
# Job: 全量测试
# ==========================================
test:
name: 🧪 全量测试
runs-on: ubuntu-22.04
steps:
- name: 📥 准备仓库
run: |
echo "========================================"
echo "📥 准备仓库到 WORKSPACE_DIR"
echo "========================================"
REPO_NAME="${{ github.event.repository.name }}"
REPO_DIR="${{ env.WORKSPACE_DIR }}/$REPO_NAME"
TOKEN="${{ secrets.WORKFLOW }}"
if [ -n "$TOKEN" ]; then
REPO_URL="https://oauth2:${TOKEN}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git"
else
REPO_URL="${GITHUB_SERVER_URL}/${{ github.repository }}.git"
fi
if [ -d "$REPO_DIR" ]; then
if [ -d "$REPO_DIR/.git" ]; then
cd "$REPO_DIR"
git clean -fdx
git reset --hard
git fetch --all --tags --force --prune --prune-tags
else
rm -rf "$REPO_DIR"
fi
fi
if [ ! -d "$REPO_DIR/.git" ]; then
mkdir -p "${{ env.WORKSPACE_DIR }}"
git clone "$REPO_URL" "$REPO_DIR"
cd "$REPO_DIR"
fi
TARGET_SHA="${{ github.sha }}"
TARGET_REF="${{ github.ref }}"
if git cat-file -e "$TARGET_SHA^{commit}" 2>/dev/null; then
git checkout -f "$TARGET_SHA"
else
if [ -n "$TARGET_REF" ]; then
git fetch origin "$TARGET_REF"
git checkout -f FETCH_HEAD
else
git checkout -f "${{ github.ref_name }}"
fi
fi
git config --global --add safe.directory "$REPO_DIR"
echo "REPO_DIR=$REPO_DIR" >> $GITHUB_ENV
- name: 🔧 安装测试依赖
run: |
echo "========================================"
echo "🔧 安装测试依赖"
echo "========================================"
apt-get update
apt-get install -y bats cmake clang-format python3-pip
python3 -m pip install --upgrade pip
python3 -m pip install toml tomli jsonschema yamllint
echo ""
echo "✓ bats 版本: $(bats --version)"
echo "✓ Python 版本: $(python3 --version)"
echo "========================================"
- name: 🧪 运行全量测试并生成报告
shell: bash
run: |
set +e
set -o pipefail
overall_fail=0
scripts_status="success"
templates_status="success"
integration_status="success"
docs_status="success"
echo "========================================"
echo "🐚 Shell 脚本测试"
echo "========================================"
cd "$REPO_DIR/tests/scripts"
run_bats() {
local name="$1"
local file="$2"
local output="${name}_test_results.tap"
if [ ! -f "$file" ]; then
echo "⚠️ 未找到测试文件: $file"
scripts_status="failure"
overall_fail=1
return
fi
bats --formatter tap "$file" | tee "$output"
if [ $? -ne 0 ]; then
echo "❌ $name 测试失败"
scripts_status="failure"
overall_fail=1
else
echo "✅ $name 测试通过"
fi
}
run_bats "sync_standards" "test_sync_standards.bats"
run_bats "sync_templates" "test_sync_templates.bats"
run_bats "vendor_playbook" "test_vendor_playbook.bats"
run_bats "install_codex_skills" "test_install_codex_skills.bats"
echo "========================================"
echo "📄 模板验证测试"
echo "========================================"
cd "$REPO_DIR/tests/templates"
run_validator() {
local name="$1"
local script="$2"
if [ ! -f "$script" ]; then
echo "⚠️ 未找到验证脚本: $script"
templates_status="failure"
overall_fail=1
return
fi
chmod +x "$script"
"./$script"
if [ $? -ne 0 ]; then
echo "❌ $name 模板验证失败"
templates_status="failure"
overall_fail=1
else
echo "✅ $name 模板验证通过"
fi
}
run_validator "python" "validate_python_templates.sh"
run_validator "cpp" "validate_cpp_templates.sh"
run_validator "ci" "validate_ci_templates.sh"
run_validator "project_templates" "validate_project_templates.sh"
echo "========================================"
echo "🔗 集成测试"
echo "========================================"
mkdir -p "${TEST_WORKSPACE}"
cd "${TEST_WORKSPACE}"
# 创建测试项目目录
mkdir -p test-project-tsl
mkdir -p test-project-cpp
mkdir -p test-project-multi
echo "========================================"
echo "🧪 测试场景1: TSL 项目标准同步"
echo "========================================"
cd "${TEST_WORKSPACE}/test-project-tsl"
# 初始化 git 仓库
git init
git config user.name "Test User"
git config user.email "test@example.com"
# 模拟 subtree add包含 rulesets 等点目录,排除 .git
mkdir -p docs/standards/playbook
tar -C "$REPO_DIR" --exclude .git -cf - . | tar -C docs/standards/playbook -xf -
# 运行同步脚本
echo "▶ 运行 sync_standards.sh tsl"
sh docs/standards/playbook/scripts/sync_standards.sh tsl
# 验证结果
if [ -d ".agents/tsl" ] && [ -f ".agents/tsl/index.md" ]; then
echo "✅ TSL 规则集同步成功"
else
echo "❌ TSL 规则集同步失败"
integration_status="failure"
overall_fail=1
fi
if grep -q "# BEGIN playbook .gitattributes" .gitattributes 2>/dev/null \
|| grep -q "# Added from playbook .gitattributes" .gitattributes 2>/dev/null \
|| grep -q "^\\* text=auto eol=lf" .gitattributes 2>/dev/null; then
echo "✅ .gitattributes 更新成功"
else
echo "❌ .gitattributes 更新失败"
integration_status="failure"
overall_fail=1
fi
echo "========================================"
echo "🧪 测试场景2: C++ 项目标准同步"
echo "========================================"
cd "${TEST_WORKSPACE}/test-project-cpp"
git init
git config user.name "Test User"
git config user.email "test@example.com"
mkdir -p docs/standards/playbook
tar -C "$REPO_DIR" --exclude .git -cf - . | tar -C docs/standards/playbook -xf -
echo "▶ 运行 sync_standards.sh cpp"
sh docs/standards/playbook/scripts/sync_standards.sh cpp
if [ -d ".agents/cpp" ] && [ -f ".agents/cpp/index.md" ]; then
echo "✅ C++ 规则集同步成功"
else
echo "❌ C++ 规则集同步失败"
integration_status="failure"
overall_fail=1
fi
echo "========================================"
echo "🧪 测试场景3: 多语言项目标准同步"
echo "========================================"
cd "${TEST_WORKSPACE}/test-project-multi"
git init
git config user.name "Test User"
git config user.email "test@example.com"
mkdir -p docs/standards/playbook
tar -C "$REPO_DIR" --exclude .git -cf - . | tar -C docs/standards/playbook -xf -
echo "▶ 运行 sync_standards.sh tsl cpp"
sh docs/standards/playbook/scripts/sync_standards.sh tsl cpp
if [ -d ".agents/tsl" ] && [ -d ".agents/cpp" ] && [ -f ".agents/index.md" ]; then
echo "✅ 多语言规则集同步成功"
else
echo "❌ 多语言规则集同步失败"
integration_status="failure"
overall_fail=1
fi
echo "========================================"
echo "🧪 测试场景4: vendor_playbook 脚本"
echo "========================================"
cd "${TEST_WORKSPACE}"
mkdir -p test-project-vendor
cd test-project-vendor
git init
git config user.name "Test User"
git config user.email "test@example.com"
echo "▶ 运行 vendor_playbook.sh"
sh "$REPO_DIR/scripts/vendor_playbook.sh" . tsl
if [ -d "docs/standards/playbook" ] && [ -d "docs/standards/playbook/rulesets/tsl" ] && [ -d ".agents/tsl" ]; then
echo "✅ vendor_playbook 脚本执行成功"
else
echo "❌ vendor_playbook 脚本执行失败"
integration_status="failure"
overall_fail=1
fi
echo "========================================"
echo "🧹 清理测试环境..."
chmod -R u+w "${TEST_WORKSPACE}" 2>/dev/null || true
rm -rf "${TEST_WORKSPACE}"
echo "✓ 清理完成"
echo "========================================"
echo "📚 文档一致性检查"
echo "========================================"
cd "$REPO_DIR/tests/integration"
if [ -f "check_doc_links.sh" ]; then
chmod +x check_doc_links.sh
./check_doc_links.sh
if [ $? -eq 0 ]; then
echo "✅ 文档链接检查通过"
else
echo "❌ 发现无效链接"
docs_status="failure"
overall_fail=1
fi
else
echo "⚠️ 未找到链接检查脚本,跳过"
fi
echo "========================================"
echo "🔍 检查代理规则一致性(三层架构)"
echo "========================================"
cd "$REPO_DIR"
# 检查 rulesets/ 三层架构完整性
python3 << 'EOF'
import sys
from pathlib import Path
errors = []
warnings = []
print("检查 Layer 1: rulesets/ (极简铁律)")
print("────────────────────────────────────────")
# 检查各语言的 rulesets/ 目录(只需 index.md
agents_base = Path("rulesets")
# 检查 rulesets/index.md
agents_index = agents_base / "index.md"
if not agents_index.exists():
errors.append(f"❌ 缺少文件: {agents_index}")
elif agents_index.stat().st_size == 0:
errors.append(f"❌ 文件为空: {agents_index}")
else:
print(f"✅ {agents_index}")
for lang_dir in ["tsl", "cpp", "python"]:
agents_lang = agents_base / lang_dir
if not agents_lang.exists():
errors.append(f"❌ 缺少目录: {agents_lang}")
continue
# 只检查 index.md≤50 行)
index_file = agents_lang / "index.md"
if not index_file.exists():
errors.append(f"❌ 缺少文件: {index_file}")
elif index_file.stat().st_size == 0:
errors.append(f"❌ 文件为空: {index_file}")
else:
# 检查规模≤50 行)
line_count = len(index_file.read_text(encoding='utf-8').splitlines())
if line_count > 50:
warnings.append(f"⚠️ {index_file}: {line_count} 行 (目标: ≤50)")
else:
print(f"✅ {index_file} ({line_count} 行)")
# 检查是否有残留的旧文件
old_files = ["auth.md", "code_quality.md", "performance.md", "testing.md"]
for old_file in old_files:
old_path = agents_lang / old_file
if old_path.exists():
warnings.append(f"⚠️ 残留旧文件: {old_path} (应删除)")
print("")
print("检查 Layer 2: codex/skills/ (按需加载)")
print("────────────────────────────────────────")
# 检查关键 skills
skills_base = Path("codex/skills")
required_skills = [
("tsl-guide", ["SKILL.md", "references/primer.md", "references/advanced.md"]),
("testing-workflow", ["SKILL.md"]),
]
for skill_name, required_files in required_skills:
skill_dir = skills_base / skill_name
if not skill_dir.exists():
errors.append(f"❌ 缺少 skill: {skill_dir}")
continue
for req_file in required_files:
file_path = skill_dir / req_file
if not file_path.exists():
errors.append(f"❌ 缺少文件: {file_path}")
elif file_path.stat().st_size == 0:
errors.append(f"❌ 文件为空: {file_path}")
else:
print(f"✅ {file_path}")
print("")
print("检查 Layer 3: docs/ (权威文档)")
print("────────────────────────────────────────")
# 检查关键文档路径
docs_paths = [
"docs/tsl/syntax_book/index.md",
"docs/tsl/code_style.md",
"docs/tsl/naming.md",
"docs/cpp/code_style.md",
"docs/python/style_guide.md",
]
for doc_path in docs_paths:
path = Path(doc_path)
if not path.exists():
errors.append(f"❌ 缺少文档: {doc_path}")
else:
print(f"✅ {doc_path}")
print("")
print("检查架构文档")
print("────────────────────────────────────────")
# 检查新增的架构文档
arch_docs = ["AGENTS.md", "SKILLS.md", "README.md"]
for doc in arch_docs:
path = Path(doc)
if not path.exists():
errors.append(f"❌ 缺少文档: {doc}")
else:
print(f"✅ {doc}")
print("")
print("────────────────────────────────────────")
if warnings:
print("\n⚠ 警告:")
for warning in warnings:
print(f" {warning}")
print("")
if errors:
print("\n❌ 发现错误:")
for error in errors:
print(f" {error}")
sys.exit(1)
else:
print("✅ 三层架构完整性检查通过")
EOF
if [ $? -ne 0 ]; then
docs_status="failure"
overall_fail=1
fi
echo "========================================"
echo "📊 生成测试综合报告"
echo "========================================"
format_status() {
case "$1" in
success)
echo "✅ 通过"
;;
failure)
echo "❌ 失败"
;;
*)
echo "❔ 未知"
;;
esac
}
cat >> $GITHUB_STEP_SUMMARY << EOFSUMMARY
# 🧪 Playbook 测试报告
## 📋 测试执行摘要
| 测试类型 | 状态 |
|---------|------|
| 🐚 Shell 脚本测试 | $(format_status "$scripts_status") |
| 📄 模板验证测试 | $(format_status "$templates_status") |
| 🔗 集成测试 | $(format_status "$integration_status") |
| 📚 文档一致性检查 | $(format_status "$docs_status") |
---
## 🔗 相关链接
- 📝 [测试文档](tests/README.md)
- 🐛 [问题反馈](../../issues)
- 📖 [开发指南](docs/index.md)
---
<div align="center">
*🤖 由 [Gitea Actions](../../actions) 自动生成*
EOFSUMMARY
echo "*📅 生成时间: $(date -u '+%Y-%m-%d %H:%M:%S UTC')*" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "</div>" >> $GITHUB_STEP_SUMMARY
echo "========================================"
if [ "$overall_fail" -ne 0 ]; then
echo "❌ 测试失败"
exit 1
fi
echo "✅ 全量测试通过"