feat(ci): 代码质量深度加固 - mypy/ruff/vulture 接入Validate #328
@@ -166,6 +166,53 @@ jobs:
|
||||
python3 -m isort --check-only alembic apps packages tests scripts
|
||||
python3 -m flake8 apps packages tests --count --statistics
|
||||
|
||||
- name: Ruff lint (advisory mode - 摸底阶段)
|
||||
if: always()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== Installing ruff ==="
|
||||
python3 -m pip install -q ruff
|
||||
ruff --version
|
||||
echo ""
|
||||
echo "=== Running ruff lint (advisory mode) ==="
|
||||
echo "告警模式,不阻断CI。用于摸底问题数量,后续分批修复后正式替换flake8。"
|
||||
echo ""
|
||||
ruff check apps packages tests scripts --statistics --output-format concise 2>&1 | tail -30
|
||||
EXIT_CODE=$?
|
||||
echo ""
|
||||
if [ "$EXIT_CODE" != "0" ]; then
|
||||
echo "ruff 发现 lint 问题(告警模式,不阻断)"
|
||||
echo "问题分类统计见上方,后续将分批修复"
|
||||
else
|
||||
echo "ruff 检查全部通过 ✅"
|
||||
fi
|
||||
exit 0
|
||||
|
||||
- name: Type check (mypy, advisory mode)
|
||||
if: always()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== Installing mypy ==="
|
||||
python3 -m pip install -q mypy
|
||||
mypy --version
|
||||
echo ""
|
||||
echo "=== Running mypy type check (advisory mode) ==="
|
||||
echo "告警模式,不阻断CI"
|
||||
echo ""
|
||||
# 只检查核心业务代码,跳过测试和迁移
|
||||
EXIT_CODE=0
|
||||
mypy apps/api/app packages --ignore-missing-imports --no-site-packages --no-strict-optional --explicit-package-bases --exclude 'tests/|test_|migrations/|alembic/' --no-error-summary 2>&1 | head -60 || EXIT_CODE=$?
|
||||
echo ""
|
||||
if [ "$EXIT_CODE" != "0" ]; then
|
||||
echo "mypy 发现类型问题(告警模式,不阻断)"
|
||||
echo "建议后续逐步修复"
|
||||
else
|
||||
echo "mypy 类型检查通过 ✅"
|
||||
fi
|
||||
exit 0
|
||||
|
||||
- name: Run security scan (bandit)
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -196,23 +243,30 @@ jobs:
|
||||
exit 0
|
||||
|
||||
- name: Dead code detection (vulture)
|
||||
if: always()
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
set +e
|
||||
echo "=== Installing vulture ==="
|
||||
python3 -m pip install -q vulture
|
||||
vulture --version
|
||||
echo ""
|
||||
echo "=== Running vulture dead code scan ==="
|
||||
EXIT_CODE=0
|
||||
echo "=== Running vulture dead code scan (confidence >= 70%) ==="
|
||||
echo "告警模式,不阻断CI。置信度>=90%建议尽快确认。"
|
||||
echo ""
|
||||
# 按置信度从高到低输出,便于优先查看高价值条目
|
||||
vulture apps packages scripts \
|
||||
--exclude "tests,test,migrations,.gitea,docs,node_modules,site-packages,*/test_*.py,*/conftest.py" \
|
||||
--min-confidence 80 \
|
||||
2>&1 | head -60 || EXIT_CODE=$?
|
||||
--min-confidence 70 \
|
||||
2>&1 | sort -t'(' -k2 -rn | head -80
|
||||
EXIT_CODE=$?
|
||||
echo ""
|
||||
echo "vulture scan completed (advisory mode - P2, for reference only)"
|
||||
echo "=== vulture scan summary ==="
|
||||
if [ "$EXIT_CODE" != "0" ]; then
|
||||
echo "NOTE: Potential dead code found (may include false positives from framework code)."
|
||||
echo "发现潜在死代码(可能包含框架装饰器注册的函数,为误报)"
|
||||
echo "建议:定期人工审查高置信度(>=90%)条目"
|
||||
else
|
||||
echo "未发现明显死代码 ✅"
|
||||
fi
|
||||
exit 0
|
||||
|
||||
|
||||
+50
-18
@@ -48,23 +48,55 @@ omit = [
|
||||
]
|
||||
branch = true
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"pragma: no cover",
|
||||
"def __repr__",
|
||||
"if __name__ == .__main__.:",
|
||||
"raise NotImplementedError",
|
||||
"pass",
|
||||
"if TYPE_CHECKING:",
|
||||
"class .*Protocol",
|
||||
"@abstractmethod",
|
||||
"raise AssertionError",
|
||||
"raise RuntimeError",
|
||||
"if 0:",
|
||||
"if __debug__:",
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
line-length = 120
|
||||
exclude = [
|
||||
".git",
|
||||
".cache",
|
||||
"__pycache__",
|
||||
".venv",
|
||||
"venv",
|
||||
"node_modules",
|
||||
"alembic",
|
||||
".gitea",
|
||||
".next",
|
||||
"dist",
|
||||
"build",
|
||||
]
|
||||
show_missing = true
|
||||
skip_covered = false
|
||||
|
||||
[tool.coverage.xml]
|
||||
output = "coverage.xml"
|
||||
[tool.ruff.lint]
|
||||
# 当前阶段:摸底模式,规则集与原flake8对齐
|
||||
# 后续迭代计划:
|
||||
# Phase 1: 修完 bugbear 后正式替换 flake8
|
||||
# Phase 2: 启用 UP(pyupgrade) + SIM(simplify)
|
||||
# Phase 3: 启用 RET(return) + ARG(unused-args)
|
||||
select = [
|
||||
"E", # pycodestyle errors(同flake8)
|
||||
"F", # pyflakes(同flake8)
|
||||
"W", # pycodestyle warnings(同flake8)
|
||||
"B", # flake8-bugbear(新增,摸底用)
|
||||
]
|
||||
# 与原 setup.cfg flake8 配置对齐,确保不新增阻断
|
||||
ignore = [
|
||||
"E203",
|
||||
"W503",
|
||||
"E501", # line-too-long(black管)
|
||||
"E302",
|
||||
"E402", # module-import-not-at-top(循环导入多)
|
||||
"E722", # bare-except
|
||||
"W291",
|
||||
"W293",
|
||||
"F401", # unused-import
|
||||
"F403",
|
||||
"F405",
|
||||
"F841", # unused-variable
|
||||
"B008", # do-not-perform-callback-from-arg(fastapi依赖注入)
|
||||
]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"__init__.py" = ["F401", "F403", "F405"]
|
||||
"tests/*" = ["E402", "F401", "F841"]
|
||||
"packages/ports/*" = ["E301", "E704"]
|
||||
"apps/*/migrations/*" = ["ALL"]
|
||||
"alembic/*" = ["ALL"]
|
||||
|
||||
Reference in New Issue
Block a user