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" # ===== 测试覆盖率目标 ===== # Shell 脚本测试覆盖率目标(百分比) SHELL_COVERAGE_TARGET: "80" # 模板验证通过率目标(百分比) TEMPLATE_VALIDATION_TARGET: "100" # ===== 测试输出配置 ===== # 是否生成详细测试报告 VERBOSE_OUTPUT: "true" # 测试报告格式(tap/junit/markdown) REPORT_FORMAT: "markdown" # ===== 颜色输出配置 ===== # 启用彩色输出 FORCE_COLOR: "1" TERM: "xterm-256color" jobs: # ========================================== # Job 1: 环境检查与准备 # ========================================== setup: name: 🔍 环境检查 runs-on: ubuntu-22.04 outputs: scripts-changed: ${{ steps.changes.outputs.scripts }} templates-changed: ${{ steps.changes.outputs.templates }} docs-changed: ${{ steps.changes.outputs.docs }} 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: 🔍 检测变更文件 id: changes run: | echo "========================================" echo "🔍 检测变更文件" echo "========================================" cd "$REPO_DIR" # 如果是手动触发或主分支push,测试所有内容 if [ "${{ github.event_name }}" = "workflow_dispatch" ] || [ "${{ github.event_name }}" = "push" ]; then echo "scripts=true" >> $GITHUB_OUTPUT echo "templates=true" >> $GITHUB_OUTPUT echo "docs=true" >> $GITHUB_OUTPUT echo "✓ 手动触发或主分支push,测试所有内容" else # PR:只测试变更的部分 SCRIPTS_CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '^scripts/' || echo "") TEMPLATES_CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '^templates/' || echo "") DOCS_CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '^(docs/|.agents/)' || echo "") if [ -n "$SCRIPTS_CHANGED" ]; then echo "scripts=true" >> $GITHUB_OUTPUT echo "✓ 检测到脚本变更" else echo "scripts=false" >> $GITHUB_OUTPUT fi if [ -n "$TEMPLATES_CHANGED" ]; then echo "templates=true" >> $GITHUB_OUTPUT echo "✓ 检测到模板变更" else echo "templates=false" >> $GITHUB_OUTPUT fi if [ -n "$DOCS_CHANGED" ]; then echo "docs=true" >> $GITHUB_OUTPUT echo "✓ 检测到文档变更" else echo "docs=false" >> $GITHUB_OUTPUT fi fi echo "========================================" - name: 📊 显示测试环境信息 run: | echo "========================================" echo "📊 测试环境信息" echo "========================================" echo "🖥️ 操作系统: $(lsb_release -ds)" echo "🐚 Shell: $SHELL" echo "🐍 Python: $(python3 --version)" echo "📦 Git: $(git --version)" echo "========================================" # ========================================== # Job 2: Shell 脚本测试 # ========================================== test-scripts: name: 🐚 Shell 脚本测试 runs-on: ubuntu-22.04 needs: setup if: needs.setup.outputs.scripts-changed == 'true' strategy: fail-fast: false matrix: script-group: - name: sync_standards scripts: "sync_standards.sh" - name: vendor_playbook scripts: "vendor_playbook.sh" - name: install_codex_skills scripts: "install_codex_skills.sh" 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: 🔧 安装 bats-core run: | echo "========================================" echo "🔧 安装 bats-core 测试框架" echo "========================================" sudo apt-get update sudo apt-get install -y bats echo "" echo "✓ bats 版本: $(bats --version)" echo "========================================" - name: 🧪 运行 ${{ matrix.script-group.name }} 测试 run: | echo "========================================" echo "🧪 测试脚本组: ${{ matrix.script-group.name }}" echo "========================================" cd "$REPO_DIR/tests/scripts" # 运行对应的测试文件 if [ -f "test_${{ matrix.script-group.name }}.bats" ]; then bats --formatter tap "test_${{ matrix.script-group.name }}.bats" | tee "${{ matrix.script-group.name }}_test_results.tap" TEST_EXIT_CODE=${PIPESTATUS[0]} echo "" if [ $TEST_EXIT_CODE -eq 0 ]; then echo "✅ ${{ matrix.script-group.name }} 测试通过" else echo "❌ ${{ matrix.script-group.name }} 测试失败" exit 1 fi else echo "⚠️ 未找到测试文件: test_${{ matrix.script-group.name }}.bats" exit 1 fi echo "========================================" - name: 📊 上传测试结果 if: always() uses: actions/upload-artifact@v4 with: name: script-test-results-${{ matrix.script-group.name }} path: ${{ env.REPO_DIR }}/tests/scripts/*_test_results.tap retention-days: 30 # ========================================== # Job 3: 模板验证测试 # ========================================== test-templates: name: 📄 模板验证测试 runs-on: ubuntu-22.04 needs: setup if: needs.setup.outputs.templates-changed == 'true' strategy: fail-fast: false matrix: template-type: - name: python validator: validate_python_templates.sh - name: cpp validator: validate_cpp_templates.sh - name: ci validator: validate_ci_templates.sh 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 "🔧 安装 ${{ matrix.template-type.name }} 模板验证工具" echo "========================================" case "${{ matrix.template-type.name }}" in python) python3 -m pip install --upgrade pip pip install toml tomli jsonschema yamllint echo "✓ Python 验证工具已安装" ;; cpp) sudo apt-get update sudo apt-get install -y cmake clang-format echo "✓ C++ 验证工具已安装" ;; ci) pip install yamllint echo "✓ CI 验证工具已安装" ;; esac echo "========================================" - name: 🧪 验证 ${{ matrix.template-type.name }} 模板 run: | echo "========================================" echo "🧪 验证模板类型: ${{ matrix.template-type.name }}" echo "========================================" cd "$REPO_DIR/tests/templates" if [ -f "${{ matrix.template-type.validator }}" ]; then chmod +x "${{ matrix.template-type.validator }}" ./"${{ matrix.template-type.validator }}" if [ $? -eq 0 ]; then echo "✅ ${{ matrix.template-type.name }} 模板验证通过" else echo "❌ ${{ matrix.template-type.name }} 模板验证失败" exit 1 fi else echo "⚠️ 未找到验证脚本: ${{ matrix.template-type.validator }}" exit 1 fi echo "========================================" - name: 📊 上传验证报告 if: always() uses: actions/upload-artifact@v4 with: name: template-validation-${{ matrix.template-type.name }} path: ${{ env.REPO_DIR }}/tests/templates/*_validation_report.txt retention-days: 30 # ========================================== # Job 4: 集成测试 # ========================================== test-integration: name: 🔗 集成测试 runs-on: ubuntu-22.04 needs: [setup, test-scripts, test-templates] if: | always() && (needs.test-scripts.result == 'success' || needs.test-scripts.result == 'skipped') && (needs.test-templates.result == 'success' || needs.test-templates.result == 'skipped') 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 "========================================" mkdir -p "${{ env.TEST_WORKSPACE }}" cd "${{ env.TEST_WORKSPACE }}" # 创建测试项目目录 mkdir -p test-project-tsl mkdir -p test-project-cpp mkdir -p test-project-multi echo "✓ 测试环境已准备" echo "========================================" - name: "🧪 测试场景1: TSL 项目标准同步" run: | echo "========================================" echo "🧪 测试场景1: TSL 项目标准同步" echo "========================================" cd "${{ env.TEST_WORKSPACE }}/test-project-tsl" # 初始化 git 仓库 git init git config user.name "Test User" git config user.email "test@example.com" # 模拟 subtree add(包含 .agents 等点目录,排除 .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 规则集同步失败" exit 1 fi if grep -q "# BEGIN playbook .gitattributes" .gitattributes 2>/dev/null; then echo "✅ .gitattributes 更新成功" else echo "❌ .gitattributes 更新失败" exit 1 fi echo "========================================" - name: "🧪 测试场景2: C++ 项目标准同步" run: | echo "========================================" echo "🧪 测试场景2: C++ 项目标准同步" echo "========================================" cd "${{ env.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++ 规则集同步失败" exit 1 fi echo "========================================" - name: "🧪 测试场景3: 多语言项目标准同步" run: | echo "========================================" echo "🧪 测试场景3: 多语言项目标准同步" echo "========================================" cd "${{ env.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 "❌ 多语言规则集同步失败" exit 1 fi echo "========================================" - name: "🧪 测试场景4: vendor_playbook 脚本" run: | echo "========================================" echo "🧪 测试场景4: vendor_playbook 脚本" echo "========================================" cd "${{ env.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 ".agents/tsl" ]; then echo "✅ vendor_playbook 脚本执行成功" else echo "❌ vendor_playbook 脚本执行失败" exit 1 fi echo "========================================" - name: 🧹 清理测试环境 if: always() run: | echo "🧹 清理测试环境..." chmod -R u+w "${{ env.TEST_WORKSPACE }}" 2>/dev/null || true rm -rf "${{ env.TEST_WORKSPACE }}" echo "✓ 清理完成" # ========================================== # Job 5: 文档一致性检查 # ========================================== test-docs: name: 📚 文档一致性检查 runs-on: ubuntu-22.04 needs: setup if: needs.setup.outputs.docs-changed == 'true' 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 "========================================" 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 "❌ 发现无效链接" exit 1 fi else echo "⚠️ 未找到链接检查脚本,跳过" fi echo "========================================" - name: 🔍 检查代理规则一致性 run: | echo "========================================" echo "🔍 检查代理规则一致性" echo "========================================" cd "$REPO_DIR" # 检查 .agents/ 和 docs/ 中的规则是否一致 python3 << 'EOF' import os import sys from pathlib import Path errors = [] # 检查各语言的 .agents/ 目录 agents_base = Path(".agents") for lang_dir in ["tsl", "cpp", "python"]: agents_lang = agents_base / lang_dir if not agents_lang.exists(): continue # 检查必须存在的文件 required_files = ["index.md", "auth.md", "code_quality.md"] for req_file in required_files: file_path = agents_lang / req_file if not file_path.exists(): errors.append(f"❌ 缺少文件: {file_path}") elif file_path.stat().st_size == 0: errors.append(f"❌ 文件为空: {file_path}") if errors: print("\n".join(errors)) sys.exit(1) else: print("✅ 代理规则一致性检查通过") EOF echo "========================================" # ========================================== # Job 6: 生成测试报告 # ========================================== report: name: 📊 生成测试报告 runs-on: ubuntu-22.04 needs: [setup, test-scripts, test-templates, test-integration, test-docs] if: always() steps: - name: 📁 准备报告目录 run: | mkdir -p "${{ env.WORKSPACE_DIR }}/test-results" - name: 📥 下载所有测试结果 uses: actions/download-artifact@v4 with: path: ${{ env.WORKSPACE_DIR }}/test-results - name: 📊 生成综合报告 if: always() run: | echo "========================================" echo "📊 生成测试综合报告" echo "========================================" cat >> $GITHUB_STEP_SUMMARY << 'EOFSUMMARY' # 🧪 Playbook 测试报告 ## 📋 测试执行摘要 | 测试类型 | 状态 | |---------|------| EOFSUMMARY # Shell 脚本测试 if [ "${{ needs.test-scripts.result }}" = "success" ]; then echo "| 🐚 Shell 脚本测试 | ✅ 通过 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-scripts.result }}" = "failure" ]; then echo "| 🐚 Shell 脚本测试 | ❌ 失败 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-scripts.result }}" = "skipped" ]; then echo "| 🐚 Shell 脚本测试 | ⏭️ 跳过 |" >> $GITHUB_STEP_SUMMARY fi # 模板验证测试 if [ "${{ needs.test-templates.result }}" = "success" ]; then echo "| 📄 模板验证测试 | ✅ 通过 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-templates.result }}" = "failure" ]; then echo "| 📄 模板验证测试 | ❌ 失败 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-templates.result }}" = "skipped" ]; then echo "| 📄 模板验证测试 | ⏭️ 跳过 |" >> $GITHUB_STEP_SUMMARY fi # 集成测试 if [ "${{ needs.test-integration.result }}" = "success" ]; then echo "| 🔗 集成测试 | ✅ 通过 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-integration.result }}" = "failure" ]; then echo "| 🔗 集成测试 | ❌ 失败 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-integration.result }}" = "skipped" ]; then echo "| 🔗 集成测试 | ⏭️ 跳过 |" >> $GITHUB_STEP_SUMMARY fi # 文档检查 if [ "${{ needs.test-docs.result }}" = "success" ]; then echo "| 📚 文档一致性检查 | ✅ 通过 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-docs.result }}" = "failure" ]; then echo "| 📚 文档一致性检查 | ❌ 失败 |" >> $GITHUB_STEP_SUMMARY elif [ "${{ needs.test-docs.result }}" = "skipped" ]; then echo "| 📚 文档一致性检查 | ⏭️ 跳过 |" >> $GITHUB_STEP_SUMMARY fi cat >> $GITHUB_STEP_SUMMARY << 'EOFEND' --- ## 🔗 相关链接 - 📝 [测试文档](tests/README.md) - 🐛 [问题反馈](../../issues) - 📖 [开发指南](docs/index.md) ---
*🤖 由 [Gitea Actions](../../actions) 自动生成* EOFEND echo "*📅 生成时间: $(date -u '+%Y-%m-%d %H:%M:%S UTC')*" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "
" >> $GITHUB_STEP_SUMMARY echo "========================================" echo "✅ 测试报告已生成" echo "========================================"