Skip to content

🔍 Code Quality

🔍 Code Quality #99

Workflow file for this run

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