🔍 Code Quality #99
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: 🔍 Code Quality | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main, develop] | |
| schedule: | |
| # 每天凌晨 2 点运行质量检查 | |
| - cron: "0 2 * * *" | |
| jobs: | |
| # ============================================================================ | |
| # 代码格式检查 | |
| # ============================================================================ | |
| formatting: | |
| name: 💅 Code Formatting | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Detect package manager | |
| id: detect-package-manager | |
| run: | | |
| if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then | |
| echo "manager=pnpm" >> $GITHUB_OUTPUT | |
| echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/yarn.lock" ]; then | |
| echo "manager=yarn" >> $GITHUB_OUTPUT | |
| echo "command=install" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/package-lock.json" ]; then | |
| echo "manager=npm" >> $GITHUB_OUTPUT | |
| echo "command=ci" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "Unable to determine package manager" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| if: steps.detect-package-manager.outputs.manager == 'pnpm' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.19.0 | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: ${{ steps.detect-package-manager.outputs.manager }} | |
| - name: 📥 Install dependencies | |
| run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} | |
| - name: 💅 Check Prettier formatting | |
| run: ${{ steps.detect-package-manager.outputs.manager }} run lint | |
| - name: 🔧 Auto-fix formatting (PR only) | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| ${{ steps.detect-package-manager.outputs.manager }} run lint:fix | |
| if [[ -n $(git status --porcelain) ]]; then | |
| echo "## 💅 Formatting Changes Applied" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "The following files were auto-formatted:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| git diff --name-only >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # ============================================================================ | |
| # TypeScript 类型检查 | |
| # ============================================================================ | |
| typescript: | |
| name: 📘 TypeScript Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Detect package manager | |
| id: detect-package-manager | |
| run: | | |
| if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then | |
| echo "manager=pnpm" >> $GITHUB_OUTPUT | |
| echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/yarn.lock" ]; then | |
| echo "manager=yarn" >> $GITHUB_OUTPUT | |
| echo "command=install" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/package-lock.json" ]; then | |
| echo "manager=npm" >> $GITHUB_OUTPUT | |
| echo "command=ci" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "Unable to determine package manager" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| if: steps.detect-package-manager.outputs.manager == 'pnpm' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.19.0 | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: ${{ steps.detect-package-manager.outputs.manager }} | |
| - name: 📥 Install dependencies | |
| run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} | |
| - name: 📘 Type check | |
| run: ${{ steps.detect-package-manager.outputs.manager }} run type-check | |
| - name: 📊 Generate type report | |
| run: | | |
| echo "## 📘 TypeScript Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ No type errors found in the codebase!" >> $GITHUB_STEP_SUMMARY | |
| # ============================================================================ | |
| # 依赖检查 | |
| # ============================================================================ | |
| dependencies: | |
| name: 📦 Dependencies Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Detect package manager | |
| id: detect-package-manager | |
| run: | | |
| if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then | |
| echo "manager=pnpm" >> $GITHUB_OUTPUT | |
| echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/yarn.lock" ]; then | |
| echo "manager=yarn" >> $GITHUB_OUTPUT | |
| echo "command=install" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/package-lock.json" ]; then | |
| echo "manager=npm" >> $GITHUB_OUTPUT | |
| echo "command=ci" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "Unable to determine package manager" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| if: steps.detect-package-manager.outputs.manager == 'pnpm' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.19.0 | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: ${{ steps.detect-package-manager.outputs.manager }} | |
| - name: 📥 Install dependencies | |
| run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} | |
| - name: 🔍 Check for outdated packages | |
| run: | | |
| echo "## 📦 Dependency Status" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 检查过期的包 | |
| if ${{ steps.detect-package-manager.outputs.manager }} outdated --json > outdated.json 2>/dev/null; then | |
| if [ -s outdated.json ]; then | |
| echo "### ⚠️ Outdated Packages" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Package | Current | Wanted | Latest |" >> $GITHUB_STEP_SUMMARY | |
| echo "|---------|---------|--------|--------|" >> $GITHUB_STEP_SUMMARY | |
| node -e " | |
| const outdated = require('./outdated.json'); | |
| Object.entries(outdated).forEach(([pkg, info]) => { | |
| console.log(\`| \${pkg} | \${info.current} | \${info.wanted} | \${info.latest} |\`); | |
| }); | |
| " >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "✅ All packages are up to date!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "✅ All packages are up to date!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: 🔒 Security audit | |
| run: | | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🔒 Security Audit" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if ${{ steps.detect-package-manager.outputs.manager }} audit --json > audit.json 2>/dev/null; then | |
| vulnerabilities=$(node -e " | |
| const audit = require('./audit.json'); | |
| const total = audit.metadata?.vulnerabilities?.total || 0; | |
| console.log(total); | |
| ") | |
| if [ "$vulnerabilities" -gt 0 ]; then | |
| echo "⚠️ Found $vulnerabilities security vulnerabilities" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Run \`${{ steps.detect-package-manager.outputs.manager }} audit fix\` to resolve automatically fixable issues." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "✅ No security vulnerabilities found!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "✅ No security vulnerabilities found!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # ============================================================================ | |
| # 代码复杂度分析 | |
| # ============================================================================ | |
| complexity: | |
| name: 🧮 Code Complexity | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Detect package manager | |
| id: detect-package-manager | |
| run: | | |
| if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then | |
| echo "manager=pnpm" >> $GITHUB_OUTPUT | |
| echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/yarn.lock" ]; then | |
| echo "manager=yarn" >> $GITHUB_OUTPUT | |
| echo "command=install" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/package-lock.json" ]; then | |
| echo "manager=npm" >> $GITHUB_OUTPUT | |
| echo "command=ci" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "Unable to determine package manager" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| if: steps.detect-package-manager.outputs.manager == 'pnpm' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.19.0 | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: ${{ steps.detect-package-manager.outputs.manager }} | |
| - name: 📥 Install dependencies | |
| run: | | |
| ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} | |
| ${{ steps.detect-package-manager.outputs.manager }} add -D eslint-plugin-complexity | |
| - name: 🧮 Analyze code complexity | |
| run: | | |
| echo "## 🧮 Code Complexity Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 分析 config-helpers.ts 的复杂度 | |
| if [ -f "utils/config-helpers.ts" ]; then | |
| lines=$(wc -l < utils/config-helpers.ts) | |
| functions=$(grep -c "^export.*function\|^function\|=>" utils/config-helpers.ts || echo "0") | |
| echo "### 📊 Metrics for config-helpers.ts" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Lines of Code | $lines |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Functions | $functions |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Average Lines per Function | $((lines / (functions > 0 ? functions : 1))) |" >> $GITHUB_STEP_SUMMARY | |
| if [ $lines -gt 500 ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "⚠️ **Warning**: File is getting large ($lines lines). Consider splitting into smaller modules." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ File size is within acceptable limits." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| fi | |
| # ============================================================================ | |
| # 文档检查 | |
| # ============================================================================ | |
| documentation: | |
| name: 📚 Documentation Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: 📚 Check documentation coverage | |
| run: | | |
| echo "## 📚 Documentation Coverage" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 检查 JSDoc 覆盖率 | |
| if [ -f "utils/config-helpers.ts" ]; then | |
| total_functions=$(grep -c "^export.*function\|^export const.*=" utils/config-helpers.ts || echo "0") | |
| documented_functions=$(grep -B1 "^export.*function\|^export const.*=" utils/config-helpers.ts | grep -c "/\*\*" || echo "0") | |
| if [ $total_functions -gt 0 ]; then | |
| coverage=$((documented_functions * 100 / total_functions)) | |
| echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Total Functions | $total_functions |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Documented Functions | $documented_functions |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Documentation Coverage | ${coverage}% |" >> $GITHUB_STEP_SUMMARY | |
| if [ $coverage -ge 80 ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ Good documentation coverage!" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "⚠️ Consider adding more JSDoc comments to improve documentation coverage." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| fi | |
| fi | |
| # 检查 README 文件 | |
| if [ -f "tests/README.md" ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ Test documentation is present." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "⚠️ Test documentation is missing." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # ============================================================================ | |
| # 质量总结 | |
| # ============================================================================ | |
| quality-summary: | |
| name: 📋 Quality Summary | |
| runs-on: ubuntu-latest | |
| needs: | |
| [ | |
| formatting, | |
| typescript, | |
| dependencies, | |
| complexity, | |
| documentation, | |
| ] | |
| if: always() | |
| steps: | |
| - name: 📋 Generate quality report | |
| run: | | |
| echo "# 🔍 Code Quality Report" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## 📊 Quality Checks Status" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Code Formatting | ${{ needs.formatting.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| TypeScript | ${{ needs.typescript.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Dependencies | ${{ needs.dependencies.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Code Complexity | ${{ needs.complexity.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Documentation | ${{ needs.documentation.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 计算总体质量分数 | |
| passed=0 | |
| total=5 | |
| ${{ needs.formatting.result == 'success' }} && passed=$((passed + 1)) | |
| ${{ needs.typescript.result == 'success' }} && passed=$((passed + 1)) | |
| ${{ needs.dependencies.result == 'success' }} && passed=$((passed + 1)) | |
| ${{ needs.complexity.result == 'success' }} && passed=$((passed + 1)) | |
| ${{ needs.documentation.result == 'success' }} && passed=$((passed + 1)) | |
| score=$((passed * 100 / total)) | |
| echo "## 🎯 Overall Quality Score: ${score}%" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ $score -ge 90 ]; then | |
| echo "🎉 **Excellent!** Your code quality is outstanding!" >> $GITHUB_STEP_SUMMARY | |
| elif [ $score -ge 75 ]; then | |
| echo "👍 **Good!** Your code quality is solid with room for minor improvements." >> $GITHUB_STEP_SUMMARY | |
| elif [ $score -ge 60 ]; then | |
| echo "⚠️ **Fair.** Consider addressing the failing quality checks." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "❌ **Needs Improvement.** Multiple quality issues need attention." >> $GITHUB_STEP_SUMMARY | |
| fi |