cov-loupe 3.0.0 → 4.0.0.pre
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.
- checksums.yaml +4 -4
- data/AGENTS.md +230 -0
- data/CLAUDE.md +5 -0
- data/CODE_OF_CONDUCT.md +62 -0
- data/CONTRIBUTING.md +102 -0
- data/GEMINI.md +5 -0
- data/README.md +154 -51
- data/RELEASE_NOTES.md +452 -0
- data/dev/images/cov-loupe-icon-lores.png +0 -0
- data/dev/images/cov-loupe-icon-square.png +0 -0
- data/dev/images/cov-loupe-icon.png +0 -0
- data/dev/images/cov-loupe-logo.png +0 -0
- data/dev/prompts/README.md +74 -0
- data/dev/prompts/archive/architectural-review-and-actions-prompt.md +53 -0
- data/dev/prompts/archive/investigate-and-report-issues-prompt.md +33 -0
- data/dev/prompts/archive/produce-action-items-prompt.md +25 -0
- data/dev/prompts/guidelines/ai-code-evaluator-guidelines.md +337 -0
- data/dev/prompts/improve/refactor-test-suite.md +18 -0
- data/dev/prompts/improve/simplify-code-logic.md +133 -0
- data/dev/prompts/improve/update-documentation.md +21 -0
- data/dev/prompts/review/comprehensive-codebase-review.md +176 -0
- data/dev/prompts/review/identify-action-items.md +143 -0
- data/dev/prompts/review/verify-code-changes.md +54 -0
- data/dev/prompts/validate/create-screencast-outline.md +234 -0
- data/dev/prompts/validate/test-documentation-examples.md +180 -0
- data/docs/QUICKSTART.md +63 -0
- data/docs/assets/images/cov-loupe-logo-lores.png +0 -0
- data/docs/assets/images/cov-loupe-logo.png +0 -0
- data/docs/assets/images/favicon.png +0 -0
- data/docs/assets/stylesheets/branding.css +16 -0
- data/docs/assets/stylesheets/extra.css +15 -0
- data/docs/code_of_conduct.md +1 -0
- data/docs/contributing.md +1 -0
- data/docs/dev/ARCHITECTURE.md +56 -11
- data/docs/dev/DEVELOPMENT.md +116 -12
- data/docs/dev/FUTURE_ENHANCEMENTS.md +14 -0
- data/docs/dev/README.md +3 -2
- data/docs/dev/RELEASING.md +2 -0
- data/docs/dev/arch-decisions/README.md +10 -7
- data/docs/dev/arch-decisions/application-architecture.md +259 -0
- data/docs/dev/arch-decisions/coverage-data-quality.md +193 -0
- data/docs/dev/arch-decisions/output-character-mode.md +217 -0
- data/docs/dev/arch-decisions/path-resolution.md +90 -0
- data/docs/dev/arch-decisions/{004-x-arch-decision.md → policy-validation.md} +32 -28
- data/docs/dev/arch-decisions/{005-x-arch-decision.md → simplecov-integration.md} +47 -44
- data/docs/dev/presentations/cov-loupe-presentation.md +15 -13
- data/docs/examples/mcp-inputs.md +3 -0
- data/docs/examples/prompts.md +3 -0
- data/docs/examples/success_predicates.md +3 -0
- data/docs/fixtures/demo_project/.resultset.json +170 -0
- data/docs/fixtures/demo_project/README.md +6 -0
- data/docs/fixtures/demo_project/app/controllers/admin/audit_logs_controller.rb +19 -0
- data/docs/fixtures/demo_project/app/controllers/orders_controller.rb +26 -0
- data/docs/fixtures/demo_project/app/models/order.rb +20 -0
- data/docs/fixtures/demo_project/app/models/user.rb +19 -0
- data/docs/fixtures/demo_project/lib/api/client.rb +22 -0
- data/docs/fixtures/demo_project/lib/ops/jobs/cleanup_job.rb +16 -0
- data/docs/fixtures/demo_project/lib/ops/jobs/report_job.rb +17 -0
- data/docs/fixtures/demo_project/lib/payments/processor.rb +15 -0
- data/docs/fixtures/demo_project/lib/payments/refund_service.rb +15 -0
- data/docs/fixtures/demo_project/lib/payments/reporting/exporter.rb +16 -0
- data/docs/index.md +1 -0
- data/docs/license.md +3 -0
- data/docs/release_notes.md +3 -0
- data/docs/user/ADVANCED_USAGE.md +208 -115
- data/docs/user/CLI_FALLBACK_FOR_LLMS.md +2 -0
- data/docs/user/CLI_USAGE.md +276 -101
- data/docs/user/ERROR_HANDLING.md +4 -4
- data/docs/user/EXAMPLES.md +121 -128
- data/docs/user/INSTALLATION.md +9 -28
- data/docs/user/LIBRARY_API.md +227 -122
- data/docs/user/MCP_INTEGRATION.md +114 -203
- data/docs/user/README.md +5 -1
- data/docs/user/TROUBLESHOOTING.md +49 -27
- data/docs/user/installing-a-prelease-version-of-covloupe.md +43 -0
- data/docs/user/{V2-BREAKING-CHANGES.md → migrations/MIGRATING_TO_V2.md} +62 -72
- data/docs/user/migrations/MIGRATING_TO_V3.md +72 -0
- data/docs/user/migrations/MIGRATING_TO_V4.md +591 -0
- data/docs/user/migrations/README.md +22 -0
- data/docs/user/prompts/README.md +9 -0
- data/docs/user/prompts/non-web-coverage-analysis-prompt.md +103 -0
- data/docs/user/prompts/rails-coverage-analysis-prompt.md +94 -0
- data/docs/user/prompts/use-cli-not-mcp-prompt.md +53 -0
- data/examples/cli_demo.sh +77 -0
- data/examples/filter_and_table_demo-output.md +114 -0
- data/examples/filter_and_table_demo.rb +174 -0
- data/examples/fixtures/demo_project/coverage/.resultset.json +10 -0
- data/examples/mcp-inputs/README.md +66 -0
- data/examples/mcp-inputs/coverage_detailed.json +1 -0
- data/examples/mcp-inputs/coverage_raw.json +1 -0
- data/examples/mcp-inputs/coverage_summary.json +1 -0
- data/examples/mcp-inputs/list.json +1 -0
- data/examples/mcp-inputs/uncovered_lines.json +1 -0
- data/examples/prompts/README.md +27 -0
- data/examples/prompts/custom_resultset.txt +2 -0
- data/examples/prompts/detailed_with_source.txt +2 -0
- data/examples/prompts/list_lowest.txt +2 -0
- data/examples/prompts/summary.txt +2 -0
- data/examples/prompts/uncovered.txt +2 -0
- data/examples/success_predicates/README.md +198 -0
- data/examples/success_predicates/all_files_above_threshold_predicate.rb +21 -0
- data/examples/success_predicates/directory_specific_thresholds_predicate.rb +30 -0
- data/examples/success_predicates/project_coverage_minimum_predicate.rb +6 -0
- data/lib/cov_loupe/base_tool.rb +229 -20
- data/lib/cov_loupe/cli.rb +132 -23
- data/lib/cov_loupe/commands/base_command.rb +25 -6
- data/lib/cov_loupe/commands/command_factory.rb +0 -1
- data/lib/cov_loupe/commands/detailed_command.rb +10 -5
- data/lib/cov_loupe/commands/list_command.rb +2 -1
- data/lib/cov_loupe/commands/raw_command.rb +7 -5
- data/lib/cov_loupe/commands/summary_command.rb +12 -7
- data/lib/cov_loupe/commands/totals_command.rb +74 -10
- data/lib/cov_loupe/commands/uncovered_command.rb +7 -5
- data/lib/cov_loupe/commands/validate_command.rb +11 -3
- data/lib/cov_loupe/commands/version_command.rb +6 -4
- data/lib/cov_loupe/{app_config.rb → config/app_config.rb} +13 -5
- data/lib/cov_loupe/config/app_context.rb +43 -0
- data/lib/cov_loupe/config/boolean_type.rb +91 -0
- data/lib/cov_loupe/config/logger.rb +92 -0
- data/lib/cov_loupe/{option_normalizers.rb → config/option_normalizers.rb} +55 -24
- data/lib/cov_loupe/{option_parser_builder.rb → config/option_parser_builder.rb} +46 -24
- data/lib/cov_loupe/coverage/coverage_calculator.rb +53 -0
- data/lib/cov_loupe/coverage/coverage_reporter.rb +63 -0
- data/lib/cov_loupe/coverage/coverage_table_formatter.rb +133 -0
- data/lib/cov_loupe/{error_handler.rb → errors/error_handler.rb} +21 -33
- data/lib/cov_loupe/{errors.rb → errors/errors.rb} +48 -71
- data/lib/cov_loupe/formatters/formatters.rb +75 -0
- data/lib/cov_loupe/formatters/source_formatter.rb +18 -7
- data/lib/cov_loupe/formatters/table_formatter.rb +80 -0
- data/lib/cov_loupe/loaders/all.rb +15 -0
- data/lib/cov_loupe/loaders/all_cli.rb +10 -0
- data/lib/cov_loupe/loaders/all_mcp.rb +23 -0
- data/lib/cov_loupe/loaders/resultset_loader.rb +147 -0
- data/lib/cov_loupe/mcp_server.rb +3 -2
- data/lib/cov_loupe/model/model.rb +520 -0
- data/lib/cov_loupe/model/model_data.rb +13 -0
- data/lib/cov_loupe/model/model_data_cache.rb +116 -0
- data/lib/cov_loupe/option_parsers/env_options_parser.rb +17 -6
- data/lib/cov_loupe/option_parsers/error_helper.rb +16 -10
- data/lib/cov_loupe/output_chars.rb +192 -0
- data/lib/cov_loupe/paths/glob_utils.rb +100 -0
- data/lib/cov_loupe/{path_relativizer.rb → paths/path_relativizer.rb} +5 -13
- data/lib/cov_loupe/paths/path_utils.rb +265 -0
- data/lib/cov_loupe/paths/volume_case_sensitivity.rb +173 -0
- data/lib/cov_loupe/presenters/base_coverage_presenter.rb +9 -13
- data/lib/cov_loupe/presenters/coverage_payload_presenter.rb +21 -0
- data/lib/cov_loupe/presenters/payload_caching.rb +23 -0
- data/lib/cov_loupe/presenters/project_coverage_presenter.rb +73 -21
- data/lib/cov_loupe/presenters/project_totals_presenter.rb +16 -10
- data/lib/cov_loupe/repositories/coverage_repository.rb +149 -0
- data/lib/cov_loupe/resolvers/coverage_line_resolver.rb +90 -76
- data/lib/cov_loupe/resolvers/{resolver_factory.rb → resolver_helpers.rb} +6 -5
- data/lib/cov_loupe/resolvers/resultset_path_resolver.rb +40 -12
- data/lib/cov_loupe/scripts/command_execution.rb +113 -0
- data/lib/cov_loupe/scripts/latest_ci_status.rb +97 -0
- data/lib/cov_loupe/scripts/pre_release_check.rb +164 -0
- data/lib/cov_loupe/scripts/setup_doc_server.rb +23 -0
- data/lib/cov_loupe/scripts/start_doc_server.rb +24 -0
- data/lib/cov_loupe/staleness/stale_status.rb +23 -0
- data/lib/cov_loupe/staleness/staleness_checker.rb +328 -0
- data/lib/cov_loupe/staleness/staleness_message_formatter.rb +91 -0
- data/lib/cov_loupe/tools/coverage_detailed_tool.rb +14 -15
- data/lib/cov_loupe/tools/coverage_raw_tool.rb +14 -14
- data/lib/cov_loupe/tools/coverage_summary_tool.rb +16 -16
- data/lib/cov_loupe/tools/coverage_table_tool.rb +139 -21
- data/lib/cov_loupe/tools/coverage_totals_tool.rb +31 -13
- data/lib/cov_loupe/tools/help_tool.rb +16 -20
- data/lib/cov_loupe/tools/list_tool.rb +65 -0
- data/lib/cov_loupe/tools/uncovered_lines_tool.rb +14 -14
- data/lib/cov_loupe/tools/validate_tool.rb +18 -24
- data/lib/cov_loupe/tools/version_tool.rb +8 -3
- data/lib/cov_loupe/version.rb +1 -1
- data/lib/cov_loupe.rb +83 -55
- metadata +184 -154
- data/docs/dev/BRANCH_ONLY_COVERAGE.md +0 -158
- data/docs/dev/arch-decisions/001-x-arch-decision.md +0 -95
- data/docs/dev/arch-decisions/002-x-arch-decision.md +0 -159
- data/docs/dev/arch-decisions/003-x-arch-decision.md +0 -165
- data/lib/cov_loupe/app_context.rb +0 -26
- data/lib/cov_loupe/constants.rb +0 -22
- data/lib/cov_loupe/coverage_reporter.rb +0 -31
- data/lib/cov_loupe/formatters.rb +0 -51
- data/lib/cov_loupe/mode_detector.rb +0 -56
- data/lib/cov_loupe/model.rb +0 -339
- data/lib/cov_loupe/presenters/coverage_detailed_presenter.rb +0 -14
- data/lib/cov_loupe/presenters/coverage_raw_presenter.rb +0 -14
- data/lib/cov_loupe/presenters/coverage_summary_presenter.rb +0 -14
- data/lib/cov_loupe/presenters/coverage_uncovered_presenter.rb +0 -14
- data/lib/cov_loupe/resultset_loader.rb +0 -131
- data/lib/cov_loupe/staleness_checker.rb +0 -247
- data/lib/cov_loupe/table_formatter.rb +0 -64
- data/lib/cov_loupe/tools/all_files_coverage_tool.rb +0 -51
- data/lib/cov_loupe/util.rb +0 -88
- data/spec/MCP_INTEGRATION_TESTS_README.md +0 -111
- data/spec/TIMESTAMPS.md +0 -48
- data/spec/all_files_coverage_tool_spec.rb +0 -53
- data/spec/app_config_spec.rb +0 -142
- data/spec/base_tool_spec.rb +0 -62
- data/spec/cli/show_default_report_spec.rb +0 -33
- data/spec/cli_enumerated_options_spec.rb +0 -90
- data/spec/cli_error_spec.rb +0 -184
- data/spec/cli_format_spec.rb +0 -123
- data/spec/cli_json_options_spec.rb +0 -50
- data/spec/cli_source_spec.rb +0 -44
- data/spec/cli_spec.rb +0 -192
- data/spec/cli_table_spec.rb +0 -28
- data/spec/cli_usage_spec.rb +0 -42
- data/spec/commands/base_command_spec.rb +0 -107
- data/spec/commands/command_factory_spec.rb +0 -76
- data/spec/commands/detailed_command_spec.rb +0 -34
- data/spec/commands/list_command_spec.rb +0 -28
- data/spec/commands/raw_command_spec.rb +0 -69
- data/spec/commands/summary_command_spec.rb +0 -34
- data/spec/commands/totals_command_spec.rb +0 -34
- data/spec/commands/uncovered_command_spec.rb +0 -55
- data/spec/commands/validate_command_spec.rb +0 -213
- data/spec/commands/version_command_spec.rb +0 -38
- data/spec/constants_spec.rb +0 -61
- data/spec/cov_loupe/formatters/source_formatter_spec.rb +0 -267
- data/spec/cov_loupe/formatters_spec.rb +0 -76
- data/spec/cov_loupe/presenters/base_coverage_presenter_spec.rb +0 -79
- data/spec/cov_loupe_model_spec.rb +0 -454
- data/spec/cov_loupe_module_spec.rb +0 -37
- data/spec/cov_loupe_opts_spec.rb +0 -185
- data/spec/coverage_reporter_spec.rb +0 -102
- data/spec/coverage_table_tool_spec.rb +0 -59
- data/spec/coverage_totals_tool_spec.rb +0 -37
- data/spec/error_handler_spec.rb +0 -197
- data/spec/error_mode_spec.rb +0 -139
- data/spec/errors_edge_cases_spec.rb +0 -312
- data/spec/errors_stale_spec.rb +0 -83
- data/spec/file_based_mcp_tools_spec.rb +0 -99
- data/spec/help_tool_spec.rb +0 -26
- data/spec/integration_spec.rb +0 -789
- data/spec/logging_fallback_spec.rb +0 -128
- data/spec/mcp_logging_spec.rb +0 -44
- data/spec/mcp_server_integration_spec.rb +0 -23
- data/spec/mcp_server_spec.rb +0 -106
- data/spec/mode_detector_spec.rb +0 -153
- data/spec/model_error_handling_spec.rb +0 -269
- data/spec/model_staleness_spec.rb +0 -79
- data/spec/option_normalizers_spec.rb +0 -203
- data/spec/option_parsers/env_options_parser_spec.rb +0 -221
- data/spec/option_parsers/error_helper_spec.rb +0 -222
- data/spec/path_relativizer_spec.rb +0 -98
- data/spec/presenters/coverage_detailed_presenter_spec.rb +0 -19
- data/spec/presenters/coverage_raw_presenter_spec.rb +0 -15
- data/spec/presenters/coverage_summary_presenter_spec.rb +0 -15
- data/spec/presenters/coverage_uncovered_presenter_spec.rb +0 -16
- data/spec/presenters/project_coverage_presenter_spec.rb +0 -87
- data/spec/presenters/project_totals_presenter_spec.rb +0 -144
- data/spec/resolvers/coverage_line_resolver_spec.rb +0 -282
- data/spec/resolvers/resolver_factory_spec.rb +0 -61
- data/spec/resolvers/resultset_path_resolver_spec.rb +0 -60
- data/spec/resultset_loader_spec.rb +0 -167
- data/spec/shared_examples/README.md +0 -115
- data/spec/shared_examples/coverage_presenter_examples.rb +0 -66
- data/spec/shared_examples/file_based_mcp_tools.rb +0 -179
- data/spec/shared_examples/formatted_command_examples.rb +0 -64
- data/spec/shared_examples/mcp_tool_text_json_response.rb +0 -16
- data/spec/spec_helper.rb +0 -127
- data/spec/staleness_checker_spec.rb +0 -374
- data/spec/staleness_more_spec.rb +0 -42
- data/spec/support/cli_helpers.rb +0 -22
- data/spec/support/control_flow_helpers.rb +0 -20
- data/spec/support/fake_mcp.rb +0 -40
- data/spec/support/io_helpers.rb +0 -29
- data/spec/support/mcp_helpers.rb +0 -35
- data/spec/support/mcp_runner.rb +0 -66
- data/spec/support/mocking_helpers.rb +0 -30
- data/spec/table_format_spec.rb +0 -70
- data/spec/tools/validate_tool_spec.rb +0 -132
- data/spec/tools_error_handling_spec.rb +0 -130
- data/spec/util_spec.rb +0 -154
- data/spec/version_spec.rb +0 -123
- data/spec/version_tool_spec.rb +0 -141
- /data/{spec/fixtures/project1 → examples/fixtures/demo_project}/lib/bar.rb +0 -0
- /data/{spec/fixtures/project1 → examples/fixtures/demo_project}/lib/foo.rb +0 -0
- /data/lib/cov_loupe/{config_parser.rb → config/config_parser.rb} +0 -0
- /data/lib/cov_loupe/{predicate_evaluator.rb → config/predicate_evaluator.rb} +0 -0
- /data/lib/cov_loupe/{error_handler_factory.rb → errors/error_handler_factory.rb} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../base_tool'
|
|
4
|
-
require_relative '../model'
|
|
5
|
-
require_relative '../presenters/
|
|
4
|
+
require_relative '../model/model'
|
|
5
|
+
require_relative '../presenters/coverage_payload_presenter'
|
|
6
6
|
|
|
7
7
|
module CovLoupe
|
|
8
8
|
module Tools
|
|
@@ -10,24 +10,23 @@ module CovLoupe
|
|
|
10
10
|
description <<~DESC
|
|
11
11
|
Use this when the user needs per-line coverage data for a single file.
|
|
12
12
|
Do not use this for high-level counts; coverage.summary is cheaper for aggregate numbers.
|
|
13
|
-
Inputs: file path (required) plus optional root/resultset/
|
|
13
|
+
Inputs: file path (required) plus optional root/resultset/raise_on_stale flag inherited from BaseTool.
|
|
14
14
|
Output: JSON object with "file", "lines" => [{"line": 12, "hits": 0, "covered": false}], plus "summary" with totals and "stale" status.
|
|
15
15
|
Example: "Show detailed coverage for lib/cov_loupe/model.rb".
|
|
16
16
|
DESC
|
|
17
17
|
input_schema(**input_schema_def)
|
|
18
18
|
class << self
|
|
19
|
-
def call(path:, root:
|
|
20
|
-
server_context:)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
19
|
+
def call(path:, root: nil, resultset: nil, raise_on_stale: nil, error_mode: 'log',
|
|
20
|
+
output_chars: nil, server_context:)
|
|
21
|
+
call_with_file_payload(
|
|
22
|
+
path: path,
|
|
23
|
+
error_mode: error_mode,
|
|
24
|
+
output_chars: output_chars,
|
|
25
|
+
server_context: server_context,
|
|
26
|
+
root: root,
|
|
27
|
+
resultset: resultset,
|
|
28
|
+
raise_on_stale: raise_on_stale
|
|
29
|
+
)
|
|
31
30
|
end
|
|
32
31
|
end
|
|
33
32
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../base_tool'
|
|
4
|
-
require_relative '../model'
|
|
5
|
-
require_relative '../presenters/
|
|
4
|
+
require_relative '../model/model'
|
|
5
|
+
require_relative '../presenters/coverage_payload_presenter'
|
|
6
6
|
|
|
7
7
|
module CovLoupe
|
|
8
8
|
module Tools
|
|
@@ -10,23 +10,23 @@ module CovLoupe
|
|
|
10
10
|
description <<~DESC
|
|
11
11
|
Use this when you need the raw SimpleCov `lines` array for a file exactly as stored on disk.
|
|
12
12
|
Do not use this for human-friendly explanations; choose coverage.detailed or coverage.summary instead.
|
|
13
|
-
Inputs: file path (required) plus optional root/resultset/
|
|
13
|
+
Inputs: file path (required) plus optional root/resultset/raise_on_stale flag inherited from BaseTool.
|
|
14
14
|
Output: JSON object with "file" and "lines" (array of integers/nulls) mirroring SimpleCov's native structure, plus "stale" status.
|
|
15
15
|
Example: "Fetch the raw coverage array for spec/support/foo_helper.rb".
|
|
16
16
|
DESC
|
|
17
17
|
input_schema(**input_schema_def)
|
|
18
18
|
class << self
|
|
19
|
-
def call(path:, root:
|
|
20
|
-
server_context:)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
def call(path:, root: nil, resultset: nil, raise_on_stale: nil, error_mode: 'log',
|
|
20
|
+
output_chars: nil, server_context:)
|
|
21
|
+
call_with_file_payload(
|
|
22
|
+
path: path,
|
|
23
|
+
error_mode: error_mode,
|
|
24
|
+
output_chars: output_chars,
|
|
25
|
+
server_context: server_context,
|
|
26
|
+
root: root,
|
|
27
|
+
resultset: resultset,
|
|
28
|
+
raise_on_stale: raise_on_stale
|
|
29
|
+
)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../base_tool'
|
|
4
|
-
require_relative '../model'
|
|
5
|
-
require_relative '../presenters/
|
|
4
|
+
require_relative '../model/model'
|
|
5
|
+
require_relative '../presenters/coverage_payload_presenter'
|
|
6
6
|
|
|
7
7
|
module CovLoupe
|
|
8
8
|
module Tools
|
|
9
9
|
class CoverageSummaryTool < BaseTool
|
|
10
10
|
description <<~DESC
|
|
11
11
|
Use this when the user asks for the covered/total line counts and percentage for a specific file.
|
|
12
|
-
Do not use this for multi-file reports; coverage.
|
|
13
|
-
Inputs: file path (required) plus optional root/resultset/
|
|
12
|
+
Do not use this for multi-file reports; coverage.list or coverage.table handle those.
|
|
13
|
+
Inputs: file path (required) plus optional root/resultset/raise_on_stale flag inherited from BaseTool.
|
|
14
14
|
Output: JSON object {"file": String, "summary": {"covered": Integer, "total": Integer, "percentage": Float}, "stale": String|False}.
|
|
15
|
-
Examples: "What is the coverage for lib/cov_loupe/tools/
|
|
15
|
+
Examples: "What is the coverage for lib/cov_loupe/tools/list_tool.rb?".
|
|
16
16
|
DESC
|
|
17
17
|
input_schema(**input_schema_def)
|
|
18
18
|
class << self
|
|
19
|
-
def call(path:, root:
|
|
20
|
-
server_context:)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
def call(path:, root: nil, resultset: nil, raise_on_stale: nil, error_mode: 'log',
|
|
20
|
+
output_chars: nil, server_context:)
|
|
21
|
+
call_with_file_payload(
|
|
22
|
+
path: path,
|
|
23
|
+
error_mode: error_mode,
|
|
24
|
+
output_chars: output_chars,
|
|
25
|
+
server_context: server_context,
|
|
26
|
+
root: root,
|
|
27
|
+
resultset: resultset,
|
|
28
|
+
raise_on_stale: raise_on_stale
|
|
29
|
+
)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -3,47 +3,165 @@
|
|
|
3
3
|
|
|
4
4
|
require_relative '../base_tool'
|
|
5
5
|
require_relative '../presenters/project_coverage_presenter'
|
|
6
|
+
require_relative '../config/option_normalizers'
|
|
7
|
+
require_relative '../output_chars'
|
|
6
8
|
|
|
7
9
|
module CovLoupe
|
|
8
10
|
module Tools
|
|
9
11
|
class CoverageTableTool < BaseTool
|
|
10
12
|
description <<~DESC
|
|
11
|
-
Use this when a user wants the plain text coverage table exactly like `cov-loupe --table` would print (no ANSI colors).
|
|
12
|
-
Do not use this for machine-readable data; coverage.
|
|
13
|
-
Inputs: optional project root/resultset path/sort order/
|
|
14
|
-
Output: text block containing the formatted coverage table with headers and percentages
|
|
13
|
+
Use this when a user wants the plain text coverage table exactly like `cov-loupe --format table` would print (no ANSI colors).
|
|
14
|
+
Do not use this for machine-readable data; coverage.list returns structured JSON.
|
|
15
|
+
Inputs: optional project root/resultset path/sort order/raise_on_stale flag matching the CLI flags.
|
|
16
|
+
Output: text block containing the formatted coverage table with headers and percentages, plus
|
|
17
|
+
any exclusions summary (missing/stale/deleted files) and skipped row warnings, exactly as the CLI displays.
|
|
15
18
|
Example: "Show me the CLI coverage table sorted descending".
|
|
16
19
|
DESC
|
|
17
20
|
input_schema(**coverage_schema(
|
|
18
21
|
additional_properties: {
|
|
19
|
-
sort_order:
|
|
20
|
-
type: 'string',
|
|
21
|
-
description: 'Sort order for the printed coverage table (ascending or descending).',
|
|
22
|
-
default: 'ascending',
|
|
23
|
-
enum: ['ascending', 'descending']
|
|
24
|
-
},
|
|
22
|
+
sort_order: SORT_ORDER_PROPERTY,
|
|
25
23
|
tracked_globs: TRACKED_GLOBS_PROPERTY
|
|
26
24
|
}
|
|
27
25
|
))
|
|
28
26
|
class << self
|
|
29
|
-
def call(root:
|
|
30
|
-
tracked_globs: nil, error_mode: 'log', server_context:)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
def call(root: nil, resultset: nil, sort_order: nil, raise_on_stale: nil,
|
|
28
|
+
tracked_globs: nil, error_mode: 'log', output_chars: nil, server_context:)
|
|
29
|
+
output_chars_sym = resolve_output_chars(output_chars, server_context)
|
|
30
|
+
with_error_handling('CoverageTableTool', error_mode: error_mode, output_chars: output_chars_sym) do
|
|
31
|
+
model, config = create_configured_model(
|
|
32
|
+
server_context: server_context,
|
|
33
|
+
root: root,
|
|
34
|
+
resultset: resultset,
|
|
35
|
+
raise_on_stale: raise_on_stale,
|
|
36
|
+
tracked_globs: tracked_globs
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Normalize and validate sort_order (supports 'a'/'d' abbreviations)
|
|
40
|
+
sort_order_sym = OptionNormalizers.normalize_sort_order(
|
|
41
|
+
sort_order || BaseTool::DEFAULT_SORT_ORDER, strict: true
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Create presenter to access file summaries and exclusion data
|
|
45
|
+
presenter = Presenters::ProjectCoveragePresenter.new(
|
|
46
|
+
model: model,
|
|
47
|
+
sort_order: sort_order_sym,
|
|
48
|
+
raise_on_stale: config[:raise_on_stale],
|
|
49
|
+
tracked_globs: config[:tracked_globs]
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Format the table with file summaries
|
|
53
|
+
file_summaries = presenter.relative_files
|
|
38
54
|
table = model.format_table(
|
|
55
|
+
file_summaries,
|
|
39
56
|
sort_order: sort_order_sym,
|
|
40
|
-
|
|
41
|
-
tracked_globs:
|
|
57
|
+
raise_on_stale: config[:raise_on_stale],
|
|
58
|
+
tracked_globs: nil,
|
|
59
|
+
output_chars: output_chars_sym
|
|
42
60
|
)
|
|
61
|
+
|
|
62
|
+
# Append exclusions summary (matching CLI behavior)
|
|
63
|
+
exclusions = format_exclusions_summary(presenter, output_chars_sym)
|
|
64
|
+
table += exclusions unless exclusions.empty?
|
|
65
|
+
|
|
66
|
+
# Append timestamp warning (matching CLI behavior)
|
|
67
|
+
timestamp_warning = format_timestamp_warning(presenter)
|
|
68
|
+
table += timestamp_warning unless timestamp_warning.empty?
|
|
69
|
+
|
|
70
|
+
# Append skipped rows warning (matching CLI behavior)
|
|
71
|
+
skipped_warning = format_skipped_rows_warning(presenter, output_chars_sym)
|
|
72
|
+
table += skipped_warning unless skipped_warning.empty?
|
|
73
|
+
|
|
43
74
|
# Return text response
|
|
44
75
|
::MCP::Tool::Response.new([{ 'type' => 'text', 'text' => table }])
|
|
45
76
|
end
|
|
46
77
|
end
|
|
78
|
+
|
|
79
|
+
private def format_exclusions_summary(presenter, output_chars)
|
|
80
|
+
missing = presenter.relative_missing_tracked_files
|
|
81
|
+
newer = presenter.relative_newer_files
|
|
82
|
+
deleted = presenter.relative_deleted_files
|
|
83
|
+
length_mismatch = presenter.relative_length_mismatch_files
|
|
84
|
+
unreadable = presenter.relative_unreadable_files
|
|
85
|
+
skipped = presenter.relative_skipped_files
|
|
86
|
+
|
|
87
|
+
# Only format if there are any exclusions
|
|
88
|
+
return '' if missing.empty? && newer.empty? && deleted.empty? &&
|
|
89
|
+
length_mismatch.empty? && unreadable.empty? && skipped.empty?
|
|
90
|
+
|
|
91
|
+
# Helper to convert paths to ASCII if needed
|
|
92
|
+
convert_path = ->(path) { OutputChars.convert(path, output_chars) }
|
|
93
|
+
|
|
94
|
+
output = ["\nFiles excluded from coverage:"]
|
|
95
|
+
|
|
96
|
+
unless missing.empty?
|
|
97
|
+
output << "\nMissing tracked files (#{missing.length}):"
|
|
98
|
+
missing.each { |file| output << " - #{convert_path.call(file)}" }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
unless newer.empty?
|
|
102
|
+
output << "\nFiles newer than coverage (#{newer.length}):"
|
|
103
|
+
newer.each { |file| output << " - #{convert_path.call(file)}" }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
unless deleted.empty?
|
|
107
|
+
output << "\nDeleted files with coverage (#{deleted.length}):"
|
|
108
|
+
deleted.each { |file| output << " - #{convert_path.call(file)}" }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
unless length_mismatch.empty?
|
|
112
|
+
output << "\nLine count mismatches (#{length_mismatch.length}):"
|
|
113
|
+
length_mismatch.each { |file| output << " - #{convert_path.call(file)}" }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
unless unreadable.empty?
|
|
117
|
+
output << "\nUnreadable files (#{unreadable.length}):"
|
|
118
|
+
unreadable.each { |file| output << " - #{convert_path.call(file)}" }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
unless skipped.empty?
|
|
122
|
+
output << "\nFiles skipped due to errors (#{skipped.length}):"
|
|
123
|
+
skipped.each do |row|
|
|
124
|
+
file_path = OutputChars.convert(row['file'], output_chars)
|
|
125
|
+
error_msg = OutputChars.convert(row['error'], output_chars)
|
|
126
|
+
output << " - #{file_path}: #{error_msg}"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
output << "\nRun with --raise-on-stale to exit when files are excluded."
|
|
131
|
+
output.join("\n")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Formats the timestamp warning matching CLI warn_missing_timestamps behavior
|
|
135
|
+
private def format_timestamp_warning(presenter)
|
|
136
|
+
return '' unless presenter.timestamp_status == 'missing'
|
|
137
|
+
|
|
138
|
+
<<~WARNING
|
|
139
|
+
|
|
140
|
+
WARNING: Coverage timestamps are missing. Time-based staleness checks were skipped.
|
|
141
|
+
Files may appear "ok" even if source code is newer than the coverage data.
|
|
142
|
+
Check your coverage tool configuration to ensure timestamps are recorded.
|
|
143
|
+
WARNING
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Formats the skipped rows warning matching CLI warn_skipped_rows behavior
|
|
147
|
+
private def format_skipped_rows_warning(presenter, output_chars)
|
|
148
|
+
skipped = presenter.relative_skipped_files
|
|
149
|
+
return '' if skipped.nil? || skipped.empty?
|
|
150
|
+
|
|
151
|
+
count = skipped.length
|
|
152
|
+
output = [
|
|
153
|
+
'',
|
|
154
|
+
"WARNING: #{count} coverage row#{count == 1 ? '' : 's'} skipped due to errors:"
|
|
155
|
+
]
|
|
156
|
+
skipped.each do |row|
|
|
157
|
+
# Paths are already relativized by presenter
|
|
158
|
+
file_path = OutputChars.convert(row['file'], output_chars)
|
|
159
|
+
error_msg = OutputChars.convert(row['error'], output_chars)
|
|
160
|
+
output << " - #{file_path}: #{error_msg}"
|
|
161
|
+
end
|
|
162
|
+
output << 'Run again with --raise-on-stale to exit when rows are skipped.'
|
|
163
|
+
output.join("\n")
|
|
164
|
+
end
|
|
47
165
|
end
|
|
48
166
|
end
|
|
49
167
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../model'
|
|
3
|
+
require_relative '../model/model'
|
|
4
4
|
require_relative '../base_tool'
|
|
5
5
|
require_relative '../presenters/project_totals_presenter'
|
|
6
6
|
|
|
@@ -10,8 +10,10 @@ module CovLoupe
|
|
|
10
10
|
description <<~DESC
|
|
11
11
|
Use this when you want aggregated coverage counts for the entire project.
|
|
12
12
|
It reports covered/total lines, uncovered line counts, and the overall average percentage.
|
|
13
|
-
Inputs: optional project root, alternate .resultset path,
|
|
14
|
-
Output: JSON {"lines":{"total","covered","uncovered"},"
|
|
13
|
+
Inputs: optional project root, alternate .resultset path, raise_on_stale flag, tracked_globs, and error mode.
|
|
14
|
+
Output: JSON {"lines":{"total","covered","uncovered","percent_covered"},"tracking":{"enabled","globs"},"files":{"total","with_coverage","without_coverage"},"timestamp_status":"ok"|"missing","warnings":[string,...]}.
|
|
15
|
+
When raise_on_stale is enabled, the tool will raise an error immediately if any files have coverage data errors or staleness issues.
|
|
16
|
+
"timestamp_status" indicates whether coverage timestamps are available for time-based staleness checks. "warnings" array is present when timestamp_status is "missing".
|
|
15
17
|
Example: "Give me total/covered/uncovered line counts and the overall coverage percent."
|
|
16
18
|
DESC
|
|
17
19
|
|
|
@@ -22,20 +24,36 @@ module CovLoupe
|
|
|
22
24
|
))
|
|
23
25
|
|
|
24
26
|
class << self
|
|
25
|
-
def call(root:
|
|
26
|
-
error_mode: 'log', server_context:)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
def call(root: nil, resultset: nil, raise_on_stale: nil, tracked_globs: nil,
|
|
28
|
+
error_mode: 'log', output_chars: nil, server_context:)
|
|
29
|
+
output_chars_sym = resolve_output_chars(output_chars, server_context)
|
|
30
|
+
with_error_handling('CoverageTotalsTool', error_mode: error_mode, output_chars: output_chars_sym) do
|
|
31
|
+
model, config = create_configured_model(
|
|
32
|
+
server_context: server_context,
|
|
33
|
+
root: root,
|
|
34
|
+
resultset: resultset,
|
|
35
|
+
raise_on_stale: raise_on_stale,
|
|
36
|
+
tracked_globs: tracked_globs
|
|
37
|
+
)
|
|
30
38
|
|
|
31
|
-
model = CoverageModel.new(root: root, resultset: resultset, staleness: staleness_sym,
|
|
32
|
-
tracked_globs: tracked_globs)
|
|
33
39
|
presenter = Presenters::ProjectTotalsPresenter.new(
|
|
34
40
|
model: model,
|
|
35
|
-
|
|
36
|
-
tracked_globs: tracked_globs
|
|
41
|
+
raise_on_stale: config[:raise_on_stale],
|
|
42
|
+
tracked_globs: config[:tracked_globs]
|
|
37
43
|
)
|
|
38
|
-
|
|
44
|
+
payload = presenter.relativized_payload
|
|
45
|
+
|
|
46
|
+
# Add warnings array if timestamp_status is missing
|
|
47
|
+
if payload['timestamp_status'] == 'missing'
|
|
48
|
+
payload['warnings'] = [
|
|
49
|
+
'Coverage timestamps are missing. Time-based staleness checks were skipped.',
|
|
50
|
+
'Files may appear "ok" even if source code is newer than the coverage data.',
|
|
51
|
+
'Check your coverage tool configuration to ensure timestamps are recorded.'
|
|
52
|
+
]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
respond_json(payload, name: 'coverage_totals.json', pretty: true,
|
|
56
|
+
output_chars: output_chars_sym)
|
|
39
57
|
end
|
|
40
58
|
end
|
|
41
59
|
end
|
|
@@ -13,7 +13,8 @@ module CovLoupe
|
|
|
13
13
|
type: 'object',
|
|
14
14
|
additionalProperties: false,
|
|
15
15
|
properties: {
|
|
16
|
-
error_mode: ERROR_MODE_PROPERTY
|
|
16
|
+
error_mode: ERROR_MODE_PROPERTY,
|
|
17
|
+
output_chars: COMMON_PROPERTIES[:output_chars]
|
|
17
18
|
}
|
|
18
19
|
)
|
|
19
20
|
|
|
@@ -23,63 +24,56 @@ module CovLoupe
|
|
|
23
24
|
label: 'Single-file coverage summary',
|
|
24
25
|
use_when: 'User wants covered/total line counts or percentage for one file.',
|
|
25
26
|
avoid_when: 'User needs repo-wide stats or specific uncovered lines.',
|
|
26
|
-
inputs: ['path (required)', 'root/resultset/
|
|
27
|
+
inputs: ['path (required)', 'root/resultset/raise_on_stale (optional)']
|
|
27
28
|
},
|
|
28
29
|
{
|
|
29
30
|
tool: UncoveredLinesTool,
|
|
30
31
|
label: 'Uncovered line numbers',
|
|
31
32
|
use_when: 'User asks which lines in a file still lack tests.',
|
|
32
33
|
avoid_when: 'User only wants overall percentages or detailed per-line hit data.',
|
|
33
|
-
inputs: ['path (required)', 'root/resultset/
|
|
34
|
+
inputs: ['path (required)', 'root/resultset/raise_on_stale (optional)']
|
|
34
35
|
},
|
|
35
36
|
{
|
|
36
37
|
tool: CoverageDetailedTool,
|
|
37
38
|
label: 'Per-line coverage details',
|
|
38
39
|
use_when: 'User needs per-line hit counts for a file.',
|
|
39
40
|
avoid_when: 'User only wants totals or uncovered line numbers.',
|
|
40
|
-
inputs: ['path (required)', 'root/resultset/
|
|
41
|
+
inputs: ['path (required)', 'root/resultset/raise_on_stale (optional)']
|
|
41
42
|
},
|
|
42
43
|
{
|
|
43
44
|
tool: CoverageRawTool,
|
|
44
45
|
label: 'Raw SimpleCov lines array',
|
|
45
46
|
use_when: 'User needs the raw SimpleCov `lines` array for a file.',
|
|
46
47
|
avoid_when: 'User expects human-friendly summaries or explanations.',
|
|
47
|
-
inputs: ['path (required)', 'root/resultset/
|
|
48
|
+
inputs: ['path (required)', 'root/resultset/raise_on_stale (optional)']
|
|
48
49
|
},
|
|
49
50
|
{
|
|
50
|
-
tool:
|
|
51
|
+
tool: ListTool,
|
|
51
52
|
label: 'Repo-wide file coverage',
|
|
52
53
|
use_when: 'User wants coverage percentages for every tracked file.',
|
|
53
54
|
avoid_when: 'User asks about a single file.',
|
|
54
|
-
inputs: ['root/resultset (optional)', 'sort_order', '
|
|
55
|
+
inputs: ['root/resultset (optional)', 'sort_order', 'raise_on_stale', 'tracked_globs']
|
|
55
56
|
},
|
|
56
57
|
{
|
|
57
58
|
tool: CoverageTotalsTool,
|
|
58
59
|
label: 'Project coverage totals',
|
|
59
60
|
use_when: 'User wants total/covered/uncovered line counts or the average percent.',
|
|
60
61
|
avoid_when: 'User needs per-file breakdowns.',
|
|
61
|
-
inputs: ['root/resultset (optional)', '
|
|
62
|
+
inputs: ['root/resultset (optional)', 'raise_on_stale', 'tracked_globs']
|
|
62
63
|
},
|
|
63
64
|
{
|
|
64
65
|
tool: CoverageTableTool,
|
|
65
66
|
label: 'Formatted coverage table',
|
|
66
67
|
use_when: 'User wants the plain-text table produced by the CLI.',
|
|
67
68
|
avoid_when: 'User needs JSON data for automation.',
|
|
68
|
-
inputs: ['root/resultset (optional)', 'sort_order', '
|
|
69
|
+
inputs: ['root/resultset (optional)', 'sort_order', 'raise_on_stale']
|
|
69
70
|
},
|
|
70
71
|
{
|
|
71
72
|
tool: ValidateTool,
|
|
72
73
|
label: 'Validate coverage policy',
|
|
73
74
|
use_when: 'User needs to enforce coverage rules (e.g., minimum percentage) in CI.',
|
|
74
75
|
avoid_when: 'User just wants to view coverage data.',
|
|
75
|
-
inputs: ['
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
tool: ValidateTool,
|
|
79
|
-
label: 'Validate coverage policy',
|
|
80
|
-
use_when: 'User needs to enforce coverage rules (e.g., minimum percentage) in CI.',
|
|
81
|
-
avoid_when: 'User just wants to view coverage data.',
|
|
82
|
-
inputs: ['path (required)', 'root/resultset (optional)']
|
|
76
|
+
inputs: ['code OR file (one required)', 'root/resultset/raise_on_stale (optional)']
|
|
83
77
|
},
|
|
84
78
|
{
|
|
85
79
|
tool: VersionTool,
|
|
@@ -91,12 +85,14 @@ module CovLoupe
|
|
|
91
85
|
].freeze
|
|
92
86
|
|
|
93
87
|
class << self
|
|
94
|
-
def call(error_mode: 'log', server_context:, **_unused)
|
|
95
|
-
|
|
88
|
+
def call(error_mode: 'log', output_chars: nil, server_context:, **_unused)
|
|
89
|
+
# Normalize output_chars before error handling so errors also get converted
|
|
90
|
+
output_chars_sym = resolve_output_chars(output_chars, server_context)
|
|
91
|
+
with_error_handling('HelpTool', error_mode: error_mode, output_chars: output_chars_sym) do
|
|
96
92
|
entries = TOOL_GUIDE.map { |guide| format_entry(guide) }
|
|
97
93
|
|
|
98
94
|
data = { tools: entries }
|
|
99
|
-
respond_json(data, name: 'tools_help.json')
|
|
95
|
+
respond_json(data, name: 'tools_help.json', output_chars: output_chars_sym)
|
|
100
96
|
end
|
|
101
97
|
end
|
|
102
98
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../model/model'
|
|
4
|
+
require_relative '../base_tool'
|
|
5
|
+
require_relative '../presenters/project_coverage_presenter'
|
|
6
|
+
require_relative '../config/option_normalizers'
|
|
7
|
+
|
|
8
|
+
module CovLoupe
|
|
9
|
+
module Tools
|
|
10
|
+
class ListTool < BaseTool
|
|
11
|
+
description <<~DESC
|
|
12
|
+
Use this when the user wants coverage percentages for every tracked file in the project.
|
|
13
|
+
Do not use this for single-file stats; prefer coverage.summary or coverage.uncovered_lines for that.
|
|
14
|
+
Inputs: optional project root, alternate .resultset path, sort order, raise_on_stale flag, and tracked_globs to alert on new files.
|
|
15
|
+
Output: JSON {"files": [{"file","covered","total","percentage","stale"}, ...], "counts": {"total", "ok", "stale"}, "skipped_files": [...], "missing_tracked_files": [...], "newer_files": [...], "deleted_files": [...], "length_mismatch_files": [...], "unreadable_files": [...], "timestamp_status": "ok"|"missing", "warnings": [string, ...]} sorted as requested. "stale" is "ok", "missing", "newer", "length_mismatch", or "error". "timestamp_status" indicates whether coverage timestamps are available for time-based staleness checks. "warnings" array is present when timestamp_status is "missing".
|
|
16
|
+
Examples: "List files with the lowest coverage"; "Show repo coverage sorted descending".
|
|
17
|
+
DESC
|
|
18
|
+
input_schema(**coverage_schema(
|
|
19
|
+
additional_properties: {
|
|
20
|
+
sort_order: SORT_ORDER_PROPERTY,
|
|
21
|
+
tracked_globs: TRACKED_GLOBS_PROPERTY
|
|
22
|
+
}
|
|
23
|
+
))
|
|
24
|
+
class << self
|
|
25
|
+
def call(root: nil, resultset: nil, sort_order: nil, raise_on_stale: nil,
|
|
26
|
+
tracked_globs: nil, error_mode: 'log', output_chars: nil, server_context:)
|
|
27
|
+
output_chars_sym = resolve_output_chars(output_chars, server_context)
|
|
28
|
+
with_error_handling('ListTool', error_mode: error_mode, output_chars: output_chars_sym) do
|
|
29
|
+
model, config = create_configured_model(
|
|
30
|
+
server_context: server_context,
|
|
31
|
+
root: root,
|
|
32
|
+
resultset: resultset,
|
|
33
|
+
raise_on_stale: raise_on_stale,
|
|
34
|
+
tracked_globs: tracked_globs
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Normalize and validate sort_order (supports 'a'/'d' abbreviations)
|
|
38
|
+
sort_order_sym = OptionNormalizers.normalize_sort_order(
|
|
39
|
+
sort_order || BaseTool::DEFAULT_SORT_ORDER, strict: true
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
presenter = Presenters::ProjectCoveragePresenter.new(
|
|
43
|
+
model: model,
|
|
44
|
+
sort_order: sort_order_sym,
|
|
45
|
+
raise_on_stale: config[:raise_on_stale],
|
|
46
|
+
tracked_globs: config[:tracked_globs]
|
|
47
|
+
)
|
|
48
|
+
payload = presenter.relativized_payload
|
|
49
|
+
|
|
50
|
+
# Add warnings array if timestamp_status is missing
|
|
51
|
+
if payload['timestamp_status'] == 'missing'
|
|
52
|
+
payload['warnings'] = [
|
|
53
|
+
'Coverage timestamps are missing. Time-based staleness checks were skipped.',
|
|
54
|
+
'Files may appear "ok" even if source code is newer than the coverage data.',
|
|
55
|
+
'Check your coverage tool configuration to ensure timestamps are recorded.'
|
|
56
|
+
]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
respond_json(payload, name: 'list_coverage.json', output_chars: output_chars_sym)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../base_tool'
|
|
4
|
-
require_relative '../model'
|
|
5
|
-
require_relative '../presenters/
|
|
4
|
+
require_relative '../model/model'
|
|
5
|
+
require_relative '../presenters/coverage_payload_presenter'
|
|
6
6
|
|
|
7
7
|
module CovLoupe
|
|
8
8
|
module Tools
|
|
@@ -10,23 +10,23 @@ module CovLoupe
|
|
|
10
10
|
description <<~DESC
|
|
11
11
|
Use this when the user wants to know which lines in a file still lack coverage.
|
|
12
12
|
Do not use this for overall percentages; coverage.summary is faster when counts are enough.
|
|
13
|
-
Inputs: file path (required) plus optional root/resultset/
|
|
13
|
+
Inputs: file path (required) plus optional root/resultset/raise_on_stale flag inherited from BaseTool.
|
|
14
14
|
Output: JSON object with keys "file", "uncovered" (array of integers), "summary" {"covered","total","percentage"}, and "stale" status.
|
|
15
15
|
Example: "List uncovered lines for lib/cov_loupe/tools/coverage_summary_tool.rb".
|
|
16
16
|
DESC
|
|
17
17
|
input_schema(**input_schema_def)
|
|
18
18
|
class << self
|
|
19
|
-
def call(path:, root:
|
|
20
|
-
server_context:)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
def call(path:, root: nil, resultset: nil, raise_on_stale: nil, error_mode: 'log',
|
|
20
|
+
output_chars: nil, server_context:)
|
|
21
|
+
call_with_file_payload(
|
|
22
|
+
path: path,
|
|
23
|
+
error_mode: error_mode,
|
|
24
|
+
output_chars: output_chars,
|
|
25
|
+
server_context: server_context,
|
|
26
|
+
root: root,
|
|
27
|
+
resultset: resultset,
|
|
28
|
+
raise_on_stale: raise_on_stale
|
|
29
|
+
)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|