diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index fbc83a070..828bdd871 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -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 diff --git a/pyproject.toml b/pyproject.toml index 7a75f45dd..bba37e42e 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -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"]