simplecov-mcp 0.3.0 → 1.0.0
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/LICENSE +21 -0
- data/README.md +173 -356
- data/docs/ADVANCED_USAGE.md +967 -0
- data/docs/ARCHITECTURE.md +79 -0
- data/docs/BRANCH_ONLY_COVERAGE.md +81 -0
- data/docs/CLI_USAGE.md +637 -0
- data/docs/DEVELOPMENT.md +82 -0
- data/docs/ERROR_HANDLING.md +93 -0
- data/docs/EXAMPLES.md +430 -0
- data/docs/INSTALLATION.md +352 -0
- data/docs/LIBRARY_API.md +635 -0
- data/docs/MCP_INTEGRATION.md +488 -0
- data/docs/TROUBLESHOOTING.md +276 -0
- data/docs/arch-decisions/001-x-arch-decision.md +93 -0
- data/docs/arch-decisions/002-x-arch-decision.md +157 -0
- data/docs/arch-decisions/003-x-arch-decision.md +163 -0
- data/docs/arch-decisions/004-x-arch-decision.md +199 -0
- data/docs/arch-decisions/005-x-arch-decision.md +187 -0
- data/docs/arch-decisions/README.md +60 -0
- data/docs/presentations/simplecov-mcp-presentation.md +249 -0
- data/exe/simplecov-mcp +4 -4
- data/lib/simplecov_mcp/app_context.rb +26 -0
- data/lib/simplecov_mcp/base_tool.rb +74 -0
- data/lib/simplecov_mcp/cli.rb +234 -0
- data/lib/simplecov_mcp/cli_config.rb +56 -0
- data/lib/simplecov_mcp/commands/base_command.rb +78 -0
- data/lib/simplecov_mcp/commands/command_factory.rb +39 -0
- data/lib/simplecov_mcp/commands/detailed_command.rb +24 -0
- data/lib/simplecov_mcp/commands/list_command.rb +13 -0
- data/lib/simplecov_mcp/commands/raw_command.rb +22 -0
- data/lib/simplecov_mcp/commands/summary_command.rb +24 -0
- data/lib/simplecov_mcp/commands/uncovered_command.rb +26 -0
- data/lib/simplecov_mcp/commands/version_command.rb +18 -0
- data/lib/simplecov_mcp/constants.rb +22 -0
- data/lib/simplecov_mcp/error_handler.rb +124 -0
- data/lib/simplecov_mcp/error_handler_factory.rb +31 -0
- data/lib/simplecov_mcp/errors.rb +179 -0
- data/lib/simplecov_mcp/formatters/source_formatter.rb +148 -0
- data/lib/simplecov_mcp/mcp_server.rb +40 -0
- data/lib/simplecov_mcp/mode_detector.rb +55 -0
- data/lib/simplecov_mcp/model.rb +300 -0
- data/lib/simplecov_mcp/option_normalizers.rb +92 -0
- data/lib/simplecov_mcp/option_parser_builder.rb +134 -0
- data/lib/simplecov_mcp/option_parsers/env_options_parser.rb +50 -0
- data/lib/simplecov_mcp/option_parsers/error_helper.rb +109 -0
- data/lib/simplecov_mcp/path_relativizer.rb +61 -0
- data/lib/simplecov_mcp/presenters/base_coverage_presenter.rb +44 -0
- data/lib/simplecov_mcp/presenters/coverage_detailed_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/coverage_raw_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/coverage_summary_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/coverage_uncovered_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/project_coverage_presenter.rb +52 -0
- data/lib/simplecov_mcp/resolvers/coverage_line_resolver.rb +126 -0
- data/lib/simplecov_mcp/resolvers/resolver_factory.rb +28 -0
- data/lib/simplecov_mcp/resolvers/resultset_path_resolver.rb +78 -0
- data/lib/simplecov_mcp/resultset_loader.rb +136 -0
- data/lib/simplecov_mcp/staleness_checker.rb +243 -0
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/all_files_coverage_tool.rb +31 -13
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/coverage_detailed_tool.rb +7 -7
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/coverage_raw_tool.rb +7 -7
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/coverage_summary_tool.rb +7 -7
- data/lib/simplecov_mcp/tools/coverage_table_tool.rb +90 -0
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/help_tool.rb +13 -4
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/uncovered_lines_tool.rb +7 -7
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/version_tool.rb +11 -3
- data/lib/simplecov_mcp/util.rb +82 -0
- data/lib/{simple_cov_mcp → simplecov_mcp}/version.rb +1 -1
- data/lib/simplecov_mcp.rb +144 -2
- data/spec/MCP_INTEGRATION_TESTS_README.md +111 -0
- data/spec/TIMESTAMPS.md +48 -0
- data/spec/all_files_coverage_tool_spec.rb +29 -25
- data/spec/base_tool_spec.rb +11 -10
- data/spec/cli/show_default_report_spec.rb +33 -0
- data/spec/cli_config_spec.rb +137 -0
- data/spec/cli_enumerated_options_spec.rb +68 -0
- data/spec/cli_error_spec.rb +105 -47
- data/spec/cli_source_spec.rb +82 -23
- data/spec/cli_spec.rb +140 -5
- data/spec/cli_success_predicate_spec.rb +141 -0
- data/spec/cli_table_spec.rb +1 -1
- data/spec/cli_usage_spec.rb +10 -26
- data/spec/commands/base_command_spec.rb +187 -0
- data/spec/commands/command_factory_spec.rb +72 -0
- data/spec/commands/detailed_command_spec.rb +48 -0
- data/spec/commands/raw_command_spec.rb +46 -0
- data/spec/commands/summary_command_spec.rb +47 -0
- data/spec/commands/uncovered_command_spec.rb +49 -0
- data/spec/constants_spec.rb +61 -0
- data/spec/coverage_table_tool_spec.rb +17 -33
- data/spec/error_handler_spec.rb +22 -13
- data/spec/error_mode_spec.rb +143 -0
- data/spec/errors_edge_cases_spec.rb +239 -0
- data/spec/errors_stale_spec.rb +2 -2
- data/spec/file_based_mcp_tools_spec.rb +99 -0
- data/spec/fixtures/project1/lib/bar.rb +0 -1
- data/spec/fixtures/project1/lib/foo.rb +0 -1
- data/spec/help_tool_spec.rb +11 -17
- data/spec/integration_spec.rb +845 -0
- data/spec/logging_fallback_spec.rb +128 -0
- data/spec/mcp_logging_spec.rb +44 -0
- data/spec/mcp_server_integration_spec.rb +23 -0
- data/spec/mcp_server_spec.rb +15 -4
- data/spec/mode_detector_spec.rb +148 -0
- data/spec/model_error_handling_spec.rb +210 -0
- data/spec/model_staleness_spec.rb +40 -10
- data/spec/option_normalizers_spec.rb +204 -0
- data/spec/option_parsers/env_options_parser_spec.rb +233 -0
- data/spec/option_parsers/error_helper_spec.rb +222 -0
- data/spec/path_relativizer_spec.rb +83 -0
- data/spec/presenters/coverage_detailed_presenter_spec.rb +19 -0
- data/spec/presenters/coverage_raw_presenter_spec.rb +15 -0
- data/spec/presenters/coverage_summary_presenter_spec.rb +15 -0
- data/spec/presenters/coverage_uncovered_presenter_spec.rb +16 -0
- data/spec/presenters/project_coverage_presenter_spec.rb +86 -0
- data/spec/resolvers/coverage_line_resolver_spec.rb +57 -0
- data/spec/resolvers/resolver_factory_spec.rb +61 -0
- data/spec/resolvers/resultset_path_resolver_spec.rb +55 -0
- data/spec/resultset_loader_spec.rb +167 -0
- data/spec/shared_examples/README.md +115 -0
- data/spec/shared_examples/coverage_presenter_examples.rb +66 -0
- data/spec/shared_examples/file_based_mcp_tools.rb +174 -0
- data/spec/shared_examples/mcp_tool_text_json_response.rb +16 -0
- data/spec/simple_cov_mcp_module_spec.rb +16 -0
- data/spec/simplecov_mcp_model_spec.rb +340 -9
- data/spec/simplecov_mcp_opts_spec.rb +182 -0
- data/spec/spec_helper.rb +147 -4
- data/spec/staleness_checker_spec.rb +373 -0
- data/spec/staleness_more_spec.rb +16 -13
- data/spec/support/mcp_runner.rb +64 -0
- data/spec/tools_error_handling_spec.rb +144 -0
- data/spec/util_spec.rb +109 -34
- data/spec/version_spec.rb +117 -9
- data/spec/version_tool_spec.rb +131 -10
- metadata +120 -63
- data/lib/simple_cov/mcp.rb +0 -9
- data/lib/simple_cov_mcp/base_tool.rb +0 -70
- data/lib/simple_cov_mcp/cli.rb +0 -390
- data/lib/simple_cov_mcp/error_handler.rb +0 -131
- data/lib/simple_cov_mcp/error_handler_factory.rb +0 -38
- data/lib/simple_cov_mcp/errors.rb +0 -176
- data/lib/simple_cov_mcp/mcp_server.rb +0 -30
- data/lib/simple_cov_mcp/model.rb +0 -104
- data/lib/simple_cov_mcp/staleness_checker.rb +0 -125
- data/lib/simple_cov_mcp/tools/coverage_table_tool.rb +0 -61
- data/lib/simple_cov_mcp/util.rb +0 -122
- data/lib/simple_cov_mcp.rb +0 -102
- data/spec/coverage_detailed_tool_spec.rb +0 -36
- data/spec/coverage_raw_tool_spec.rb +0 -32
- data/spec/coverage_summary_tool_spec.rb +0 -39
- data/spec/legacy_shim_spec.rb +0 -13
- data/spec/uncovered_lines_tool_spec.rb +0 -33
@@ -0,0 +1,967 @@
|
|
1
|
+
# Advanced Usage Guide
|
2
|
+
|
3
|
+
This guide covers advanced usage patterns, integration strategies, and optimization techniques for simplecov-mcp.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [Advanced MCP Integration](#advanced-mcp-integration)
|
8
|
+
- [Staleness Detection & Validation](#staleness-detection--validation)
|
9
|
+
- [Advanced Path Resolution](#advanced-path-resolution)
|
10
|
+
- [Error Handling Strategies](#error-handling-strategies)
|
11
|
+
- [Custom Ruby Integration](#custom-ruby-integration)
|
12
|
+
- [CI/CD Integration Patterns](#cicd-integration-patterns)
|
13
|
+
- [Advanced Filtering & Glob Patterns](#advanced-filtering--glob-patterns)
|
14
|
+
- [Performance Optimization](#performance-optimization)
|
15
|
+
- [Custom Output Processing](#custom-output-processing)
|
16
|
+
|
17
|
+
---
|
18
|
+
|
19
|
+
## Advanced MCP Integration
|
20
|
+
|
21
|
+
### MCP Error Handling
|
22
|
+
|
23
|
+
The MCP server uses structured error responses. Understanding the error types helps with debugging:
|
24
|
+
|
25
|
+
```json
|
26
|
+
{
|
27
|
+
"jsonrpc": "2.0",
|
28
|
+
"error": {
|
29
|
+
"code": -32603,
|
30
|
+
"message": "Coverage data not found at coverage/.resultset.json",
|
31
|
+
"data": {
|
32
|
+
"type": "FileError",
|
33
|
+
"context": "MCP tool execution"
|
34
|
+
}
|
35
|
+
},
|
36
|
+
"id": 1
|
37
|
+
}
|
38
|
+
```
|
39
|
+
|
40
|
+
**Error Types:**
|
41
|
+
- `FileError` - File not found in coverage or filesystem
|
42
|
+
- `FileNotFoundError` - Source file missing from filesystem
|
43
|
+
- `CoverageDataError` - Invalid or corrupt `.resultset.json`
|
44
|
+
- `CoverageDataStaleError` - Coverage older than source (single file)
|
45
|
+
- `CoverageDataProjectStaleError` - Project-wide staleness issues
|
46
|
+
|
47
|
+
### MCP Server Logging
|
48
|
+
|
49
|
+
The MCP server logs to `simplecov_mcp.log` in the current directory by default. For custom log locations, configure via your MCP client:
|
50
|
+
|
51
|
+
**Claude Code (`claude_desktop_config.json`):**
|
52
|
+
```json
|
53
|
+
{
|
54
|
+
"mcpServers": {
|
55
|
+
"simplecov-mcp": {
|
56
|
+
"command": "simplecov-mcp",
|
57
|
+
"args": ["--log-file", "/var/log/coverage/mcp.log"]
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
```
|
62
|
+
|
63
|
+
**Or use environment variables:**
|
64
|
+
```json
|
65
|
+
{
|
66
|
+
"mcpServers": {
|
67
|
+
"simplecov-mcp": {
|
68
|
+
"command": "simplecov-mcp",
|
69
|
+
"env": {
|
70
|
+
"SIMPLECOV_MCP_OPTS": "--log-file /var/log/coverage/mcp.log"
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
```
|
76
|
+
|
77
|
+
**To log to standard error:**
|
78
|
+
```json
|
79
|
+
{
|
80
|
+
"mcpServers": {
|
81
|
+
"simplecov-mcp": {
|
82
|
+
"command": "simplecov-mcp",
|
83
|
+
"args": ["--log-file", "stderr"]
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
```
|
88
|
+
|
89
|
+
**Note:** Logging to `stdout` is not permitted in MCP mode.
|
90
|
+
|
91
|
+
### Testing MCP Server Manually
|
92
|
+
|
93
|
+
Use JSON-RPC over stdin to test the MCP server:
|
94
|
+
|
95
|
+
```sh
|
96
|
+
# Get version
|
97
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"version_tool","arguments":{}}}' | simplecov-mcp
|
98
|
+
|
99
|
+
# Get file summary
|
100
|
+
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"coverage_summary_tool","arguments":{"path":"lib/simplecov_mcp/model.rb"}}}' | simplecov-mcp
|
101
|
+
|
102
|
+
# List all files with sorting
|
103
|
+
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"all_files_coverage_tool","arguments":{"sort_order":"ascending"}}}' | simplecov-mcp
|
104
|
+
|
105
|
+
# Get uncovered lines
|
106
|
+
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"uncovered_lines_tool","arguments":{"path":"lib/simplecov_mcp/cli.rb"}}}' | simplecov-mcp
|
107
|
+
```
|
108
|
+
|
109
|
+
---
|
110
|
+
|
111
|
+
## Staleness Detection & Validation
|
112
|
+
|
113
|
+
### Understanding Staleness Modes
|
114
|
+
|
115
|
+
Staleness checking prevents using outdated coverage data. Two modes are available:
|
116
|
+
|
117
|
+
**Mode: `off` (default)**
|
118
|
+
- No validation, fastest operation
|
119
|
+
- Coverage data used as-is
|
120
|
+
- Stale indicators still computed but don't block operations
|
121
|
+
|
122
|
+
**Mode: `error`**
|
123
|
+
- Strict validation enabled
|
124
|
+
- Raises errors if coverage is outdated
|
125
|
+
- Perfect for CI/CD pipelines
|
126
|
+
|
127
|
+
### File-Level Staleness
|
128
|
+
|
129
|
+
A file is considered stale when any of the following are true:
|
130
|
+
1. Source file modified after coverage generation
|
131
|
+
2. Line count differs from coverage array length
|
132
|
+
3. File exists in coverage but deleted from filesystem
|
133
|
+
|
134
|
+
**CLI Usage:**
|
135
|
+
```sh
|
136
|
+
# Fail if any file is stale
|
137
|
+
simplecov-mcp --stale error summary lib/model.rb
|
138
|
+
|
139
|
+
# Check specific file staleness
|
140
|
+
simplecov-mcp summary lib/model.rb --stale error
|
141
|
+
```
|
142
|
+
|
143
|
+
**Ruby API:**
|
144
|
+
```ruby
|
145
|
+
model = SimpleCovMcp::CoverageModel.new(
|
146
|
+
staleness: 'error'
|
147
|
+
)
|
148
|
+
|
149
|
+
begin
|
150
|
+
summary = model.summary_for('lib/model.rb')
|
151
|
+
rescue SimpleCovMcp::CoverageDataStaleError => e
|
152
|
+
puts "File modified after coverage: #{e.file_path}"
|
153
|
+
puts "Coverage timestamp: #{e.cov_timestamp}"
|
154
|
+
puts "File mtime: #{e.file_mtime}"
|
155
|
+
puts "Source lines: #{e.src_len}, Coverage lines: #{e.cov_len}"
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
### Project-Level Staleness
|
160
|
+
|
161
|
+
Detects system-wide staleness issues:
|
162
|
+
|
163
|
+
**Conditions Checked:**
|
164
|
+
1. **Newer files** - Any tracked file modified after coverage
|
165
|
+
2. **Missing files** - Tracked files with no coverage data
|
166
|
+
3. **Deleted files** - Coverage exists for non-existent files
|
167
|
+
|
168
|
+
**CLI Usage:**
|
169
|
+
```sh
|
170
|
+
# Track specific patterns
|
171
|
+
simplecov-mcp --stale error \
|
172
|
+
--tracked-globs "lib/**/*.rb" \
|
173
|
+
--tracked-globs "app/**/*.rb"
|
174
|
+
|
175
|
+
# Combine with JSON output for parsing
|
176
|
+
simplecov-mcp list --stale error --json > stale-check.json
|
177
|
+
```
|
178
|
+
|
179
|
+
**Ruby API:**
|
180
|
+
```ruby
|
181
|
+
model = SimpleCovMcp::CoverageModel.new(
|
182
|
+
staleness: 'error',
|
183
|
+
tracked_globs: ['lib/**/*.rb', 'app/**/*.rb']
|
184
|
+
)
|
185
|
+
|
186
|
+
begin
|
187
|
+
files = model.all_files(check_stale: true)
|
188
|
+
rescue SimpleCovMcp::CoverageDataProjectStaleError => e
|
189
|
+
puts "Newer files: #{e.newer_files.join(', ')}"
|
190
|
+
puts "Missing from coverage: #{e.missing_files.join(', ')}"
|
191
|
+
puts "Deleted but in coverage: #{e.deleted_files.join(', ')}"
|
192
|
+
end
|
193
|
+
```
|
194
|
+
|
195
|
+
### Staleness in CI/CD
|
196
|
+
|
197
|
+
**Example: GitHub Actions**
|
198
|
+
```yaml
|
199
|
+
- name: Validate Coverage Freshness
|
200
|
+
run: |
|
201
|
+
bundle exec rspec
|
202
|
+
simplecov-mcp --stale error --tracked-globs "lib/**/*.rb" || {
|
203
|
+
echo "Coverage is stale! Re-run tests."
|
204
|
+
exit 1
|
205
|
+
}
|
206
|
+
```
|
207
|
+
|
208
|
+
**Example: GitLab CI**
|
209
|
+
```yaml
|
210
|
+
coverage:validate:
|
211
|
+
script:
|
212
|
+
- bundle exec rspec
|
213
|
+
- simplecov-mcp list --stale error --json > coverage.json
|
214
|
+
artifacts:
|
215
|
+
reports:
|
216
|
+
coverage_report:
|
217
|
+
coverage_format: cobertura
|
218
|
+
path: coverage.json
|
219
|
+
```
|
220
|
+
|
221
|
+
---
|
222
|
+
|
223
|
+
## Advanced Path Resolution
|
224
|
+
|
225
|
+
### Multi-Strategy Path Matching
|
226
|
+
|
227
|
+
SimpleCov-mcp uses a sophisticated path resolution strategy:
|
228
|
+
|
229
|
+
1. **Exact absolute path match**
|
230
|
+
2. **Relative path resolution from root**
|
231
|
+
3. **Basename (filename) fallback**
|
232
|
+
|
233
|
+
This allows flexible path specifications:
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
model = SimpleCovMcp::CoverageModel.new(root: '/project')
|
237
|
+
|
238
|
+
# All these work:
|
239
|
+
model.summary_for('/project/lib/model.rb') # Absolute
|
240
|
+
model.summary_for('lib/model.rb') # Relative
|
241
|
+
model.summary_for('model.rb') # Basename only
|
242
|
+
```
|
243
|
+
|
244
|
+
### Working with Multiple Projects
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
# Project A
|
248
|
+
model_a = SimpleCovMcp::CoverageModel.new(
|
249
|
+
root: '/projects/service-a',
|
250
|
+
resultset: '/projects/service-a/coverage/.resultset.json'
|
251
|
+
)
|
252
|
+
|
253
|
+
# Project B
|
254
|
+
model_b = SimpleCovMcp::CoverageModel.new(
|
255
|
+
root: '/projects/service-b',
|
256
|
+
resultset: '/projects/service-b/tmp/coverage/.resultset.json'
|
257
|
+
)
|
258
|
+
|
259
|
+
# Compare coverage
|
260
|
+
coverage_a = model_a.all_files
|
261
|
+
coverage_b = model_b.all_files
|
262
|
+
```
|
263
|
+
|
264
|
+
|
265
|
+
|
266
|
+
|
267
|
+
---
|
268
|
+
|
269
|
+
## Error Handling Strategies
|
270
|
+
|
271
|
+
### Context-Aware Error Handling
|
272
|
+
|
273
|
+
SimpleCov-mcp uses different error handling strategies based on context:
|
274
|
+
|
275
|
+
**CLI Mode:**
|
276
|
+
- User-friendly messages
|
277
|
+
- Exit codes (0 = success, 1 = error)
|
278
|
+
- Optional debug mode
|
279
|
+
|
280
|
+
**Library Mode:**
|
281
|
+
- Raises typed exceptions
|
282
|
+
- Programmatic error handling
|
283
|
+
- Full exception details
|
284
|
+
|
285
|
+
**MCP Server Mode:**
|
286
|
+
- JSON-RPC error responses
|
287
|
+
- Logging to file
|
288
|
+
- Structured error data
|
289
|
+
|
290
|
+
### Error Modes
|
291
|
+
|
292
|
+
**CLI Error Modes:**
|
293
|
+
```sh
|
294
|
+
# Silent mode - minimal output
|
295
|
+
simplecov-mcp --error-mode off summary lib/model.rb
|
296
|
+
|
297
|
+
# Standard mode - user-friendly errors (default)
|
298
|
+
simplecov-mcp --error-mode on summary lib/model.rb
|
299
|
+
|
300
|
+
# Verbose mode - full stack traces
|
301
|
+
simplecov-mcp --error-mode trace summary lib/model.rb
|
302
|
+
```
|
303
|
+
|
304
|
+
**Ruby API Error Handling:**
|
305
|
+
```ruby
|
306
|
+
require 'simplecov_mcp'
|
307
|
+
|
308
|
+
begin
|
309
|
+
model = SimpleCovMcp::CoverageModel.new(
|
310
|
+
root: '/project',
|
311
|
+
resultset: '/nonexistent/.resultset.json'
|
312
|
+
)
|
313
|
+
rescue SimpleCovMcp::FileError => e
|
314
|
+
# Handle missing resultset
|
315
|
+
puts "Coverage file not found: #{e.message}"
|
316
|
+
rescue SimpleCovMcp::CoverageDataError => e
|
317
|
+
# Handle corrupt/invalid coverage data
|
318
|
+
puts "Invalid coverage data: #{e.message}"
|
319
|
+
end
|
320
|
+
```
|
321
|
+
|
322
|
+
### Custom Error Handlers
|
323
|
+
|
324
|
+
For library integration, provide custom error handlers:
|
325
|
+
|
326
|
+
```ruby
|
327
|
+
class CustomErrorHandler
|
328
|
+
def handle_error(error, context: nil)
|
329
|
+
# Log to custom service
|
330
|
+
ErrorTracker.notify(error, context: context)
|
331
|
+
|
332
|
+
# Re-raise or handle gracefully
|
333
|
+
raise error
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
cli = SimpleCovMcp::CoverageCLI.new(
|
338
|
+
error_handler: CustomErrorHandler.new
|
339
|
+
)
|
340
|
+
```
|
341
|
+
|
342
|
+
---
|
343
|
+
|
344
|
+
## Custom Ruby Integration
|
345
|
+
|
346
|
+
### Building Custom Coverage Policies
|
347
|
+
|
348
|
+
Use `--success-predicate` to enforce custom coverage policies in CI/CD. Example predicates are in [`examples/success_predicates/`](../../examples/success_predicates/).
|
349
|
+
|
350
|
+
> **⚠️ SECURITY WARNING**
|
351
|
+
>
|
352
|
+
> Success predicates execute as **arbitrary Ruby code with full system privileges**. They have unrestricted access to:
|
353
|
+
> - File system operations (read, write, delete)
|
354
|
+
> - Network operations (HTTP requests, sockets)
|
355
|
+
> - System commands (via backticks, `system()`, `exec()`, etc.)
|
356
|
+
> - Environment variables and sensitive data
|
357
|
+
>
|
358
|
+
> **Only use predicate files from trusted sources.** Treat them like any other executable code in your project.
|
359
|
+
> - Never use predicates from untrusted or unknown sources
|
360
|
+
> - Review predicates before use, especially in CI/CD environments
|
361
|
+
> - Store predicates in version control with code review
|
362
|
+
> - Be cautious when copying examples from the internet
|
363
|
+
|
364
|
+
**Quick Usage:**
|
365
|
+
```sh
|
366
|
+
# All files must be >= 80%
|
367
|
+
simplecov-mcp --success-predicate examples/success_predicates/all_files_above_threshold.rb
|
368
|
+
|
369
|
+
# Total project coverage >= 85%
|
370
|
+
simplecov-mcp --success-predicate examples/success_predicates/project_coverage_minimum.rb
|
371
|
+
|
372
|
+
# Custom predicate
|
373
|
+
simplecov-mcp --success-predicate coverage_policy.rb
|
374
|
+
```
|
375
|
+
|
376
|
+
**Creating a predicate:**
|
377
|
+
```ruby
|
378
|
+
# coverage_policy.rb
|
379
|
+
->(model) do
|
380
|
+
# All files must have >= 80% coverage
|
381
|
+
model.all_files.all? { |f| f['percentage'] >= 80 }
|
382
|
+
end
|
383
|
+
```
|
384
|
+
|
385
|
+
**Advanced predicate with reporting:**
|
386
|
+
```ruby
|
387
|
+
# coverage_policy.rb
|
388
|
+
class CoveragePolicy
|
389
|
+
def call(model)
|
390
|
+
threshold = 80
|
391
|
+
low_files = model.all_files.select { |f| f['percentage'] < threshold }
|
392
|
+
|
393
|
+
if low_files.empty?
|
394
|
+
puts "✓ All files have >= #{threshold}% coverage"
|
395
|
+
true
|
396
|
+
else
|
397
|
+
warn "✗ Files below #{threshold}%:"
|
398
|
+
low_files.each { |f| warn " #{f['file']}: #{f['percentage']}%" }
|
399
|
+
false
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
CoveragePolicy.new
|
405
|
+
```
|
406
|
+
|
407
|
+
**Exit codes:**
|
408
|
+
- `0` - Predicate returned truthy (pass)
|
409
|
+
- `1` - Predicate returned falsy (fail)
|
410
|
+
- `2` - Predicate raised an error
|
411
|
+
|
412
|
+
See [examples/success_predicates/README.md](../../examples/success_predicates/README.md) for more examples.
|
413
|
+
|
414
|
+
### Path Relativization
|
415
|
+
|
416
|
+
Convert absolute paths to relative for cleaner output:
|
417
|
+
|
418
|
+
```ruby
|
419
|
+
model = SimpleCovMcp::CoverageModel.new(root: '/project')
|
420
|
+
|
421
|
+
# Get data with absolute paths
|
422
|
+
data = model.summary_for('lib/model.rb')
|
423
|
+
# => { 'file' => '/project/lib/model.rb', ... }
|
424
|
+
|
425
|
+
# Relativize paths
|
426
|
+
relative_data = model.relativize(data)
|
427
|
+
# => { 'file' => 'lib/model.rb', ... }
|
428
|
+
|
429
|
+
# Works with arrays too
|
430
|
+
files = model.all_files
|
431
|
+
relative_files = model.relativize(files)
|
432
|
+
```
|
433
|
+
|
434
|
+
### Batch Operations
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
# Process multiple files efficiently
|
438
|
+
files_to_check = ['lib/model.rb', 'lib/controller.rb', 'lib/view.rb']
|
439
|
+
|
440
|
+
model = SimpleCovMcp::CoverageModel.new
|
441
|
+
|
442
|
+
results = files_to_check.map do |file|
|
443
|
+
begin
|
444
|
+
{
|
445
|
+
file: file,
|
446
|
+
summary: model.summary_for(file),
|
447
|
+
uncovered: model.uncovered_for(file)
|
448
|
+
}
|
449
|
+
rescue SimpleCovMcp::FileError => e
|
450
|
+
{ file: file, error: e.message }
|
451
|
+
end
|
452
|
+
end
|
453
|
+
```
|
454
|
+
|
455
|
+
---
|
456
|
+
|
457
|
+
## CI/CD Integration Patterns
|
458
|
+
|
459
|
+
### GitHub Actions
|
460
|
+
|
461
|
+
**Complete Workflow:**
|
462
|
+
```yaml
|
463
|
+
name: Coverage Analysis
|
464
|
+
|
465
|
+
on: [push, pull_request]
|
466
|
+
|
467
|
+
jobs:
|
468
|
+
coverage:
|
469
|
+
runs-on: ubuntu-latest
|
470
|
+
steps:
|
471
|
+
- uses: actions/checkout@v3
|
472
|
+
|
473
|
+
- name: Set up Ruby
|
474
|
+
uses: ruby/setup-ruby@v1
|
475
|
+
with:
|
476
|
+
ruby-version: 3.2
|
477
|
+
bundler-cache: true
|
478
|
+
|
479
|
+
- name: Run tests with coverage
|
480
|
+
run: bundle exec rspec
|
481
|
+
|
482
|
+
- name: Install simplecov-mcp
|
483
|
+
run: gem install simplecov-mcp
|
484
|
+
|
485
|
+
- name: Validate coverage freshness
|
486
|
+
run: |
|
487
|
+
simplecov-mcp --stale error \
|
488
|
+
--tracked-globs "lib/**/*.rb" \
|
489
|
+
--tracked-globs "app/**/*.rb"
|
490
|
+
|
491
|
+
- name: Check minimum coverage
|
492
|
+
run: |
|
493
|
+
# Export coverage data
|
494
|
+
simplecov-mcp list --json > coverage.json
|
495
|
+
|
496
|
+
# Use jq to check minimum threshold
|
497
|
+
MIN_COVERAGE=$(jq '[.files[].percentage] | add / length' coverage.json)
|
498
|
+
if (( $(echo "$MIN_COVERAGE < 80" | bc -l) )); then
|
499
|
+
echo "Coverage below 80%: $MIN_COVERAGE%"
|
500
|
+
exit 1
|
501
|
+
fi
|
502
|
+
|
503
|
+
- name: Upload coverage report
|
504
|
+
uses: actions/upload-artifact@v3
|
505
|
+
with:
|
506
|
+
name: coverage-report
|
507
|
+
path: coverage.json
|
508
|
+
|
509
|
+
- name: Comment PR with coverage
|
510
|
+
if: github.event_name == 'pull_request'
|
511
|
+
run: |
|
512
|
+
COVERAGE=$(simplecov-mcp list)
|
513
|
+
gh pr comment ${{ github.event.pull_request.number }} \
|
514
|
+
--body "## Coverage Report\n\`\`\`\n$COVERAGE\n\`\`\`"
|
515
|
+
env:
|
516
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
517
|
+
```
|
518
|
+
|
519
|
+
### GitLab CI
|
520
|
+
|
521
|
+
```yaml
|
522
|
+
coverage:
|
523
|
+
stage: test
|
524
|
+
script:
|
525
|
+
- bundle exec rspec
|
526
|
+
- gem install simplecov-mcp
|
527
|
+
- simplecov-mcp --stale error
|
528
|
+
artifacts:
|
529
|
+
reports:
|
530
|
+
coverage_report:
|
531
|
+
coverage_format: cobertura
|
532
|
+
path: coverage/coverage.xml
|
533
|
+
paths:
|
534
|
+
- coverage/
|
535
|
+
coverage: '/TOTAL.*\s(\d+\.\d+)%/'
|
536
|
+
```
|
537
|
+
|
538
|
+
### Jenkins Pipeline
|
539
|
+
|
540
|
+
```groovy
|
541
|
+
pipeline {
|
542
|
+
agent any
|
543
|
+
|
544
|
+
stages {
|
545
|
+
stage('Test') {
|
546
|
+
steps {
|
547
|
+
sh 'bundle exec rspec'
|
548
|
+
}
|
549
|
+
}
|
550
|
+
|
551
|
+
stage('Coverage Analysis') {
|
552
|
+
steps {
|
553
|
+
sh 'gem install simplecov-mcp'
|
554
|
+
sh '''
|
555
|
+
simplecov-mcp list --json > coverage.json
|
556
|
+
simplecov-mcp --stale error || exit 1
|
557
|
+
'''
|
558
|
+
}
|
559
|
+
}
|
560
|
+
|
561
|
+
stage('Coverage Report') {
|
562
|
+
steps {
|
563
|
+
publishHTML([
|
564
|
+
reportDir: 'coverage',
|
565
|
+
reportFiles: 'index.html',
|
566
|
+
reportName: 'Coverage Report'
|
567
|
+
])
|
568
|
+
}
|
569
|
+
}
|
570
|
+
}
|
571
|
+
}
|
572
|
+
```
|
573
|
+
|
574
|
+
### Pre-commit Hooks
|
575
|
+
|
576
|
+
```sh
|
577
|
+
#!/bin/bash
|
578
|
+
# .git/hooks/pre-commit
|
579
|
+
|
580
|
+
# Run tests
|
581
|
+
bundle exec rspec || exit 1
|
582
|
+
|
583
|
+
# Validate coverage
|
584
|
+
simplecov-mcp --stale error --tracked-globs "lib/**/*.rb" || {
|
585
|
+
echo "Coverage validation failed!"
|
586
|
+
echo "Re-run tests or review coverage changes."
|
587
|
+
exit 1
|
588
|
+
}
|
589
|
+
|
590
|
+
# Check for files with low coverage
|
591
|
+
LOW_COVERAGE=$(simplecov-mcp list --json | \
|
592
|
+
jq -r '.files[] | select(.percentage < 80) | .file' | \
|
593
|
+
head -5)
|
594
|
+
|
595
|
+
if [ -n "$LOW_COVERAGE" ]; then
|
596
|
+
echo "Warning: Files with coverage below 80%:"
|
597
|
+
echo "$LOW_COVERAGE"
|
598
|
+
fi
|
599
|
+
```
|
600
|
+
|
601
|
+
### Using Success Predicates in CI/CD
|
602
|
+
|
603
|
+
Use `--success-predicate` to enforce coverage policies:
|
604
|
+
|
605
|
+
**GitHub Actions:**
|
606
|
+
```yaml
|
607
|
+
- name: Enforce Coverage Policy
|
608
|
+
run: |
|
609
|
+
bundle exec rspec
|
610
|
+
bundle exec simplecov-mcp --success-predicate coverage_policy.rb
|
611
|
+
```
|
612
|
+
|
613
|
+
**GitLab CI:**
|
614
|
+
```yaml
|
615
|
+
coverage:enforce:
|
616
|
+
script:
|
617
|
+
- bundle exec rspec
|
618
|
+
- bundle exec simplecov-mcp --success-predicate coverage_policy.rb
|
619
|
+
```
|
620
|
+
|
621
|
+
**Jenkins:**
|
622
|
+
```groovy
|
623
|
+
stage('Coverage Policy') {
|
624
|
+
steps {
|
625
|
+
sh 'bundle exec rspec'
|
626
|
+
sh 'bundle exec simplecov-mcp --success-predicate coverage_policy.rb'
|
627
|
+
}
|
628
|
+
}
|
629
|
+
```
|
630
|
+
|
631
|
+
The build will fail (exit code 1) if the predicate returns falsy.
|
632
|
+
|
633
|
+
---
|
634
|
+
|
635
|
+
## Advanced Filtering & Glob Patterns
|
636
|
+
|
637
|
+
### Tracked Globs Overview
|
638
|
+
|
639
|
+
Tracked globs serve two purposes:
|
640
|
+
1. **Filter output** - Only show matching files
|
641
|
+
2. **Validate coverage** - Ensure new files have coverage
|
642
|
+
|
643
|
+
### Pattern Syntax
|
644
|
+
|
645
|
+
Uses Ruby's `File.fnmatch` with extended glob support:
|
646
|
+
|
647
|
+
```sh
|
648
|
+
# Single directory
|
649
|
+
--tracked-globs "lib/**/*.rb"
|
650
|
+
|
651
|
+
# Multiple patterns
|
652
|
+
--tracked-globs "lib/**/*.rb" --tracked-globs "app/**/*.rb"
|
653
|
+
|
654
|
+
# Exclude patterns (use CLI filtering)
|
655
|
+
simplecov-mcp list --json | jq '.files[] | select(.file | test("spec") | not)'
|
656
|
+
|
657
|
+
# Complex patterns
|
658
|
+
--tracked-globs "lib/{models,controllers}/**/*.rb"
|
659
|
+
--tracked-globs "app/**/concerns/*.rb"
|
660
|
+
```
|
661
|
+
|
662
|
+
### Use Cases
|
663
|
+
|
664
|
+
**1. Monitor Subsystem Coverage:**
|
665
|
+
```sh
|
666
|
+
# API layer only
|
667
|
+
simplecov-mcp list --tracked-globs "lib/api/**/*.rb"
|
668
|
+
|
669
|
+
# Core business logic
|
670
|
+
simplecov-mcp list --tracked-globs "lib/domain/**/*.rb"
|
671
|
+
```
|
672
|
+
|
673
|
+
**2. Ensure New Files Have Coverage:**
|
674
|
+
```sh
|
675
|
+
# Fail if any tracked file lacks coverage
|
676
|
+
simplecov-mcp --stale error \
|
677
|
+
--tracked-globs "lib/features/**/*.rb"
|
678
|
+
```
|
679
|
+
|
680
|
+
**3. Multi-tier Reporting:**
|
681
|
+
```sh
|
682
|
+
# Generate separate reports per layer
|
683
|
+
for layer in models views controllers; do
|
684
|
+
simplecov-mcp list \
|
685
|
+
--tracked-globs "app/${layer}/**/*.rb" \
|
686
|
+
--json > "coverage-${layer}.json"
|
687
|
+
done
|
688
|
+
```
|
689
|
+
|
690
|
+
### Ruby API with Globs
|
691
|
+
|
692
|
+
```ruby
|
693
|
+
model = SimpleCovMcp::CoverageModel.new
|
694
|
+
|
695
|
+
# Filter files in output
|
696
|
+
api_files = model.all_files(
|
697
|
+
tracked_globs: ['lib/api/**/*.rb']
|
698
|
+
)
|
699
|
+
|
700
|
+
# Multi-pattern filtering
|
701
|
+
core_files = model.all_files(
|
702
|
+
tracked_globs: [
|
703
|
+
'lib/core/**/*.rb',
|
704
|
+
'lib/domain/**/*.rb'
|
705
|
+
]
|
706
|
+
)
|
707
|
+
|
708
|
+
# Validate specific subsystems
|
709
|
+
begin
|
710
|
+
model.all_files(
|
711
|
+
check_stale: true,
|
712
|
+
tracked_globs: ['lib/critical/**/*.rb']
|
713
|
+
)
|
714
|
+
rescue SimpleCovMcp::CoverageDataProjectStaleError => e
|
715
|
+
# Handle missing coverage for critical files
|
716
|
+
puts "Critical files missing coverage:"
|
717
|
+
e.missing_files.each { |f| puts " - #{f}" }
|
718
|
+
end
|
719
|
+
```
|
720
|
+
|
721
|
+
---
|
722
|
+
|
723
|
+
## Performance Optimization
|
724
|
+
|
725
|
+
### Minimizing Coverage Reads
|
726
|
+
|
727
|
+
The `CoverageModel` reads `.resultset.json` once at initialization:
|
728
|
+
|
729
|
+
```ruby
|
730
|
+
# Good: Single model for multiple queries
|
731
|
+
model = SimpleCovMcp::CoverageModel.new
|
732
|
+
files = model.all_files
|
733
|
+
file1 = model.summary_for('lib/a.rb')
|
734
|
+
file2 = model.summary_for('lib/b.rb')
|
735
|
+
|
736
|
+
# Bad: Re-reads coverage for each operation
|
737
|
+
model1 = SimpleCovMcp::CoverageModel.new
|
738
|
+
files = model1.all_files
|
739
|
+
|
740
|
+
model2 = SimpleCovMcp::CoverageModel.new
|
741
|
+
file1 = model2.summary_for('lib/a.rb')
|
742
|
+
```
|
743
|
+
|
744
|
+
### Batch Processing
|
745
|
+
|
746
|
+
```ruby
|
747
|
+
# Process multiple files in one pass
|
748
|
+
files_to_analyze = ['lib/a.rb', 'lib/b.rb', 'lib/c.rb']
|
749
|
+
model = SimpleCovMcp::CoverageModel.new
|
750
|
+
|
751
|
+
results = files_to_analyze.each_with_object({}) do |file, hash|
|
752
|
+
hash[file] = {
|
753
|
+
summary: model.summary_for(file),
|
754
|
+
uncovered: model.uncovered_for(file)
|
755
|
+
}
|
756
|
+
rescue SimpleCovMcp::FileError
|
757
|
+
hash[file] = { error: 'No coverage' }
|
758
|
+
end
|
759
|
+
```
|
760
|
+
|
761
|
+
### Filtering Early
|
762
|
+
|
763
|
+
Use `tracked_globs` to reduce data processing:
|
764
|
+
|
765
|
+
```ruby
|
766
|
+
# Bad: Filter after loading all data
|
767
|
+
all_files = model.all_files
|
768
|
+
api_files = all_files.select { |f| f['file'].include?('api') }
|
769
|
+
|
770
|
+
# Good: Filter during query
|
771
|
+
api_files = model.all_files(
|
772
|
+
tracked_globs: ['lib/api/**/*.rb']
|
773
|
+
)
|
774
|
+
```
|
775
|
+
|
776
|
+
### Caching Coverage Models
|
777
|
+
|
778
|
+
For long-running processes:
|
779
|
+
|
780
|
+
```ruby
|
781
|
+
class CoverageCache
|
782
|
+
def initialize(ttl: 300) # 5 minute cache
|
783
|
+
@cache = {}
|
784
|
+
@ttl = ttl
|
785
|
+
end
|
786
|
+
|
787
|
+
def model_for(root)
|
788
|
+
key = root.to_s
|
789
|
+
now = Time.now
|
790
|
+
|
791
|
+
if @cache[key] && (now - @cache[key][:time] < @ttl)
|
792
|
+
@cache[key][:model]
|
793
|
+
else
|
794
|
+
@cache[key] = {
|
795
|
+
model: SimpleCovMcp::CoverageModel.new(root: root),
|
796
|
+
time: now
|
797
|
+
}
|
798
|
+
@cache[key][:model]
|
799
|
+
end
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
cache = CoverageCache.new
|
804
|
+
model = cache.model_for('/project')
|
805
|
+
```
|
806
|
+
|
807
|
+
---
|
808
|
+
|
809
|
+
## Custom Output Processing
|
810
|
+
|
811
|
+
### Format Conversion
|
812
|
+
|
813
|
+
**CSV Export:**
|
814
|
+
```ruby
|
815
|
+
require 'csv'
|
816
|
+
|
817
|
+
model = SimpleCovMcp::CoverageModel.new
|
818
|
+
files = model.all_files
|
819
|
+
|
820
|
+
CSV.open('coverage.csv', 'w') do |csv|
|
821
|
+
csv << ['File', 'Coverage %', 'Lines Covered', 'Total Lines', 'Stale']
|
822
|
+
files.each do |f|
|
823
|
+
csv << [
|
824
|
+
model.relativize(f)['file'],
|
825
|
+
f['percentage'],
|
826
|
+
f['covered'],
|
827
|
+
f['total'],
|
828
|
+
f['stale']
|
829
|
+
]
|
830
|
+
end
|
831
|
+
end
|
832
|
+
```
|
833
|
+
|
834
|
+
**HTML Report:**
|
835
|
+
```ruby
|
836
|
+
require 'erb'
|
837
|
+
|
838
|
+
template = ERB.new(<<~HTML)
|
839
|
+
<html>
|
840
|
+
<head><title>Coverage Report</title></head>
|
841
|
+
<body>
|
842
|
+
<h1>Coverage Report</h1>
|
843
|
+
<table>
|
844
|
+
<tr>
|
845
|
+
<th>File</th><th>Coverage</th><th>Covered</th><th>Total</th>
|
846
|
+
</tr>
|
847
|
+
<% files.each do |f| %>
|
848
|
+
<tr class="<%= f['percentage'] < 80 ? 'low' : 'ok' %>">
|
849
|
+
<td><%= f['file'] %></td>
|
850
|
+
<td><%= f['percentage'].round(2) %>%</td>
|
851
|
+
<td><%= f['covered'] %></td>
|
852
|
+
<td><%= f['total'] %></td>
|
853
|
+
</tr>
|
854
|
+
<% end %>
|
855
|
+
</table>
|
856
|
+
</body>
|
857
|
+
</html>
|
858
|
+
HTML
|
859
|
+
|
860
|
+
model = SimpleCovMcp::CoverageModel.new
|
861
|
+
files = model.relativize(model.all_files)
|
862
|
+
File.write('coverage.html', template.result(binding))
|
863
|
+
```
|
864
|
+
|
865
|
+
### Annotated Source Output
|
866
|
+
|
867
|
+
The CLI supports annotated source viewing:
|
868
|
+
|
869
|
+
```sh
|
870
|
+
# Show uncovered lines with context
|
871
|
+
simplecov-mcp uncovered lib/model.rb \
|
872
|
+
--source uncovered \
|
873
|
+
--source-context 3
|
874
|
+
|
875
|
+
# Show full file with coverage annotations
|
876
|
+
simplecov-mcp uncovered lib/model.rb \
|
877
|
+
--source full \
|
878
|
+
--source-context 0
|
879
|
+
```
|
880
|
+
|
881
|
+
**Programmatic Source Annotation:**
|
882
|
+
```ruby
|
883
|
+
def annotate_source(file_path)
|
884
|
+
model = SimpleCovMcp::CoverageModel.new
|
885
|
+
details = model.detailed_for(file_path)
|
886
|
+
source_lines = File.readlines(file_path)
|
887
|
+
|
888
|
+
output = []
|
889
|
+
details['lines'].each do |line_data|
|
890
|
+
line_num = line_data['line']
|
891
|
+
hits = line_data['hits']
|
892
|
+
source = source_lines[line_num - 1]
|
893
|
+
|
894
|
+
marker = case hits
|
895
|
+
when nil then ' '
|
896
|
+
when 0 then ' ✗ '
|
897
|
+
else " #{hits} "
|
898
|
+
end
|
899
|
+
|
900
|
+
output << "#{marker}#{line_num.to_s.rjust(4)}: #{source}"
|
901
|
+
end
|
902
|
+
|
903
|
+
output.join
|
904
|
+
end
|
905
|
+
|
906
|
+
puts annotate_source('lib/model.rb')
|
907
|
+
```
|
908
|
+
|
909
|
+
### Integration with Coverage Trackers
|
910
|
+
|
911
|
+
**Send to Codecov:**
|
912
|
+
```sh
|
913
|
+
#!/bin/bash
|
914
|
+
bundle exec rspec
|
915
|
+
simplecov-mcp list --json > coverage.json
|
916
|
+
|
917
|
+
# Transform to Codecov format (example)
|
918
|
+
jq '{
|
919
|
+
coverage: [
|
920
|
+
.files[] | {
|
921
|
+
name: .file,
|
922
|
+
coverage: .percentage
|
923
|
+
}
|
924
|
+
]
|
925
|
+
}' coverage.json | curl -X POST \
|
926
|
+
-H "Authorization: token $CODECOV_TOKEN" \
|
927
|
+
-d @- https://codecov.io/upload
|
928
|
+
```
|
929
|
+
|
930
|
+
**Send to Coveralls:**
|
931
|
+
```ruby
|
932
|
+
require 'simplecov_mcp'
|
933
|
+
require 'net/http'
|
934
|
+
require 'json'
|
935
|
+
|
936
|
+
model = SimpleCovMcp::CoverageModel.new
|
937
|
+
files = model.all_files
|
938
|
+
|
939
|
+
coveralls_data = {
|
940
|
+
repo_token: ENV['COVERALLS_REPO_TOKEN'],
|
941
|
+
source_files: files.map { |f|
|
942
|
+
{
|
943
|
+
name: f['file'],
|
944
|
+
coverage: model.raw_for(f['file'])['lines']
|
945
|
+
}
|
946
|
+
}
|
947
|
+
}
|
948
|
+
|
949
|
+
uri = URI('https://coveralls.io/api/v1/jobs')
|
950
|
+
Net::HTTP.post(uri, coveralls_data.to_json, {
|
951
|
+
'Content-Type' => 'application/json'
|
952
|
+
})
|
953
|
+
```
|
954
|
+
|
955
|
+
---
|
956
|
+
|
957
|
+
## Additional Resources
|
958
|
+
|
959
|
+
- [CLI Usage Guide](CLI_USAGE.md)
|
960
|
+
- [Library API Reference](LIBRARY_API.md)
|
961
|
+
- [MCP Integration Guide](MCP_INTEGRATION.md)
|
962
|
+
- [Error Handling Details](ERROR_HANDLING.md)
|
963
|
+
- [Troubleshooting](TROUBLESHOOTING.md)
|
964
|
+
|
965
|
+
---
|
966
|
+
|
967
|
+
**Made with ❤️ for sophisticated Ruby test coverage analysis**
|