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
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
## MCP JSON Inputs
|
|
2
|
+
|
|
3
|
+
[Back to main README](../../docs/index.md)
|
|
4
|
+
|
|
5
|
+
This directory contains example JSON-RPC requests that can be sent to the MCP server over stdio.
|
|
6
|
+
|
|
7
|
+
Each file contains a single line of JSON (NDJSON-ready), so you can pipe it directly to the executable.
|
|
8
|
+
|
|
9
|
+
**Target Project:** These inputs are designed to work with the demo project located at `docs/fixtures/demo_project`.
|
|
10
|
+
|
|
11
|
+
### Running the Examples
|
|
12
|
+
|
|
13
|
+
From the repository root:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json
|
|
17
|
+
exe/cov-loupe -m mcp < examples/mcp-inputs/uncovered_lines.json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
If `cov-loupe` is installed globally and available on your `PATH`:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Formatting Tips (jq and rexe)
|
|
27
|
+
|
|
28
|
+
You can use tools like [jq](https://github.com/jqlang/jq) or [rexe](https://github.com/keithrbennett/rexe) to format the JSON input and output, which is especially helpful for debugging.
|
|
29
|
+
|
|
30
|
+
**Pretty-print an input file:**
|
|
31
|
+
|
|
32
|
+
Using `jq`:
|
|
33
|
+
```sh
|
|
34
|
+
jq . examples/mcp-inputs/coverage_summary.json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Using Ruby:
|
|
38
|
+
```sh
|
|
39
|
+
ruby -r json -e '
|
|
40
|
+
puts JSON.pretty_generate(JSON.parse(File.read("examples/mcp-inputs/coverage_summary.json")))
|
|
41
|
+
'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Using `rexe`:
|
|
45
|
+
```sh
|
|
46
|
+
rexe -f examples/mcp-inputs/coverage_summary.json -oJ
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Pretty-print the MCP server's JSON response (NDJSON):**
|
|
50
|
+
|
|
51
|
+
Using `jq`:
|
|
52
|
+
```sh
|
|
53
|
+
exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json | jq .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Using Ruby:
|
|
57
|
+
```sh
|
|
58
|
+
exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json | ruby -r json -e '
|
|
59
|
+
puts JSON.pretty_generate(JSON.parse($stdin.read))
|
|
60
|
+
'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Using `rexe`:
|
|
64
|
+
```sh
|
|
65
|
+
exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json | rexe -ml -ij -oJ
|
|
66
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"coverage_detailed_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"coverage_raw_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"coverage_summary_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"list_tool","arguments":{"root":"docs/fixtures/demo_project"}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"uncovered_lines_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## Example Prompts for MCP-Aware Assistants
|
|
2
|
+
|
|
3
|
+
[Back to main README](../../docs/index.md)
|
|
4
|
+
|
|
5
|
+
This directory contains example natural-language prompts that you can use with an MCP-enabled AI assistant to interact with the `cov-loupe` server and analyze your project's test coverage.
|
|
6
|
+
|
|
7
|
+
These prompts demonstrate how to request different types of coverage information. You can adapt them to your specific project and needs.
|
|
8
|
+
|
|
9
|
+
### Getting Started
|
|
10
|
+
|
|
11
|
+
1. **Copy a prompt:** Choose a prompt from one of the `.txt` files in this directory.
|
|
12
|
+
2. **Paste it into your assistant:** Paste the prompt into your chat with an MCP-enabled AI assistant.
|
|
13
|
+
3. **Adjust file paths:** If necessary, change the file paths in the prompt to match your project's structure.
|
|
14
|
+
|
|
15
|
+
### Example Prompts
|
|
16
|
+
|
|
17
|
+
* **`summary.txt`**: A basic prompt to get a high-level summary of your project's test coverage.
|
|
18
|
+
* **`detailed_with_source.txt`**: A more advanced prompt that requests a detailed breakdown of coverage, including the source code of the files.
|
|
19
|
+
* **`list_lowest.txt`**: A prompt to find the files with the lowest test coverage.
|
|
20
|
+
* **`uncovered.txt`**: A prompt to get a list of all the lines that are not covered by tests.
|
|
21
|
+
* **`custom_resultset.txt`**: An example of how to specify a custom SimpleCov resultset file for analysis.
|
|
22
|
+
|
|
23
|
+
### Tips for Writing Your Own Prompts
|
|
24
|
+
|
|
25
|
+
* **Be specific:** The more specific you are in your request, the better the assistant will be able to understand you.
|
|
26
|
+
* **Request JSON for machine-readable output:** If you want to process the output programmatically, ask for the results in JSON format.
|
|
27
|
+
* **Specify the root directory:** If your project is not in the current working directory, you can specify the root directory in your prompt.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Read coverage from build/coverage/.resultset.json for src/app.rb. Compare its coverage level to typical standards for application entry points. If coverage is incomplete, explain what failure modes or edge cases might be untested and why that matters for a main application file.
|
|
2
|
+
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Identify the 5 files with the lowest test coverage. For each, analyze what type of code it contains (core logic, utilities, error handling, etc.) and assess the risk of inadequate testing. Recommend a priority order for adding tests based on both coverage percentage and code criticality.
|
|
2
|
+
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Coverage Validation Predicate Examples
|
|
2
|
+
|
|
3
|
+
[Back to main README](../../docs/index.md)
|
|
4
|
+
|
|
5
|
+
This directory contains example coverage validation predicates for use with the `validate` subcommand.
|
|
6
|
+
|
|
7
|
+
> **⚠️ SECURITY WARNING**
|
|
8
|
+
>
|
|
9
|
+
> Success predicates execute as **arbitrary Ruby code with full system privileges**. They have unrestricted access to:
|
|
10
|
+
> - File system operations (read, write, delete)
|
|
11
|
+
> - Network operations (HTTP requests, sockets)
|
|
12
|
+
> - System commands (via backticks, `system()`, `exec()`, etc.)
|
|
13
|
+
> - Environment variables and sensitive data
|
|
14
|
+
>
|
|
15
|
+
> **Only use predicate files from trusted sources.** Treat them like any other executable code in your project.
|
|
16
|
+
> - Never use predicates from untrusted or unknown sources
|
|
17
|
+
> - Review predicates before use, especially in CI/CD environments
|
|
18
|
+
> - Store predicates in version control with code review
|
|
19
|
+
> - Be cautious when copying examples from the internet
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
**File mode:**
|
|
24
|
+
```sh
|
|
25
|
+
cov-loupe validate examples/success_predicates/<filename>.rb
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**String mode:**
|
|
29
|
+
```sh
|
|
30
|
+
cov-loupe validate -i '->(model) { model.list["files"].all? { |f| f["percentage"] >= 80 } }'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The predicate receives a `CoverageModel` instance and returns:
|
|
34
|
+
- **Truthy value** → Exit code 0 (success)
|
|
35
|
+
- **Falsy value** → Exit code 1 (failure)
|
|
36
|
+
- **Exception** → Exit code 2 (error)
|
|
37
|
+
|
|
38
|
+
## Available Examples
|
|
39
|
+
|
|
40
|
+
### `all_files_above_threshold_predicate.rb`
|
|
41
|
+
All files must have >= 80% coverage.
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
cov-loupe validate examples/success_predicates/all_files_above_threshold_predicate.rb
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### `project_coverage_minimum_predicate.rb`
|
|
48
|
+
Total project coverage must be >= 85%.
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
cov-loupe validate examples/success_predicates/project_coverage_minimum_predicate.rb
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `directory_specific_thresholds_predicate.rb`
|
|
55
|
+
Different thresholds for different directories:
|
|
56
|
+
- `lib/api/` - 90% required
|
|
57
|
+
- `lib/core/` - 85% required
|
|
58
|
+
- `lib/legacy/` - 60% required
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
cov-loupe validate examples/success_predicates/directory_specific_thresholds_predicate.rb
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Creating Custom Predicates
|
|
65
|
+
|
|
66
|
+
A predicate must be a callable object (lambda, proc, or class with `#call` method):
|
|
67
|
+
|
|
68
|
+
**Lambda example:**
|
|
69
|
+
```ruby
|
|
70
|
+
->(model) do
|
|
71
|
+
model.list['files'].all? { |f| f['percentage'] >= 80 }
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Class method example:**
|
|
76
|
+
```ruby
|
|
77
|
+
class MyPolicy
|
|
78
|
+
def self.call(model)
|
|
79
|
+
model.list['files'].all? { |f| f['percentage'] >= @threshold }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
MyPolicy # The class itself
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Instance method example:**
|
|
87
|
+
```ruby
|
|
88
|
+
class MyPolicy
|
|
89
|
+
def initialize(threshold = 80)
|
|
90
|
+
@threshold = threshold
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def call(model)
|
|
94
|
+
model.list['files'].all? { |f| f['percentage'] >= @threshold }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
MyPolicy
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### CoverageModel API
|
|
103
|
+
|
|
104
|
+
The `model` parameter provides:
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
# Get all files
|
|
108
|
+
files = model.list['files']
|
|
109
|
+
# => [{ "file" => "...", "covered" => 12, "total" => 14, "percentage" => 85.71, "stale" => false }, ...]
|
|
110
|
+
|
|
111
|
+
# Filter by globs
|
|
112
|
+
api_files = model.list(tracked_globs: ['lib/api/**/*.rb'])['files']
|
|
113
|
+
|
|
114
|
+
# Get specific file data
|
|
115
|
+
summary = model.summary_for('lib/model.rb')
|
|
116
|
+
uncovered = model.uncovered_for('lib/model.rb')
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
See [docs/user/LIBRARY_API.md](../../docs/user/LIBRARY_API.md) for the complete API.
|
|
120
|
+
|
|
121
|
+
### When to Use Standalone Scripts Instead
|
|
122
|
+
|
|
123
|
+
For more complex scenarios, you may prefer writing a standalone Ruby script that uses the `cov-loupe` library directly instead of using the `validate` subcommand.
|
|
124
|
+
|
|
125
|
+
**Use a standalone script when:**
|
|
126
|
+
- **External dependencies needed** - Your policy requires other gems or libraries
|
|
127
|
+
- **Complex setup required** - You need custom logging, database connections, or API calls
|
|
128
|
+
- **Easier testing desired** - Standalone scripts can be tested like any Ruby code
|
|
129
|
+
- **More explicit control** - You want full control over model initialization and error handling
|
|
130
|
+
- **Sophisticated logic** - Multi-step analysis, data aggregation, or integration with other tools
|
|
131
|
+
|
|
132
|
+
**Predicate approach is better when:**
|
|
133
|
+
- Policy is simple and self-contained (most common use case)
|
|
134
|
+
- You want the tool to handle option parsing (--resultset, --raise-on-stale, etc.)
|
|
135
|
+
- Consistent error handling and exit codes are desired
|
|
136
|
+
- Less boilerplate is preferred
|
|
137
|
+
|
|
138
|
+
**Example standalone script:**
|
|
139
|
+
```ruby
|
|
140
|
+
#!/usr/bin/env ruby
|
|
141
|
+
require 'cov_loupe'
|
|
142
|
+
require 'httparty' # External gem
|
|
143
|
+
|
|
144
|
+
# Custom initialization
|
|
145
|
+
model = CovLoupe::CoverageModel.new(
|
|
146
|
+
resultset: ENV['COVERAGE_PATH'],
|
|
147
|
+
raise_on_stale: true
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Complex logic with external API
|
|
151
|
+
files = model.list['files']
|
|
152
|
+
low_coverage_files = files.select { |f| f['percentage'] < 80 }
|
|
153
|
+
|
|
154
|
+
# Post to Slack
|
|
155
|
+
if low_coverage_files.any?
|
|
156
|
+
HTTParty.post(
|
|
157
|
+
ENV['SLACK_WEBHOOK_URL'],
|
|
158
|
+
body: { text: "#{low_coverage_files.size} files below 80%" }.to_json
|
|
159
|
+
)
|
|
160
|
+
exit 1
|
|
161
|
+
else
|
|
162
|
+
exit 0
|
|
163
|
+
end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Both approaches execute arbitrary code with full system privileges, so the security considerations are identical. Choose the approach that best fits your use case.
|
|
167
|
+
|
|
168
|
+
## CI/CD Integration
|
|
169
|
+
|
|
170
|
+
**GitHub Actions:**
|
|
171
|
+
```yaml
|
|
172
|
+
- name: Enforce Coverage Policy
|
|
173
|
+
run: bundle exec cov-loupe validate coverage_policy.rb
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**GitLab CI:**
|
|
177
|
+
```yaml
|
|
178
|
+
coverage:enforce:
|
|
179
|
+
script:
|
|
180
|
+
- bundle exec cov-loupe validate coverage_policy.rb
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Jenkins:**
|
|
184
|
+
```groovy
|
|
185
|
+
stage('Coverage Policy') {
|
|
186
|
+
steps {
|
|
187
|
+
sh 'bundle exec cov-loupe validate coverage_policy.rb'
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Exit Codes
|
|
193
|
+
|
|
194
|
+
- **0** - Predicate returned truthy (success)
|
|
195
|
+
- **1** - Predicate returned falsy (failure)
|
|
196
|
+
- **2** - Predicate raised an error
|
|
197
|
+
|
|
198
|
+
Use exit code 1 to fail CI/CD builds when coverage doesn't meet policy.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Success predicate: All files must have >= 80% coverage, illustrates use of a class `call` method
|
|
4
|
+
# Usage: cov-loupe --success-predicate examples/success_predicates/all_files_above_threshold_predicate.rb
|
|
5
|
+
class AllFilesAboveThreshold
|
|
6
|
+
THRESHOLD = 95
|
|
7
|
+
|
|
8
|
+
def self.call(model)
|
|
9
|
+
low_files = model.list.select { |f| f['percentage'] < THRESHOLD }
|
|
10
|
+
|
|
11
|
+
if low_files.any?
|
|
12
|
+
# Can add custom logging/reporting here
|
|
13
|
+
warn "Files below #{THRESHOLD}%:"
|
|
14
|
+
low_files.each { |f| warn format('%5.1f%% %s', f['percentage'], f['name']) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
low_files.none?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
AllFilesAboveThreshold
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Success predicate: Different thresholds for different directories, using a `call` class method
|
|
4
|
+
# Usage: cov-loupe --success-predicate examples/success_predicates/directory_specific_thresholds_predicate.rb
|
|
5
|
+
|
|
6
|
+
class DirectorySpecificThresholds
|
|
7
|
+
def self.call(model)
|
|
8
|
+
new(model).call
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(model)
|
|
12
|
+
@files = model.relativize(model.list)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def files_ok?(filemask, threshold_percentage)
|
|
16
|
+
files = @files.select { |f| File.fnmatch?(filemask, f['file']) }
|
|
17
|
+
files.all? { |f| f['percentage'] >= threshold_percentage }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call
|
|
21
|
+
[
|
|
22
|
+
['lib/cov_loupe/**/*.rb', 85], # global default minimum
|
|
23
|
+
['lib/cov_loupe/option_parsers/**/*.rb', 95],
|
|
24
|
+
['lib/cov_loupe/tools/**/*.rb', 100]
|
|
25
|
+
].map { |(filemask, threshold_pct)| files_ok?(filemask, threshold_pct) }
|
|
26
|
+
.all?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
DirectorySpecificThresholds
|