nkds

导航

 

MonkeyCode 代码质量门禁设置实践:从零构建企业级质量防线

引言

在软件开发过程中,代码质量门禁(Quality Gates) 是保证交付质量的核心机制。作为一款支持私有化部署的 AI 编程工具,MonkeyCode 在代码质量管理方面积累了丰富的实践经验。本文将全面分享 MonkeyCode 的质量门禁体系建设方法,帮助团队建立可靠的代码质量保障机制。

GitHub Issue 邀请:如果您在代码质量门禁配置、静态分析工具集成或质量度量方面有任何问题或建议,欢迎前往 MonkeyCode GitHub 仓库 提交 Issue 或参与讨论!


一、为什么需要代码质量门禁?

1.1 传统开发模式的痛点

┌─────────────────────────────────────────────────────────────┐
│              ❌ 没有质量门禁的开发模式                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  开发者 A 写完代码 → 直接提交 → 合并到主分支                  │
│       ↓                                                      │
│  开发者 B 在此基础上继续开发 → 发现基础有问题                   │
│       ↓                                                      │
│  追溯问题 → 花费大量时间定位 → 影响多人工作                    │
│       ↓                                                      │
│  生产环境出现 Bug → 紧急修复 → 压力巨大                        │
│                                                             │
│  💥 结果:技术债务累积、Bug 率高、团队士气低落                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 质量门禁的价值

维度 无门禁 有门禁
Bug 引入率 高(15-25%) 低(<5%)
代码审查效率 低(审查变形式) 高(自动化初筛)
回归风险 高 显著降低
新人上手 困难(无标准约束) 容易(自动检查引导)
技术债务 快速积累 可控增长

二、MonkeyCode 质量门禁体系概览

2.1 四级门禁架构

                    ┌─────────────────────────────────┐
                    │      MonkeyCode 质量门禁体系      │
                    └──────────────┬──────────────────┘
                                   │
        ┌──────────────────────────┼──────────────────────────┐
        ▼                          ▼                          ▼
┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐
│   🟢 L1 本地     │    │   🟡 L2 提交      │    │   🟠 L3 PR       │
│   门禁           │    │   门禁            │    │   门禁           │
├──────────────────┤    ├──────────────────┤    ├──────────────────┤
│ • EditorConfig   │    │ • Git Hooks      │    │ • CI 自动化检查   │
│ • ESLint/Prettier│    │ • pre-commit     │    │ • 单元测试通过    │
│ • IDE 集成       │    │ • 类型检查        │    │ • 代码覆盖率达标  │
│ • 格式化         │    │ • lint 检查       │    │ • 安全扫描        │
│ • 实时错误提示   │    │ • 格式化          │    │ • AI 辅助审查     │
└──────────────────┘    └──────────────────┘    └──────────────────┘
                                                        │
                                                        ▼
                                            ┌──────────────────┐
                                            │   🔴 L4 发布     │
                                            │   门禁           │
                                            ├──────────────────┤
                                            │ • E2E 测试通过    │
                                            │ • 性能基准达标    │
                                            │ • 文档完整性检查  │
                                            │ • 变更日志生成    │
                                            │ • 安全审计通过    │
                                            └──────────────────┘

2.2 各级门禁职责对比

quality_gates:
  
  level_1_local:
    name: "本地开发门禁"
    trigger: "保存文件时 / 编辑时"
    tools:
      - "IDE 内置诊断"
      - "ESLint / Prettier"
      - "TypeScript 类型检查"
      - "EditorConfig"
    blocking: false  # 仅警告,不阻止
    goal: "即时反馈,快速修正"
    
  level_2_commit:
    name: "提交前门禁"
    trigger: "git commit 时"
    tools:
      - "pre-commit hooks (husky)"
      - "lint-staged"
      - "commitlint (规范 commit message)"
      - "格式化检查"
    blocking: true  # 不通过则拒绝提交
    goal: "保证提交的基本质量"
    
  level_3_pr:
    name: "PR 门禁"
    trigger: "创建/更新 Pull Request 时"
    tools:
      - "CI Pipeline (GitHub Actions)"
      - "单元测试 + 集成测试"
      - "代码覆盖率检查"
      - "安全扫描 (Snyk / Trivy)"
      - "AI 代码审查 (MonkeyCode)"
    blocking: true  # 不通过则不能合并
    goal: "保证合并代码的质量基线"
    
  level_4_release:
    name: "发布门禁"
    trigger: "打 tag / 发布时"
    tools:
      - "E2E 测试套件"
      - "性能基准测试"
      - "文档生成与验证"
      - "安全合规扫描"
      - "变更影响分析"
    blocking: true  # 全部通过才能发布
    goal: "保证生产环境的可靠性"

三、L1:本地开发门禁配置

3.1 EditorConfig 统一编码风格

# .editorconfig — MonkeyCode 项目编码规范
root = true

# 默认规则
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2

# Markdown 文件
[*.md]
trim_trailing_whitespace = false
max_line_length = off

# JSON / YAML
[*.{json,yml,yaml}]
indent_size = 2

# Python 文件
[*.py]
indent_size = 4

# Rust / Go
[*.{rs,go}]
indent_style = tab
indent_size = 4

# Shell 脚本
[*.sh]
indent_size = 2

# Dockerfile
[Dockerfile]
indent_size = 4

3.2 ESLint 配置(JavaScript/TypeScript)

// .eslintrc.cjs — MonkeyCode ESLint 规则配置
module.exports = {
  root: true,
  env: {
    browser: true,
    es2022: true,
    node: true,
    jest: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'prettier',  // 与 Prettier 兼容
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: './tsconfig.json',
    tsconfigRootDir: __dirname,
  },
  plugins: [
    '@typescript-eslint',
    'react',
    'react-hooks',
    'import',
    'jsx-a11y',
  ],
  rules: {
    // TypeScript 严格类型检查
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/no-unused-vars': ['error', {
      argsIgnorePattern: '^_',
      varsIgnorePattern: '^_',
    }],
    '@typescript-eslint/explicit-function-return-type': ['warn', {
      allowExpressions: true,
      allowTypedFunctionExpressions: true,
    }],
    '@typescript-eslint/no-floating-promises': 'error',
    '@typescript-eslint/await-thenable': 'error',
    '@typescript-eslint/no-misused-promises': 'error',
    
    // React 规则
    'react/react-in-jsx-scope': 'off',  // React 17+ 不需要
    'react/prop-types': 'off',  // 使用 TypeScript 替代
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'warn',
    
    // Import 排序和规范
    'import/order': ['error', {
      groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'type'],
      'newlines-between': 'always',
      alphabetize: { order: 'asc', caseInsensitive: true },
    }],
    'import/no-duplicates': 'error',
    'import/no-cycle': ['error', { maxDepth: 10 }],
    
    // 代码复杂度
    'complexity': ['warn', { max: 15 }],
    'max-lines-per-function': ['warn', { max: 80, skipBlankLines: true, skipComments: true }],
    'max-depth': ['warn', { max: 4 }],
    'max-params': ['warn', { max: 5 }],
    
    // 最佳实践
    'no-console': ['warn', { allow: ['warn', 'error'] }],
    'no-debugger': 'error',
    'no-alert': 'error',
    'prefer-const': 'error',
    'no-var': 'error',
    eqeqeq: ['error', 'always'],
    curly: ['error', 'all'],
  },
  settings: {
    react: { version: 'detect' },
    'import/resolver': {
      typescript: {},
      node: { extensions: ['.js', '.ts', '.tsx'] },
    },
  },
  ignorePatterns: ['dist/**', 'build/**', '*.config.js', '*.config.ts', 'node_modules/**', '.next/**', 'coverage/**'],
};

3.3 Prettier 配置

// .prettierrc.js — MonkeyCode 格式化配置
module.exports = {
  printWidth: 100,           // 每行最大字符数
  tabWidth: 2,               // 缩进空格数
  useTabs: false,            // 使用空格缩进
  semi: true,                // 行尾分号
  singleQuote: true,         // 使用单引号
  quoteProps: 'as-needed',   // 对象属性引号
  trailingComma: 'all',      // 尾逗号
  bracketSpacing: true,      // 对象括号空格
  bracketSameLine: false,    // JSX 标签换行
  arrowParens: 'always',     // 箭头函数括号
  endOfLine: 'lf',           // 换行符
  proseWrap: 'preserve',     // Markdown 换行
  htmlWhitespaceSensitivity: 'css',
  embeddedLanguageFormatting: 'auto',
  singleAttributePerLine: false,

  overrides: [
    { files: '*.md', options: { printWidth: 80, proseWrap: 'always' } },
    { files: '*.{json,yaml,yml}', options: { tabWidth: 2 } },
  ],
};

3.4 VS Code 工作区配置

// .vscode/settings.json — MonkeyCode VS Code 统一配置
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.organizeImports": "never",
    "source.addMissingImports": "explicit"
  },
  "editor.tabSize": 2,
  "editor.insertSpaces": true,
  "editor.rulers": [100],
  "files.eol": "\n",
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  "[markdown]": { "files.trimTrailingWhitespace": false },
  "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
  "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
  "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
  "typescript.preferences.importModuleSpecifier": "relative",
  "typescript.suggest.autoImports": true,
  "typescript.updateImportsOnFileMove.enabled": "always",
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/.next": true,
    "**/coverage": true
  }
}

四、L2:Git 提交门禁(Pre-commit Hooks)

4.1 Husky + lint-staged 配置

# 安装依赖
npm install --save-dev husky lint-staged @commitlint/cli @commitlint/config-conventional

# 初始化 husky
npx husky init
// package.json — MonkeyCode pre-commit 配置
{
  "name": "monkeyCode",
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": ["eslint --fix --max-warnings=0", "prettier --write"],
    "*.{json,yaml,yml}": ["prettier --write"],
    "*.{md,mdx}": ["prettier --write", "markdownlint-cli2-fix"],
    "*.{css,scss,less}": ["stylelint --fix", "prettier --write"]
  }
}
// commitlint.config.js — MonkeyCode Commit Message 规范
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [2, 'always', [
      'feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test',
      'build', 'ci', 'chore', 'revert', 'release', 'security'
    ]],
    'subject-case': [2, 'never', ['start-case', 'pascal-case', 'UPPER-CASE']],
    'subject-max-length': [2, 'always', 72],
    'body-max-line-length': [2, 'always', 100],
  },
};

4.2 自定义 Pre-commit Hook 示例

#!/bin/sh
# .husky/pre-commit — MonkeyCode 自定义 pre-commit hook

set -e

echo "🔍 Running MonkeyCode quality checks..."

# 检查是否有大文件被添加(> 5MB)
check_large_files() {
  if git diff --cached --name-only | xargs -I {} git diff --cached --size-filter="+5M" -- {} | grep -q .; then
    echo "❌ Error: Files larger than 5MB detected!"
    echo "Please use git-lfs for large files."
    exit 1
  fi
}

# 检查是否包含敏感信息
check_secrets() {
  if git diff --cached --name-only -z | xargs -0 git grep --cached -l -E '(password|secret|api_key|token)\s*[:=]\s*["\x27][^"\x27]{8,}' | grep -q .; then
    echo "⚠️ Warning: Potential secrets detected in staged changes!"
    read -p "Continue anyway? (y/N) " choice
    case "$choice" in y|Y) ;; *) exit 1 ;; esac
  fi
}

check_large_files
check_secrets

echo "✅ All quality checks passed!"

五、L3:PR 门禁与 CI 流水线

5.1 GitHub Actions PR Check 配置

# .github/workflows/pr-quality-gate.yml — MonkeyCode PR 质量门禁
name: 🔒 Quality Gate

on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches: [main, develop]

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref }}
  cancel-in-progress: true

permissions:
  contents: read
  pull-requests: write
  checks: write

env:
  MIN_COVERAGE: 70
  MAX_WARNINGS: 0

jobs:
  code-style:
    name: 🎨 Code Style
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with: { version: 9 }
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile
      - name: ESLint
        run: pnpm eslint . --max-warnings=${{ env.MAX_WARNINGS }}
      - name: Prettier Check
        run: pnpm prettier --check "src/**/*.{ts,tsx,js,jsx,json,css}"
      - name: Type Check
        run: pnpm tsc --noEmit --pretty

  unit-tests:
    name: 🧪 Unit Tests & Coverage
    runs-on: ubuntu-latest
    needs: code-style
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile
      - name: Run Tests with Coverage
        run: pnpm vitest run --coverage --reporter=verbose
      - name: Coverage Threshold Check
        run: |
          COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
          echo "Current coverage: ${COVERAGE}%"
          if (( $(echo "$COVERAGE < $MIN_COVERAGE" | bc -l) )); then
            echo "::error::Coverage ${COVERAGE}% is below minimum threshold of ${MIN_COVERAGE}%"
            exit 1
          fi
      - name: Upload Coverage Report
        uses: codecov/codecov-action@v4
        with: { token: ${{ secrets.CODECOV_TOKEN }}, fail_ci_if_error: false }

  security-scan:
    name: 🔒 Security Scan
    runs-on: ubuntu-latest
    needs: code-style
    steps:
      - uses: actions/checkout@v4
      - name: Run Trivy filesystem scanner
        uses: aquasecurity/trivy-action@master
        with: { scan-type: 'fs', scan-ref: '.', severity: 'CRITICAL,HIGH,MEDIUM', exit-code: '1', ignore-unfixed: true }

  complexity-analysis:
    name: 📊 Complexity Analysis
    runs-on: ubuntu-latest
    needs: unit-tests
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile
      - name: Run Complexity Report
        id: complexity
        run: |
          pnpm eslint . --format=json > eslint-report.json
          HIGH=$(jq '[.[] | select(.messages[].ruleId == "complexity") | length] | add' eslint-report.json)
          DEPTH=$(jq '[.[] | select(.messages[].ruleId == "max-depth") | length] | add' eslint-report.json)
          PARAMS=$(jq '[.[] | select(.messages[].ruleId == "max-params") | length] | add' eslint-report.json)
          echo "high_complexity=$HIGH" >> $GITHUB_OUTPUT
          echo "max_depth_violations=$DEPTH" >> $GITHUB_OUTPUT
          echo "max_params_violations=$PARAMS" >> $GITHUB_OUTPUT
      - name: Comment on PR
        uses: actions/github-script@v7
        with:
          script: |
            const body = `## 📊 Code Complexity Report\n\n` +
              `| Metric | Count | Status |\n|--------|-------|--------|\n` +
              `| High Complexity | \`${{ steps.complexity.outputs.high_complexity }}\` | ⚠️ |\n` +
              `| Max Depth Violations | \`${{ steps.complexity.outputs.max_depth_violations }}\` | ⚠️ |\n`;
            github.rest.issues.createComment({
              owner: context.repo.owner, repo: context.repo.repo,
              issue_number: context.issue.number, body: body
            });

5.2 分支保护规则配置

branch_protection_rules:
  main_branch:
    branch: "main"
    require_pull_request_reviews:
      required_approving_review_count: 2
      dismiss_stale_reviews: true
      require_code_owner_reviews: true
      require_last_push_approval: true
    required_status_checks:
      strict: true
      contexts:
        - "🧪 Unit Tests & Coverage"
        - "🔒 Security Scan"
        - "📊 Complexity Analysis"
        - "🎨 Code Style"
    enforce_admins: true
    force_pushes: { enabled: false }
    deletions: { enabled: false }

六、L4:发布门禁配置

6.1 发布前 Checklist

release_quality_gate:
  pre_release_checks:
    - { name: "Version bump correct", check: "package.json version matches tag", mandatory: true }
    - { name: "Changelog updated", check: "CHANGELOG.md contains current version", mandatory: true }
    - { name: "All tests pass", check: "Full test suite passes on all platforms", mandatory: true }
    - { name: "Coverage >= 80%", check: "Overall coverage meets threshold", mandatory: true }
    - { name: "No critical bugs", check: "GitHub Issues has no open P0/P1", mandatory: true }
    - { name: "Security scan clean", check: "No CRITICAL/HIGH vulnerabilities", mandatory: true }
    - { name: "Documentation complete", check: "API docs and user guide updated", mandatory: true }
    - { name: "Performance OK", check: "Key metrics within ±5% of baseline", mandatory: true }

6.2 发布流水线示例

# .github/workflows/release.yml — MonkeyCode 发布流水线
name: 🚀 Release

on:
  push:
    tags: ['v*']

permissions:
  contents: write
  packages: write

jobs:
  quality-gate:
    runs-on: ubuntu-latest
    outputs: { should_release: "${{ steps.check.outputs.should_release }}" }
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - name: Version Validation
        id: check
        run: |
          TAG="${GITHUB_REF_NAME#v}"
          PKG=$(node -p "require('./package.json').version")
          if [ "$TAG" != "$PKG" ]; then
            echo "::error::Tag ($TAG) != package.json ($PKG)"
            echo "should_release=false" >> $GITHUB_OUTPUT
            exit 1
          fi
          echo "should_release=true" >> $GITHUB_OUTPUT

  full-test-suite:
    runs-on: ${{ matrix.os }}
    needs: quality-gate
    if: needs.quality-gate.outputs.should_release == 'true'
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: ${{ matrix.node-version }}, cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile && pnpm lint && pnpm typecheck && pnpm test:unit --coverage && pnpm test:integration

  security-audit:
    runs-on: ubuntu-latest
    needs: quality-gate
    if: needs.quality-gate.outputs.should_release == 'true'
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile && pnpm audit --audit-level=moderate

  publish:
    runs-on: ubuntu-latest
    needs: [full-test-suite, security-audit]
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, registry-url: 'https://registry.npmjs.org', cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile && pnpm build
      - name: Publish to npm
        env: { NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN } }
        run: pnpm publish --no-git-checks --access public
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with: { generate_release_notes: true, draft: false, prerelease: ${{ contains(github.ref, '-') }}, files: 'dist/*.tgz\nCHANGELOG.md' }

七、常见问题与故障排查

FAQ

问题 解决方案
门禁太严格影响效率? 分级实施、渐进式收紧、例外流程
历史遗留代码? 增量覆盖、baseline 记录、专项清理
团队不遵守? 自动化强制、IDE集成、正向激励
平衡质量和速度? 风险分级、智能门禁、并行化、缓存优化

故障排查速查表

问题现象 可能原因 解决方案
PR 无法合并 CI 未通过 查看 CI 日志修复
Lint 报错不一致 版本不同步 锁定工具版本统一配置
覆盖率下降 新代码缺测试 补充单元测试
Hook 不生效 Husky 未安装 重新运行 husky install
Secret 泄露误报 测试含密钥样例 加入白名单或改写测试

八、最佳实践总结

╔═══════════════════════════════════════════════════════════╗
║  🏆 MonkeyCode 质量门禁十大原则                            ║
║                                                           ║
║  1️⃣ 左移原则 — 越早发现问题,修复成本越低                  ║
║  2️⃣ 自动化优先 — 能自动化的绝不依赖人工                     ║
║  3️⃣ 渐进式实施 — 从简单开始,逐步完善                       ║
║  4️⃣ 数据驱动 — 用指标衡量效果,持续优化                     ║
║  5️⃣ 文化先行 — 工具是手段,质量意识是根本                    ║
║  6️⃣ 分级管理 — 不同场景适用不同严格程度                      ║
║  7️⃣ 反馈及时 — 让开发者秒级获得质量反馈                      ║
║  8️⃣ 透明可视 — 质量指标对全团队公开                         ║
║  9️⃣ 持续迭代 — 定期回顾和调整门禁规则                       ║
║  🔟 平衡艺术 — 质量和速度需要找到平衡点                      ║
║                                                           ║
╚═══════════════════════════════════════════════════════════╝

九、总结与行动号召

本文详细介绍了 MonkeyCode 四级代码质量门禁体系的完整实施方案:

层级 核心价值 关键工具 实施难度
L1 本地门禁 即时反馈 ESLint, Prettier, EditorConfig ⭐
L2 提交门禁 保证提交质量 Husky, lint-staged, commitlint ⭐⭐
L3 PR 门禁 保证合并质量 GitHub Actions, 测试, 安全扫描 ⭐⭐⭐
L4 发布门禁 保证生产质量 E2E 测试, 性能基准, 安全审计 ⭐⭐⭐⭐

记住:质量门禁不是目的,而是手段。真正的目标是建立全员参与的质量文化!

  • 🔧 贡献配置模板:帮我们完善各语言的门禁配置
  • 🐛 报告质量问题:在 GitHub Issue 中标注 [quality-gate] 前缀
  • 💬 参与 讨论:在 GitHub Discussions 中交流心得

现在就访问 MonkeyCode GitHub,查看我们的完整质量门禁配置,提出你的改进建议吧!


本文最后更新于 2026 年 7 月 1 日。请以 GitHub 仓库最新信息为准。

相关文章推荐:


© 2026 MonkeyCode Open Source Project. Licensed under Apache License 2.0.

posted on 2026-07-01 12:43  MonkeyCode  阅读(47)  评论(0)    收藏  举报