py-wlcli 0.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py_wlcli-0.8.0.dist-info/METADATA +139 -0
- py_wlcli-0.8.0.dist-info/RECORD +320 -0
- py_wlcli-0.8.0.dist-info/WHEEL +4 -0
- py_wlcli-0.8.0.dist-info/entry_points.txt +2 -0
- py_wlcli-0.8.0.dist-info/licenses/LICENSE +21 -0
- wl_cli/__init__.py +27 -0
- wl_cli/__main__.py +130 -0
- wl_cli/capabilities.py +79 -0
- wl_cli/cc/__init__.py +5 -0
- wl_cli/cc/checks.py +1019 -0
- wl_cli/cc/cli.py +370 -0
- wl_cli/cc/mutate.py +1350 -0
- wl_cli/cli_click.py +156 -0
- wl_cli/commands/__init__.py +84 -0
- wl_cli/commands/base.py +80 -0
- wl_cli/commands/buildcommands/__init__.py +1 -0
- wl_cli/commands/buildcommands/build.py +71 -0
- wl_cli/commands/buildcommands/build_utils.py +47 -0
- wl_cli/commands/buildcommands/builders/__init__.py +18 -0
- wl_cli/commands/buildcommands/builders/cleanup.py +35 -0
- wl_cli/commands/buildcommands/builders/coordinator.py +122 -0
- wl_cli/commands/buildcommands/builders/environment.py +81 -0
- wl_cli/commands/buildcommands/builders/rust_builder.py +39 -0
- wl_cli/commands/buildcommands/builders/stubs.py +58 -0
- wl_cli/commands/buildcommands/dist.py +326 -0
- wl_cli/commands/buildcommands/test.py +89 -0
- wl_cli/commands/clean/__init__.py +1 -0
- wl_cli/commands/clean/build.py +151 -0
- wl_cli/commands/clean/clean.py +294 -0
- wl_cli/commands/clean/clean_utils.py +77 -0
- wl_cli/commands/clean/core.py +236 -0
- wl_cli/commands/clean/dead_code/__init__.py +0 -0
- wl_cli/commands/clean/dead_code/dead_code_command.py +70 -0
- wl_cli/commands/clean/dead_code/detector.py +161 -0
- wl_cli/commands/clean/dead_code/fixer.py +176 -0
- wl_cli/commands/clean/dead_code/reporter.py +295 -0
- wl_cli/commands/clean/dead_code/utils.py +0 -0
- wl_cli/commands/clean/lfs.py +215 -0
- wl_cli/commands/clean/python.py +81 -0
- wl_cli/commands/clean/rust.py +91 -0
- wl_cli/commands/clean/utils/__init__.py +34 -0
- wl_cli/commands/clean/venv.py +91 -0
- wl_cli/commands/cleanup.py +73 -0
- wl_cli/commands/click_base.py +79 -0
- wl_cli/commands/config/__init__.py +1 -0
- wl_cli/commands/config/config.py +291 -0
- wl_cli/commands/debug/__init__.py +6 -0
- wl_cli/commands/debug/debug.py +309 -0
- wl_cli/commands/debug/debug_cache.py +86 -0
- wl_cli/commands/debug/debug_subagent.py +156 -0
- wl_cli/commands/debug/output_formatter.py +165 -0
- wl_cli/commands/debug/source_hasher.py +92 -0
- wl_cli/commands/format/__init__.py +13 -0
- wl_cli/commands/format/format_cache_adapter.py +125 -0
- wl_cli/commands/format/format_command.py +197 -0
- wl_cli/commands/format/format_coordinator.py +191 -0
- wl_cli/commands/format/format_executor.py +470 -0
- wl_cli/commands/format/format_outcome.py +44 -0
- wl_cli/commands/format/format_path_handler.py +1016 -0
- wl_cli/commands/format/format_progress.py +62 -0
- wl_cli/commands/format/format_reporter.py +31 -0
- wl_cli/commands/format/python_formatter.py +506 -0
- wl_cli/commands/format/rust_formatter.py +106 -0
- wl_cli/commands/gate/__init__.py +1 -0
- wl_cli/commands/gate/gate_command.py +862 -0
- wl_cli/commands/gate/preflight.py +445 -0
- wl_cli/commands/git/__init__.py +1 -0
- wl_cli/commands/git/config.py +169 -0
- wl_cli/commands/git/git_facts.py +60 -0
- wl_cli/commands/git/git_flow.py +86 -0
- wl_cli/commands/git/hook.py +112 -0
- wl_cli/commands/git/policy.py +216 -0
- wl_cli/commands/git/push_update.py +82 -0
- wl_cli/commands/initenv/__init__.py +1 -0
- wl_cli/commands/initenv/common/__init__.py +23 -0
- wl_cli/commands/initenv/common/check_git_bash.py +78 -0
- wl_cli/commands/initenv/common/error_handler.py +68 -0
- wl_cli/commands/initenv/common/exceptions.py +52 -0
- wl_cli/commands/initenv/components/__init__.py +4 -0
- wl_cli/commands/initenv/components/cargo_sync.py +240 -0
- wl_cli/commands/initenv/components/config_manager.py +106 -0
- wl_cli/commands/initenv/components/directory_utils.py +71 -0
- wl_cli/commands/initenv/components/git/__init__.py +9 -0
- wl_cli/commands/initenv/components/git/branch_creator.py +143 -0
- wl_cli/commands/initenv/components/git/git_flow_interface.py +24 -0
- wl_cli/commands/initenv/components/git/git_flow_manager.py +159 -0
- wl_cli/commands/initenv/components/git/git_lfs_manager.py +272 -0
- wl_cli/commands/initenv/components/git/git_utility.py +254 -0
- wl_cli/commands/initenv/components/git/gitignore_manager.py +53 -0
- wl_cli/commands/initenv/components/git_initializer.py +212 -0
- wl_cli/commands/initenv/components/i18n_manager.py +104 -0
- wl_cli/commands/initenv/components/log_manager.py +241 -0
- wl_cli/commands/initenv/components/project_structure/__init__.py +23 -0
- wl_cli/commands/initenv/components/project_structure/config_generator.py +360 -0
- wl_cli/commands/initenv/components/project_structure/directory_creator.py +184 -0
- wl_cli/commands/initenv/components/project_structure/hook_source.py +110 -0
- wl_cli/commands/initenv/components/project_structure/hooks_manager.py +995 -0
- wl_cli/commands/initenv/components/project_structure/readme_handler.py +56 -0
- wl_cli/commands/initenv/components/project_structure/rust_files_handler.py +30 -0
- wl_cli/commands/initenv/components/project_structure/setup_handler.py +103 -0
- wl_cli/commands/initenv/components/project_structure/sop_generator.py +73 -0
- wl_cli/commands/initenv/components/project_structure/template_copier.py +104 -0
- wl_cli/commands/initenv/components/project_structure/template_manager.py +195 -0
- wl_cli/commands/initenv/components/pyproject_generator.py +194 -0
- wl_cli/commands/initenv/components/rust_initializer.py +145 -0
- wl_cli/commands/initenv/components/symlink_cleaner.py +99 -0
- wl_cli/commands/initenv/components/symlink_manager.py +52 -0
- wl_cli/commands/initenv/components/venv_manager.py +118 -0
- wl_cli/commands/initenv/initenv.py +169 -0
- wl_cli/commands/initenv/services/__init__.py +11 -0
- wl_cli/commands/initenv/services/environment_initializer.py +288 -0
- wl_cli/commands/initenv/services/git_lfs_initializer.py +26 -0
- wl_cli/commands/initenv/services/project_structure_initializer.py +52 -0
- wl_cli/commands/lfs/README.md +221 -0
- wl_cli/commands/lfs/__init__.py +5 -0
- wl_cli/commands/lfs/cli.py +106 -0
- wl_cli/commands/lfs/config.py +164 -0
- wl_cli/commands/lfs/hook.py +61 -0
- wl_cli/commands/lfs/initializer.py +531 -0
- wl_cli/commands/lfs/manager.py +95 -0
- wl_cli/commands/lfs/policy.py +165 -0
- wl_cli/commands/lfs/watcher.py +294 -0
- wl_cli/commands/lint/__init__.py +1 -0
- wl_cli/commands/lint/lint_command.py +297 -0
- wl_cli/commands/lint/lint_executor.py +409 -0
- wl_cli/commands/lint/lint_reporter.py +579 -0
- wl_cli/commands/lint/lint_run.py +258 -0
- wl_cli/commands/lint/mypy_config.py +90 -0
- wl_cli/commands/registry.py +103 -0
- wl_cli/commands/self/__init__.py +7 -0
- wl_cli/commands/self/common/__init__.py +8 -0
- wl_cli/commands/self/common/capabilities.py +30 -0
- wl_cli/commands/self/common/config.py +27 -0
- wl_cli/commands/self/common/version_cache.py +85 -0
- wl_cli/commands/self/handlers/__init__.py +19 -0
- wl_cli/commands/self/handlers/base_handler.py +28 -0
- wl_cli/commands/self/handlers/install_handler.py +85 -0
- wl_cli/commands/self/handlers/status_handler.py +66 -0
- wl_cli/commands/self/handlers/uninstall_handler.py +58 -0
- wl_cli/commands/self/handlers/update_handler.py +102 -0
- wl_cli/commands/self/handlers/version_handler.py +16 -0
- wl_cli/commands/self/self_command.py +237 -0
- wl_cli/commands/self/services/__init__.py +15 -0
- wl_cli/commands/self/services/installation_manager.py +187 -0
- wl_cli/commands/self/services/local_installer.py +165 -0
- wl_cli/commands/self/services/pypi_updater.py +278 -0
- wl_cli/commands/self/services/windows_update.py +174 -0
- wl_cli/commands/testcommands/__init__.py +8 -0
- wl_cli/commands/testcommands/base_dependency_analyzer.py +198 -0
- wl_cli/commands/testcommands/batch_processor.py +278 -0
- wl_cli/commands/testcommands/cache_manager.py +1156 -0
- wl_cli/commands/testcommands/coverage_analyzer.py +955 -0
- wl_cli/commands/testcommands/coverage_cache_manager.py +183 -0
- wl_cli/commands/testcommands/progress_manager.py +79 -0
- wl_cli/commands/testcommands/python_env_detector.py +207 -0
- wl_cli/commands/testcommands/report_generator.py +101 -0
- wl_cli/commands/testcommands/single_test_executor.py +250 -0
- wl_cli/commands/testcommands/speed_checker.py +118 -0
- wl_cli/commands/testcommands/test_command_builder.py +165 -0
- wl_cli/commands/testcommands/test_commands.py +786 -0
- wl_cli/commands/testcommands/test_reporter.py +181 -0
- wl_cli/commands/testcommands/test_result_handler.py +96 -0
- wl_cli/commands/testcommands/test_runner.py +1343 -0
- wl_cli/commands/testcommands/test_utils.py +197 -0
- wl_cli/commands/testcommands/utils/__init__.py +17 -0
- wl_cli/commands/testcommands/utils/coverage_parser.py +98 -0
- wl_cli/commands/testcommands/utils/env_info.py +36 -0
- wl_cli/commands/testcommands/utils/junit_parser.py +75 -0
- wl_cli/commands/testcommands/utils/markdown_utils.py +20 -0
- wl_cli/commands/testcommands/utils/project_root.py +61 -0
- wl_cli/commands/update/__init__.py +9 -0
- wl_cli/commands/update/services/__init__.py +21 -0
- wl_cli/commands/update/services/backup_manager.py +207 -0
- wl_cli/commands/update/services/component_manager.py +83 -0
- wl_cli/commands/update/services/conflict_resolver.py +189 -0
- wl_cli/commands/update/services/vendors_updater.py +85 -0
- wl_cli/commands/update/services/version_tracker.py +127 -0
- wl_cli/commands/update/update_command.py +270 -0
- wl_cli/commands/update/utils/__init__.py +3 -0
- wl_cli/commands/version/__init__.py +9 -0
- wl_cli/commands/version/version_command.py +155 -0
- wl_cli/commands/workflow.py +477 -0
- wl_cli/env/__init__.py +5 -0
- wl_cli/env/cli.py +167 -0
- wl_cli/env_status.py +157 -0
- wl_cli/envelope.py +91 -0
- wl_cli/exceptions.py +85 -0
- wl_cli/lib/__init__.py +3 -0
- wl_cli/lib/rust_utils.py +35 -0
- wl_cli/mcp/__init__.py +6 -0
- wl_cli/mcp/capabilities.py +19 -0
- wl_cli/mcp/cli.py +22 -0
- wl_cli/mcp/gitlab.py +553 -0
- wl_cli/mcp/k8s.py +344 -0
- wl_cli/mcp/protocol.py +159 -0
- wl_cli/platform.py +139 -0
- wl_cli/quality/__init__.py +18 -0
- wl_cli/utils/__init__.py +7 -0
- wl_cli/utils/cache.py +491 -0
- wl_cli/utils/cache_ledger.py +355 -0
- wl_cli/utils/cache_store.py +546 -0
- wl_cli/utils/config/__init__.py +27 -0
- wl_cli/utils/config/config_loader.py +163 -0
- wl_cli/utils/config/core.py +862 -0
- wl_cli/utils/config/defaults.py +142 -0
- wl_cli/utils/config/env_exporter.py +86 -0
- wl_cli/utils/config/env_parser.py +108 -0
- wl_cli/utils/config/validation.py +280 -0
- wl_cli/utils/error_handler.py +165 -0
- wl_cli/utils/file_copier.py +56 -0
- wl_cli/utils/file_operations.py +506 -0
- wl_cli/utils/language_utils.py +122 -0
- wl_cli/utils/lazy_import.py +240 -0
- wl_cli/utils/log_levels.py +35 -0
- wl_cli/utils/log_rotators.py +74 -0
- wl_cli/utils/logging.py +458 -0
- wl_cli/utils/output_context.py +142 -0
- wl_cli/utils/performance/__init__.py +1 -0
- wl_cli/utils/performance/decorators.py +111 -0
- wl_cli/utils/performance/exporter.py +38 -0
- wl_cli/utils/performance/models.py +16 -0
- wl_cli/utils/performance/monitor.py +161 -0
- wl_cli/utils/performance_monitor.py +32 -0
- wl_cli/utils/platform_adapter.py +131 -0
- wl_cli/utils/pre_commit.py +266 -0
- wl_cli/utils/pre_commit_config.py +72 -0
- wl_cli/utils/root.py +521 -0
- wl_cli/utils/root_fallback.py +256 -0
- wl_cli/utils/run_evidence.py +236 -0
- wl_cli/utils/structured_logger.py +18 -0
- wl_cli/utils/structured_logging/__init__.py +19 -0
- wl_cli/utils/structured_logging/config.py +337 -0
- wl_cli/utils/structured_logging/core.py +177 -0
- wl_cli/utils/structured_logging/env.py +56 -0
- wl_cli/utils/structured_logging/filtering.py +75 -0
- wl_cli/utils/structured_logging/filters.py +55 -0
- wl_cli/utils/structured_logging/formatters.py +251 -0
- wl_cli/utils/structured_logging/handlers.py +308 -0
- wl_cli/utils/structured_logging/logger.py +354 -0
- wl_cli/utils/subprocess.py +71 -0
- wl_cli/utils/subprocess_utils.py +260 -0
- wl_cli/utils/test_utils/__init__.py +5 -0
- wl_cli/utils/test_utils/test_filter.py +36 -0
- wl_cli/utils/uv_run.py +79 -0
- wl_cli/utils/uv_tool.py +117 -0
- wl_cli/utils/uv_tree.py +71 -0
- wl_cli/utils/uv_workspace.py +174 -0
- wl_cli/utils/version/__init__.py +15 -0
- wl_cli/utils/version/pypi_version_checker.py +95 -0
- wl_cli/utils/version/version_comparator.py +133 -0
- wl_cli/utils/version/version_detectors.py +312 -0
- wl_cli/utils/version/version_service.py +131 -0
- wl_cli/utils/version/version_updater.py +198 -0
- wl_cli/utils/wl_dir_updater.py +1440 -0
- wl_cli/utils/workspace_detector/__init__.py +28 -0
- wl_cli/utils/workspace_detector/core.py +161 -0
- wl_cli/utils/workspace_detector/detection_strategies.py +107 -0
- wl_cli/utils/workspace_detector/exceptions.py +5 -0
- wl_cli/utils/workspace_detector/types.py +17 -0
- wl_cli/utils/workspace_detector/venv_resolver.py +84 -0
- wl_cli/vendors/config/.codespellrc +2 -0
- wl_cli/vendors/config/dependencies.toml +10 -0
- wl_cli/vendors/config/mypy.ini +62 -0
- wl_cli/vendors/config/pyproject_defaults.toml +28 -0
- wl_cli/vendors/config/template_config.toml +24 -0
- wl_cli/vendors/config/tool_configs.toml +76 -0
- wl_cli/vendors/git/.gitignore +122 -0
- wl_cli/vendors/git/.pre-commit-config.yaml +37 -0
- wl_cli/vendors/hooks/applypatch-msg.sample +15 -0
- wl_cli/vendors/hooks/commit-msg.sample +24 -0
- wl_cli/vendors/hooks/fsmonitor-watchman.sample +174 -0
- wl_cli/vendors/hooks/post-update.sample +8 -0
- wl_cli/vendors/hooks/pre-applypatch.sample +14 -0
- wl_cli/vendors/hooks/pre-commit +45 -0
- wl_cli/vendors/hooks/pre-commit.legacy +31 -0
- wl_cli/vendors/hooks/pre-commit.sample +49 -0
- wl_cli/vendors/hooks/pre-merge-commit.sample +13 -0
- wl_cli/vendors/hooks/pre-push.sample +60 -0
- wl_cli/vendors/hooks/pre-rebase.sample +169 -0
- wl_cli/vendors/hooks/pre-receive.sample +24 -0
- wl_cli/vendors/hooks/prepare-commit-msg.sample +42 -0
- wl_cli/vendors/hooks/push-to-checkout.sample +78 -0
- wl_cli/vendors/hooks/sendemail-validate.sample +77 -0
- wl_cli/vendors/hooks/unix/applypatch-msg.sample +15 -0
- wl_cli/vendors/hooks/unix/check_lockfile.py +58 -0
- wl_cli/vendors/hooks/unix/check_lockfile.sh +36 -0
- wl_cli/vendors/hooks/unix/commit-msg.sample +24 -0
- wl_cli/vendors/hooks/unix/fsmonitor-watchman.sample +174 -0
- wl_cli/vendors/hooks/unix/post-update.sample +8 -0
- wl_cli/vendors/hooks/unix/pre-applypatch.sample +14 -0
- wl_cli/vendors/hooks/unix/pre-commit +190 -0
- wl_cli/vendors/hooks/unix/pre-commit.legacy +31 -0
- wl_cli/vendors/hooks/unix/pre-commit.py +81 -0
- wl_cli/vendors/hooks/unix/pre-commit.sample +49 -0
- wl_cli/vendors/hooks/unix/pre-merge-commit.sample +13 -0
- wl_cli/vendors/hooks/unix/pre-push +417 -0
- wl_cli/vendors/hooks/unix/pre-push.sample +53 -0
- wl_cli/vendors/hooks/unix/pre-rebase.sample +169 -0
- wl_cli/vendors/hooks/unix/pre-receive.sample +24 -0
- wl_cli/vendors/hooks/unix/prepare-commit-msg.sample +42 -0
- wl_cli/vendors/hooks/update.sample +128 -0
- wl_cli/vendors/hooks/win/work.bat +63 -0
- wl_cli/vendors/project/.gitignore +90 -0
- wl_cli/vendors/project/.python-version +1 -0
- wl_cli/vendors/project/LICENSE +21 -0
- wl_cli/vendors/project/README.md +0 -0
- wl_cli/vendors/project/pyproject.toml +27 -0
- wl_cli/vendors/project/pyproject_no_workspace.toml +16 -0
- wl_cli/vendors/project/pyproject_workspace.toml +14 -0
- wl_cli/vendors/readme/README.md +120 -0
- wl_cli/vendors/rust/Cargo.toml +14 -0
- wl_cli/vendors/rust/lib/__init__.py +3 -0
- wl_cli/vendors/rust/lib/rust_utils.py +31 -0
- wl_cli/vendors/rust/src/lib.rs +13 -0
- wl_cli/vendors/rust/src/main.rs +3 -0
- wl_cli/vendors/rust/tests/test_rust_fallback.py +40 -0
- wl_cli/vendors/sop_doc/git-dev-sop.md +220 -0
- wl_cli/vendors/sop_doc/industrial-standard-sop.md +145 -0
- wl_cli/vendors/sop_doc/python-sop.md +342 -0
- wl_cli/vendors/sop_doc/rust-readme.md +219 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ...utils.logging import log_info_pair
|
|
4
|
+
from .utils import (
|
|
5
|
+
coverage_totals,
|
|
6
|
+
file_entries,
|
|
7
|
+
fmt_pct,
|
|
8
|
+
get_env_info,
|
|
9
|
+
parse_junit,
|
|
10
|
+
read_json,
|
|
11
|
+
read_xml,
|
|
12
|
+
write_md,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# Re-export private functions for backward compatibility (used in tests)
|
|
16
|
+
_coverage_totals = coverage_totals
|
|
17
|
+
_file_entries = file_entries
|
|
18
|
+
_fmt_pct = fmt_pct
|
|
19
|
+
_get_env_info = get_env_info
|
|
20
|
+
_parse_junit = parse_junit
|
|
21
|
+
_read_json = read_json
|
|
22
|
+
_read_xml = read_xml
|
|
23
|
+
_write_md = write_md
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def generate_reports(
|
|
27
|
+
coverage_json_path: str,
|
|
28
|
+
junit_xml_path: str,
|
|
29
|
+
out_cov: str,
|
|
30
|
+
out_err: str,
|
|
31
|
+
project_root: str,
|
|
32
|
+
) -> str:
|
|
33
|
+
_log_inputs(coverage_json_path, junit_xml_path, out_cov, out_err)
|
|
34
|
+
cov = _read_json(coverage_json_path)
|
|
35
|
+
junit = _read_xml(junit_xml_path)
|
|
36
|
+
env_info = _get_env_info()
|
|
37
|
+
|
|
38
|
+
line_pct, branch_pct, num_lines, num_branches, num_files = _coverage_totals(cov)
|
|
39
|
+
files = _file_entries(cov, project_root)
|
|
40
|
+
top_files = sorted(files, key=lambda x: x[1] or 0.0, reverse=True)[:10]
|
|
41
|
+
low_files = sorted(files, key=lambda x: x[1] or 0.0)[:10]
|
|
42
|
+
|
|
43
|
+
cov_lines = _build_coverage_lines(
|
|
44
|
+
env_info,
|
|
45
|
+
line_pct,
|
|
46
|
+
branch_pct,
|
|
47
|
+
num_lines,
|
|
48
|
+
num_branches,
|
|
49
|
+
num_files,
|
|
50
|
+
top_files,
|
|
51
|
+
low_files,
|
|
52
|
+
)
|
|
53
|
+
_write_md(out_cov, cov_lines)
|
|
54
|
+
_log_written(out_cov)
|
|
55
|
+
|
|
56
|
+
tests, failures, errors, skipped, warnings, time_spent, cases = _parse_junit(junit)
|
|
57
|
+
err_lines = _build_error_lines(
|
|
58
|
+
env_info, tests, failures, errors, skipped, warnings, time_spent, cases
|
|
59
|
+
)
|
|
60
|
+
_write_md(out_err, err_lines)
|
|
61
|
+
_log_written(out_err)
|
|
62
|
+
|
|
63
|
+
summary = f"总行覆盖率 {fmt_pct(line_pct)} | 分支覆盖率 {fmt_pct(branch_pct)} | 文件数 {num_files} | 失败用例 {failures + errors}"
|
|
64
|
+
return summary
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _log_inputs(
|
|
68
|
+
coverage_json_path: str, junit_xml_path: str, out_cov: str, out_err: str
|
|
69
|
+
) -> None:
|
|
70
|
+
try:
|
|
71
|
+
log_info_pair(
|
|
72
|
+
f"Generating coverage report to: {out_cov}",
|
|
73
|
+
f"生成覆盖率报告到: {out_cov}",
|
|
74
|
+
)
|
|
75
|
+
log_info_pair(
|
|
76
|
+
f"Generating error report to: {out_err}",
|
|
77
|
+
f"生成错误报告到: {out_err}",
|
|
78
|
+
)
|
|
79
|
+
log_info_pair(
|
|
80
|
+
f"Coverage JSON source: {coverage_json_path}",
|
|
81
|
+
f"覆盖率JSON来源: {coverage_json_path}",
|
|
82
|
+
)
|
|
83
|
+
log_info_pair(
|
|
84
|
+
f"JUnit XML source: {junit_xml_path}",
|
|
85
|
+
f"JUnit XML来源: {junit_xml_path}",
|
|
86
|
+
)
|
|
87
|
+
except Exception:
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _log_written(path: str) -> None:
|
|
92
|
+
try:
|
|
93
|
+
log_info_pair(
|
|
94
|
+
f"Coverage Markdown written: {path}",
|
|
95
|
+
f"覆盖率Markdown已写入: {path}",
|
|
96
|
+
)
|
|
97
|
+
except Exception:
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _build_coverage_lines(
|
|
102
|
+
env_info,
|
|
103
|
+
line_pct,
|
|
104
|
+
branch_pct,
|
|
105
|
+
num_lines,
|
|
106
|
+
num_branches,
|
|
107
|
+
num_files,
|
|
108
|
+
top_files,
|
|
109
|
+
low_files,
|
|
110
|
+
) -> list[str]:
|
|
111
|
+
cov_lines: list[str] = []
|
|
112
|
+
cov_lines.append("# WL 测试覆盖率报告")
|
|
113
|
+
cov_lines.append("")
|
|
114
|
+
cov_lines.append("## 测试环境")
|
|
115
|
+
cov_lines.extend([f"- {x}" for x in env_info])
|
|
116
|
+
cov_lines.append("")
|
|
117
|
+
cov_lines.append("## 总览")
|
|
118
|
+
cov_lines.append(f"- 行覆盖率: {fmt_pct(line_pct)}")
|
|
119
|
+
cov_lines.append(f"- 分支覆盖率: {fmt_pct(branch_pct)}")
|
|
120
|
+
cov_lines.append(f"- 语句数: {num_lines if num_lines else 'N/A'}")
|
|
121
|
+
cov_lines.append(f"- 分支数: {num_branches if num_branches else 'N/A'}")
|
|
122
|
+
cov_lines.append(f"- 文件数: {num_files}")
|
|
123
|
+
cov_lines.append("")
|
|
124
|
+
cov_lines.append("## Top 文件")
|
|
125
|
+
for rel, lp, bp in top_files:
|
|
126
|
+
cov_lines.append(f"- `{rel}` | 行 {fmt_pct(lp)} | 分支 {fmt_pct(bp)}")
|
|
127
|
+
cov_lines.append("")
|
|
128
|
+
cov_lines.append("## 低覆盖率文件")
|
|
129
|
+
for rel, lp, bp in low_files:
|
|
130
|
+
cov_lines.append(f"- `{rel}` | 行 {fmt_pct(lp)} | 分支 {fmt_pct(bp)}")
|
|
131
|
+
return cov_lines
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _build_error_lines(
|
|
135
|
+
env_info, tests, failures, errors, skipped, warnings, time_spent, cases
|
|
136
|
+
) -> list[str]:
|
|
137
|
+
err_lines: list[str] = []
|
|
138
|
+
err_lines.append("# WL 测试错误报告")
|
|
139
|
+
err_lines.append("")
|
|
140
|
+
err_lines.append("## 测试环境")
|
|
141
|
+
err_lines.extend([f"- {x}" for x in env_info])
|
|
142
|
+
err_lines.append("")
|
|
143
|
+
err_lines.append("## 测试统计")
|
|
144
|
+
err_lines.append(f"- 总用例: {tests}")
|
|
145
|
+
err_lines.append(f"- 失败: {failures}")
|
|
146
|
+
err_lines.append(f"- 错误: {errors}")
|
|
147
|
+
err_lines.append(f"- 跳过: {skipped}")
|
|
148
|
+
err_lines.append(f"- 警告: {warnings}")
|
|
149
|
+
err_lines.append(f"- 总时长: {time_spent:.2f}s")
|
|
150
|
+
err_lines.append("")
|
|
151
|
+
|
|
152
|
+
failure_cases = [c for c in cases if c.get("kind") == "failure"]
|
|
153
|
+
error_cases = [c for c in cases if c.get("kind") == "error"]
|
|
154
|
+
warning_cases = [c for c in cases if c.get("kind") == "warning"]
|
|
155
|
+
|
|
156
|
+
if failure_cases:
|
|
157
|
+
err_lines.append("## 失败明细")
|
|
158
|
+
_append_case_lines(err_lines, failure_cases)
|
|
159
|
+
|
|
160
|
+
if error_cases:
|
|
161
|
+
err_lines.append("## 错误明细")
|
|
162
|
+
_append_case_lines(err_lines, error_cases)
|
|
163
|
+
|
|
164
|
+
if warning_cases:
|
|
165
|
+
err_lines.append("## 警告明细")
|
|
166
|
+
_append_case_lines(err_lines, warning_cases)
|
|
167
|
+
|
|
168
|
+
return err_lines
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _append_case_lines(err_lines: list[str], cases: list) -> None:
|
|
172
|
+
for c in cases:
|
|
173
|
+
loc = c.get("file") or c.get("classname") or ""
|
|
174
|
+
err_lines.append(
|
|
175
|
+
f"- 用例: `{c.get('name', '')}` @ `{loc}` [{c.get('kind', '')}]"
|
|
176
|
+
)
|
|
177
|
+
err_lines.append("")
|
|
178
|
+
err_lines.append("```")
|
|
179
|
+
err_lines.append(c.get("text", ""))
|
|
180
|
+
err_lines.append("```")
|
|
181
|
+
err_lines.append("")
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test result handling utilities for test command.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestResultHandler:
|
|
9
|
+
"""Handle test results and exit codes."""
|
|
10
|
+
|
|
11
|
+
def handle_test_result(self, result, report_mode: bool) -> int:
|
|
12
|
+
"""
|
|
13
|
+
Handle the test result based on return code.
|
|
14
|
+
|
|
15
|
+
Reports the outcome to the user and returns the exit code to hand back
|
|
16
|
+
to the caller. Exiting is deliberately left to the caller so that
|
|
17
|
+
post-run work (report generation, per-file cache attribution) still
|
|
18
|
+
happens on a failing suite.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
result: The subprocess result object
|
|
22
|
+
report_mode: Whether we're in report mode
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
The exit code to exit with (pytest's return code, unchanged)
|
|
26
|
+
"""
|
|
27
|
+
if result.returncode == 0:
|
|
28
|
+
# Tests passed
|
|
29
|
+
if not report_mode:
|
|
30
|
+
print("All tests passed successfully!")
|
|
31
|
+
else:
|
|
32
|
+
# Tests failed
|
|
33
|
+
if not report_mode:
|
|
34
|
+
self._print_test_failure_info(result)
|
|
35
|
+
return int(result.returncode)
|
|
36
|
+
|
|
37
|
+
def _print_test_failure_info(self, result) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Print test failure information, filtering out progress bars.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
result: The subprocess result object
|
|
43
|
+
"""
|
|
44
|
+
# In concise mode, only show the short test summary info
|
|
45
|
+
# Skip the long progress bar to reduce token consumption
|
|
46
|
+
if hasattr(result, "stdout") and result.stdout:
|
|
47
|
+
output = self._filter_test_output(result.stdout, result)
|
|
48
|
+
# Only print if there's something left to print
|
|
49
|
+
if output.strip():
|
|
50
|
+
print(output)
|
|
51
|
+
if hasattr(result, "stderr") and result.stderr:
|
|
52
|
+
# stderr usually doesn't contain the summary
|
|
53
|
+
# Only output if it's not empty and not already in stdout
|
|
54
|
+
stderr = result.stderr.strip()
|
|
55
|
+
if stderr:
|
|
56
|
+
print(stderr, file=sys.stderr)
|
|
57
|
+
print(f"Tests failed with return code {result.returncode}")
|
|
58
|
+
|
|
59
|
+
def _filter_test_output(self, output: str, result) -> str:
|
|
60
|
+
"""
|
|
61
|
+
Filter test output to remove progress bars and keep only useful information.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
output: The test output to filter
|
|
65
|
+
result: The subprocess result object
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Filtered test output
|
|
69
|
+
"""
|
|
70
|
+
# Find the short test summary info section
|
|
71
|
+
marker = "short test summary info"
|
|
72
|
+
if marker in output:
|
|
73
|
+
# Extract everything from the marker onwards
|
|
74
|
+
return output[output.index(marker) :]
|
|
75
|
+
else:
|
|
76
|
+
# If no marker found, filter out progress bar lines manually
|
|
77
|
+
# Filter lines that look like:
|
|
78
|
+
# - progress percentage: "... [XX%]"
|
|
79
|
+
# - progress dots: "filename.py ........." with many dots
|
|
80
|
+
lines = output.splitlines()
|
|
81
|
+
filtered_lines = []
|
|
82
|
+
for line in lines:
|
|
83
|
+
# Skip collection progress lines with percentage
|
|
84
|
+
# Matches both "[ 100%]" and "[100%]"
|
|
85
|
+
if "[" in line and "%]" in line:
|
|
86
|
+
continue
|
|
87
|
+
# Skip lines like "filename.py ........." that contain many dots
|
|
88
|
+
# These are the per-file progress dots from pytest
|
|
89
|
+
if "." in line and line.count(".") > 7:
|
|
90
|
+
continue
|
|
91
|
+
filtered_lines.append(line)
|
|
92
|
+
filtered_output = "\n".join(filtered_lines)
|
|
93
|
+
# If after filtering output is empty and there's stderr, don't print anything here
|
|
94
|
+
if not filtered_output.strip() and hasattr(result, "stderr"):
|
|
95
|
+
return ""
|
|
96
|
+
return filtered_output
|