coverband 6.1.4 → 6.1.8

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.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +27 -8
  3. data/.gitignore +3 -1
  4. data/.rubocop.yml +1 -1
  5. data/.standard.yml +1 -1
  6. data/Gemfile +4 -1
  7. data/Gemfile.rails7.0 +3 -0
  8. data/Gemfile.rails7.1 +4 -1
  9. data/{Gemfile.rails7 → Gemfile.rails7.2} +5 -2
  10. data/{Gemfile.rails6.0 → Gemfile.rails8.0} +5 -2
  11. data/README.md +161 -7
  12. data/Rakefile +1 -1
  13. data/agents.md +217 -0
  14. data/bin/coverband-mcp +42 -0
  15. data/changes.md +54 -3
  16. data/coverband.gemspec +5 -2
  17. data/lib/coverband/adapters/base.rb +21 -6
  18. data/lib/coverband/adapters/file_store.rb +1 -2
  19. data/lib/coverband/adapters/hash_redis_store.rb +3 -4
  20. data/lib/coverband/adapters/redis_store.rb +1 -2
  21. data/lib/coverband/adapters/web_service_store.rb +1 -2
  22. data/lib/coverband/collectors/abstract_tracker.rb +5 -5
  23. data/lib/coverband/collectors/delta.rb +4 -4
  24. data/lib/coverband/collectors/route_tracker.rb +2 -2
  25. data/lib/coverband/collectors/view_tracker.rb +33 -15
  26. data/lib/coverband/collectors/view_tracker_service.rb +1 -1
  27. data/lib/coverband/configuration.rb +57 -20
  28. data/lib/coverband/integrations/resque.rb +2 -2
  29. data/lib/coverband/mcp/http_handler.rb +118 -0
  30. data/lib/coverband/mcp/server.rb +116 -0
  31. data/lib/coverband/mcp/tools/get_coverage_summary.rb +41 -0
  32. data/lib/coverband/mcp/tools/get_dead_methods.rb +69 -0
  33. data/lib/coverband/mcp/tools/get_file_coverage.rb +74 -0
  34. data/lib/coverband/mcp/tools/get_route_tracker_data.rb +60 -0
  35. data/lib/coverband/mcp/tools/get_translation_tracker_data.rb +60 -0
  36. data/lib/coverband/mcp/tools/get_uncovered_files.rb +73 -0
  37. data/lib/coverband/mcp/tools/get_view_tracker_data.rb +60 -0
  38. data/lib/coverband/mcp.rb +27 -0
  39. data/lib/coverband/reporters/base.rb +3 -5
  40. data/lib/coverband/reporters/json_report.rb +7 -0
  41. data/lib/coverband/reporters/web.rb +17 -14
  42. data/lib/coverband/utils/absolute_file_converter.rb +37 -7
  43. data/lib/coverband/utils/dead_methods.rb +5 -1
  44. data/lib/coverband/utils/file_list.rb +15 -7
  45. data/lib/coverband/utils/html_formatter.rb +5 -2
  46. data/lib/coverband/utils/lines_classifier.rb +1 -1
  47. data/lib/coverband/utils/method_definition_scanner.rb +14 -2
  48. data/lib/coverband/utils/railtie.rb +1 -1
  49. data/lib/coverband/utils/relative_file_converter.rb +22 -7
  50. data/lib/coverband/utils/result.rb +2 -3
  51. data/lib/coverband/utils/source_file/line.rb +84 -0
  52. data/lib/coverband/utils/source_file.rb +35 -83
  53. data/lib/coverband/utils/tasks.rb +55 -6
  54. data/lib/coverband/version.rb +1 -1
  55. data/lib/coverband.rb +28 -2
  56. data/test/benchmarks/benchmark.rake +16 -18
  57. data/test/benchmarks/benchmark_delta.rb +54 -0
  58. data/test/benchmarks/benchmark_file_list.rb +58 -0
  59. data/test/benchmarks/benchmark_unused_keys.rb +52 -0
  60. data/test/coverband/collectors/coverage_test.rb +3 -7
  61. data/test/coverband/collectors/route_tracker_test.rb +3 -4
  62. data/test/coverband/collectors/translation_tracker_test.rb +1 -2
  63. data/test/coverband/collectors/view_tracker_test.rb +2 -2
  64. data/test/coverband/configuration_test.rb +0 -10
  65. data/test/coverband/file_store_integration_test.rb +72 -0
  66. data/test/coverband/file_store_redis_error_test.rb +56 -0
  67. data/test/coverband/github_issue_586_test.rb +46 -0
  68. data/test/coverband/initialization_timing_test.rb +71 -0
  69. data/test/coverband/integrations/rack_server_check_test.rb +6 -3
  70. data/test/coverband/mcp/http_handler_test.rb +159 -0
  71. data/test/coverband/mcp/security_test.rb +145 -0
  72. data/test/coverband/mcp/server_test.rb +125 -0
  73. data/test/coverband/mcp/tools/get_coverage_summary_test.rb +75 -0
  74. data/test/coverband/mcp/tools/get_dead_methods_test.rb +162 -0
  75. data/test/coverband/mcp/tools/get_file_coverage_test.rb +203 -0
  76. data/test/coverband/mcp/tools/get_route_tracker_data_test.rb +122 -0
  77. data/test/coverband/mcp/tools/get_translation_tracker_data_test.rb +122 -0
  78. data/test/coverband/mcp/tools/get_uncovered_files_test.rb +177 -0
  79. data/test/coverband/mcp/tools/get_view_tracker_data_test.rb +122 -0
  80. data/test/coverband/reporters/console_test.rb +1 -0
  81. data/test/coverband/reporters/json_test.rb +3 -3
  82. data/test/coverband/reporters/web_test.rb +5 -0
  83. data/test/coverband/track_key_test.rb +66 -0
  84. data/test/coverband/tracker_initialization_test.rb +75 -0
  85. data/test/coverband/user_environment_simulation_test.rb +75 -0
  86. data/test/coverband/utils/absolute_file_converter_test.rb +35 -0
  87. data/test/coverband/utils/dead_methods_test.rb +14 -2
  88. data/test/coverband/utils/lines_classifier_test.rb +1 -1
  89. data/test/coverband/utils/method_definition_scanner_test.rb +1 -1
  90. data/test/coverband/utils/relative_file_converter_test.rb +26 -0
  91. data/test/coverband/utils/result_test.rb +19 -0
  92. data/test/coverband/utils/{source_file_line_test.rb → source_file/line_test.rb} +1 -1
  93. data/test/dog.rb +5 -0
  94. data/test/forked/rails_full_stack_views_test.rb +1 -1
  95. data/test/integration/mcp_integration_test.rb +175 -0
  96. data/test/rails7_dummy/config/coverband.rb +13 -1
  97. data/test/rails7_dummy/config/coverband_missing_redis.rb +12 -1
  98. data/test/rails8_dummy/config/coverband.rb +3 -0
  99. data/test/rails8_dummy/config/coverband_missing_redis.rb +3 -0
  100. data/test/rails8_dummy/tmp/local_secret.txt +1 -0
  101. data/test/test_helper.rb +4 -8
  102. data/test/unique_files.rb +6 -2
  103. metadata +105 -59
  104. data/Gemfile.rails6.1 +0 -10
  105. data/test/rails4_dummy/config/application.rb +0 -15
  106. data/test/rails4_dummy/config/coverband.rb +0 -3
  107. data/test/rails4_dummy/config/coverband_missing_redis.rb +0 -3
  108. data/test/rails5_dummy/Rakefile +0 -6
  109. data/test/rails5_dummy/app/controllers/dummy_controller.rb +0 -5
  110. data/test/rails5_dummy/app/controllers/dummy_view_controller.rb +0 -16
  111. data/test/rails5_dummy/app/views/dummy_view/show.html.erb +0 -5
  112. data/test/rails5_dummy/app/views/dummy_view/show_haml.html.haml +0 -4
  113. data/test/rails5_dummy/app/views/dummy_view/show_slim.html.slim +0 -4
  114. data/test/rails5_dummy/config/application.rb +0 -14
  115. data/test/rails5_dummy/config/coverband.rb +0 -15
  116. data/test/rails5_dummy/config/coverband_missing_redis.rb +0 -14
  117. data/test/rails5_dummy/config/environment.rb +0 -2
  118. data/test/rails5_dummy/config/routes.rb +0 -7
  119. data/test/rails5_dummy/config.ru +0 -3
  120. data/test/rails5_dummy/tmp/.keep +0 -0
  121. data/test/rails6_dummy/Rakefile +0 -6
  122. data/test/rails6_dummy/app/controllers/dummy_controller.rb +0 -5
  123. data/test/rails6_dummy/app/controllers/dummy_view_controller.rb +0 -16
  124. data/test/rails6_dummy/app/views/dummy_view/show.html.erb +0 -5
  125. data/test/rails6_dummy/app/views/dummy_view/show_haml.html.haml +0 -4
  126. data/test/rails6_dummy/app/views/dummy_view/show_slim.html.slim +0 -4
  127. data/test/rails6_dummy/config/boot.rb +0 -3
  128. data/test/rails6_dummy/config/coverband.rb +0 -3
  129. data/test/rails6_dummy/config/coverband_missing_redis.rb +0 -3
  130. data/test/rails6_dummy/config/environment.rb +0 -5
  131. data/test/rails6_dummy/config/routes.rb +0 -7
  132. data/test/rails6_dummy/config/secrets.yml +0 -3
  133. data/test/rails6_dummy/config.ru +0 -4
  134. data/test/rails6_dummy/tmp/.keep +0 -0
  135. /data/test/{rails4_dummy → rails8_dummy}/Rakefile +0 -0
  136. /data/test/{rails4_dummy → rails8_dummy}/app/controllers/dummy_controller.rb +0 -0
  137. /data/test/{rails4_dummy → rails8_dummy}/app/controllers/dummy_view_controller.rb +0 -0
  138. /data/test/{rails4_dummy → rails8_dummy}/app/views/dummy_view/show.html.erb +0 -0
  139. /data/test/{rails4_dummy → rails8_dummy}/app/views/dummy_view/show_haml.html.haml +0 -0
  140. /data/test/{rails4_dummy → rails8_dummy}/app/views/dummy_view/show_slim.html.slim +0 -0
  141. /data/test/{rails6_dummy → rails8_dummy}/config/application.rb +0 -0
  142. /data/test/{rails4_dummy → rails8_dummy}/config/boot.rb +0 -0
  143. /data/test/{rails4_dummy → rails8_dummy}/config/environment.rb +0 -0
  144. /data/test/{rails4_dummy → rails8_dummy}/config/routes.rb +0 -0
  145. /data/test/{rails4_dummy → rails8_dummy}/config/secrets.yml +0 -0
  146. /data/test/{rails4_dummy → rails8_dummy}/config.ru +0 -0
  147. /data/test/{rails4_dummy → rails8_dummy}/tmp/.keep +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3ffdf0c9a4cefbcbc728967f36ed20a90755074864a2fe858859b739e6912bb
4
- data.tar.gz: e853e687820d45bbf414f51efd3a51f996b05f5eff0dcecac95351b076b3300d
3
+ metadata.gz: '01680ffc24d42fce1b45f90fff31a9d190b029af8a83b0a1405ed81d2785bc10'
4
+ data.tar.gz: 04daf91b9d7f64849d217075e71ff00d54cac2e64fd1b5c7fdd7e0b27943b56e
5
5
  SHA512:
6
- metadata.gz: 3f2f69c9de574808771f002af9fc4903fed8ec9af0d52288457759ff21b1c8a3c0e42111a6ea59c8830893fc57acf05e300f8520903dda920a894419710ad386
7
- data.tar.gz: 20073041f076062cefeeeb8bcec74d703086d70c86c6f7b0b2511474f5c0cd2b9cb61510245cca49104dff53a8979249a2b4dae2bfad85b09682c9dd56ce5628
6
+ metadata.gz: 0de107048e072e97c1bded932a59ac9b6be2c6ac94b045118977aae38282a109772b183bed1b7ca99d7867d3fc694f326a53e2e93174bbf372e7f0ba16e8bd13
7
+ data.tar.gz: 57d8e1921056acb7f13e47b02caeb6207e635984a461c1952aafd0dbf4e445519d99ca8b369b60d11c3121b86da6f5f3d3d2a4e6aaf6d68fd2d3a8aa155d14fb
@@ -19,20 +19,39 @@ jobs:
19
19
  # truffleruby,
20
20
  # truffleruby-head,
21
21
  # removing jruby again to flaky
22
- gemfile: [ Gemfile.rails6.0, Gemfile.rails6.1, Gemfile.rails7.0, Gemfile.rails7.1 ]
22
+ gemfile: [ Gemfile.rails7.0, Gemfile.rails7.1, Gemfile.rails7.2, Gemfile.rails8.0 ]
23
23
  # need to add support for multiple gemfiles
24
- ruby: ["2.7", "3.0", "3.1", "3.2", "3.3"]
24
+ ruby: ["3.1", "3.2", "3.3", "3.4", "4.0", "ruby-head"]
25
25
  redis-version: [4, 5, 6, 7]
26
+ exclude:
27
+ # Rails 8 requires ruby 3.2+.
28
+ - gemfile: 'rails_8.0'
29
+ ruby: '3.1'
26
30
  runs-on: ${{ matrix.os }}-latest
31
+ services:
32
+ redis:
33
+ image: redis:${{ matrix.redis-version }}
34
+ ports:
35
+ - 6379:6379
36
+ options: >-
37
+ --health-cmd "redis-cli ping"
38
+ --health-interval 10s
39
+ --health-timeout 5s
40
+ --health-retries 5
27
41
  steps:
28
- - uses: actions/checkout@v4
29
- - uses: supercharge/redis-github-action@1.8.0
30
- with:
31
- redis-version: ${{ matrix.redis-version }}
42
+ - uses: actions/checkout@v6
32
43
  - uses: ruby/setup-ruby@v1
33
44
  with:
34
45
  ruby-version: ${{ matrix.ruby }}
35
46
  bundler-cache: true # runs 'bundle install' and caches installed gems automatically
36
- - run: bundle exec standardrb
37
- - run: bundle exec rake
47
+ - run: bundle exec rake test:all
38
48
  - run: "RUBYOPT='--enable=frozen-string-literal --debug=frozen-string-literal' bundle exec rake"
49
+ starndardrb:
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - uses: actions/checkout@v6
53
+ - uses: ruby/setup-ruby@v1
54
+ with:
55
+ ruby-version: 3.1
56
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
57
+ - run: bundle exec standardrb --format github
data/.gitignore CHANGED
@@ -24,4 +24,6 @@ temp_results
24
24
  .env
25
25
  log/
26
26
  test/unique_files
27
- test/rails5_dummy/tmp
27
+ test/rails7_dummy/tmp
28
+ CLAUDE.md
29
+ .claude/
data/.rubocop.yml CHANGED
@@ -2,4 +2,4 @@ require: standard
2
2
 
3
3
  inherit_gem:
4
4
  standard:
5
- - config/ruby-2.7.yml
5
+ - config/ruby-3.1.yml
data/.standard.yml CHANGED
@@ -1,4 +1,4 @@
1
- ruby_version: 2.7
1
+ ruby_version: 3.1
2
2
  fix: false # default: false
3
3
  parallel: true # default: false
4
4
  format: progress # default: Standard::Formatter
data/Gemfile CHANGED
@@ -4,7 +4,10 @@ source "https://rubygems.org"
4
4
 
5
5
  # Specify your gem's dependencies in coverband.gemspec
6
6
  gemspec
7
- gem "rails", "~>7"
7
+ gem "rails" # latest
8
8
  gem "haml"
9
9
  gem "slim"
10
10
  gem "webrick"
11
+
12
+ # Required for Ruby 3.4+ (extracted from stdlib)
13
+ gem "cgi"
data/Gemfile.rails7.0 CHANGED
@@ -8,3 +8,6 @@ gem 'rails', '~>7.0.0'
8
8
  gem "haml"
9
9
  gem "slim"
10
10
  gem "webrick"
11
+
12
+ # Required for Ruby 3.4+ (extracted from stdlib)
13
+ gem "cgi"
data/Gemfile.rails7.1 CHANGED
@@ -7,4 +7,7 @@ gemspec
7
7
  gem 'rails', '~>7.1.0'
8
8
  gem "haml"
9
9
  gem "slim"
10
- gem "webrick"
10
+ gem "webrick"
11
+
12
+ # Required for Ruby 3.4+ (extracted from stdlib)
13
+ gem "cgi"
@@ -4,7 +4,10 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in coverband.gemspec
6
6
  gemspec
7
- gem 'rails', '~>7'
7
+ gem 'rails', '~>7.2.0'
8
8
  gem "haml"
9
9
  gem "slim"
10
- gem "webrick"
10
+ gem "webrick"
11
+
12
+ # Required for Ruby 3.4+ (extracted from stdlib)
13
+ gem "cgi"
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in coverband.gemspec
6
6
  gemspec
7
- gem "rails", "~>6.0.0"
7
+ gem 'rails', '~>8.0.0'
8
8
  gem "haml"
9
9
  gem "slim"
10
10
  gem "webrick"
11
+
12
+ # Required for Ruby 3.4+ (extracted from stdlib)
13
+ gem "cgi"
data/README.md CHANGED
@@ -116,6 +116,39 @@ The columns in the web UI are as follows:
116
116
  When viewing an individual file, a line of code such as a class or method definition may appear green because it is eager loaded by the application, but still not be hit at all in runtime by actual users.
117
117
 
118
118
  ![example of a file with lines not hit at runtime](https://user-images.githubusercontent.com/96786/63541229-aa98a580-c4eb-11e9-8eb8-c004fe1369db.png)
119
+ #### Coverage first seen and Last activity recorded
120
+ In the context of Coverband, a file is considered relevant for monitoring if it is located within certain specified project paths. Specifically, Coverband monitors all *.rb files located in the following paths:
121
+
122
+ - app/
123
+
124
+ - lib/
125
+
126
+ - config/
127
+
128
+ This applies as long as these files are not included in the list of exclusions defined in "config.ignore".
129
+
130
+ #### Coverage first seen
131
+ This attribute shows the exact date and time when Coverband first detected the file. This detection happens when:
132
+
133
+ - The file is loaded by Ruby (e.g., during application startup in Rails via autoload or require).
134
+
135
+ - The file becomes relevant for monitoring, even if no lines within it have been executed yet.
136
+
137
+ - By default, Coverband resets a file’s coverage data and updates its “Coverage first seen” timestamp whenever the file changes, ensuring the coverage reflects the file’s new state.
138
+
139
+ #### Last activity recorded
140
+ This attribute shows the most recent time when any line in the file was executed at runtime. It specifically reflects runtime execution and does not include the file’s load time.
141
+
142
+ - When any line in the file is executed at runtime (e.g., a method is called, a route is triggered, or a conditional is evaluated), Coverband updates the “Last activity recorded” timestamp.
143
+
144
+ - This only occurs when the file’s lines are actually executed. If a file is loaded but none of its lines are executed, the “Last activity recorded” timestamp will not be updated.
145
+
146
+ - It helps determine if a file is actively being used in the application. If a file has no recent activity, it may be a candidate for review or removal.
147
+
148
+ #### Example
149
+ - If a file has a “Coverage first seen” timestamp but no “Last activity recorded”, this indicates that the file is being loaded but no runtime activity is occurring (e.g., it contains unused methods or classes).
150
+
151
+ - If both attributes are populated and the “Last activity recorded” timestamp is recent, the file is actively used in the application.
119
152
 
120
153
  ### Mounting as a Rack App
121
154
 
@@ -305,12 +338,10 @@ Now that Coverband uses MD5 hashes there should be no reason to manually clear c
305
338
 
306
339
  `rake coverband:clear`
307
340
 
308
- This can also be done through the web if `config.web_enable_clear` is enabled.
309
-
310
- **NOTE**: The previous task does not clear the trackers data (views, routes, translations, etc).
311
- To clear trackers data, run
341
+ This will clear both the coverage and trackers data. It can also be done through the web if `config.web_enable_clear` is enabled.
312
342
 
313
- `rake coverband:clear_tracker`
343
+ To clear only coverage data, run `rake coverband:clear_coverage`.
344
+ To clear only trackers data, run `rake coverband:clear_tracker`.
314
345
 
315
346
  ### Adding Rake Tasks outside of Rails
316
347
 
@@ -375,6 +406,129 @@ A few folks have asked about what size of Redis is needed to run Coverband. I ha
375
406
 
376
407
  # Newer Features
377
408
 
409
+ ### MCP Server for AI Assistants
410
+
411
+ Coverband includes an optional MCP (Model Context Protocol) server that allows AI assistants like Claude to query your production coverage data directly. This enables AI-powered code analysis, dead code detection, and coverage insights.
412
+
413
+ #### Installation
414
+
415
+ Add the MCP gem to your Gemfile:
416
+
417
+ ```ruby
418
+ gem 'mcp'
419
+ ```
420
+
421
+ #### Available Tools
422
+
423
+ The MCP server provides the following tools:
424
+
425
+ | Tool | Description |
426
+ |------|-------------|
427
+ | `get_coverage_summary` | Get overall coverage statistics |
428
+ | `get_file_coverage` | Get detailed coverage for a specific file |
429
+ | `get_uncovered_files` | List files with no coverage data |
430
+ | `get_dead_methods` | Find methods that are never called |
431
+ | `get_view_tracker_data` | Get view/template usage data |
432
+ | `get_route_tracker_data` | Get route usage statistics |
433
+ | `get_translation_tracker_data` | Get translation key usage data |
434
+
435
+ #### Running the MCP Server
436
+
437
+ **Standalone (stdio transport):**
438
+
439
+ ```bash
440
+ bundle exec coverband-mcp
441
+ ```
442
+
443
+ **With a rake task:**
444
+
445
+ ```bash
446
+ bundle exec rake coverband:mcp
447
+ ```
448
+
449
+ **HTTP mode (for remote access):**
450
+
451
+ ```bash
452
+ COVERBAND_MCP_HTTP=true COVERBAND_MCP_PORT=9023 bundle exec rake coverband:mcp
453
+ ```
454
+
455
+ #### Configuring Claude Desktop
456
+
457
+ Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
458
+
459
+ **Option 1: Stdio transport (recommended for local development)**
460
+
461
+ ```json
462
+ {
463
+ "mcpServers": {
464
+ "coverband": {
465
+ "command": "bundle",
466
+ "args": ["exec", "coverband-mcp"],
467
+ "cwd": "/path/to/your/rails/app"
468
+ }
469
+ }
470
+ }
471
+ ```
472
+
473
+ **Option 2: HTTP transport (for remote access or shared servers)**
474
+
475
+ First, start the MCP server in HTTP mode:
476
+
477
+ ```bash
478
+ COVERBAND_MCP_HTTP=true bundle exec rake coverband:mcp
479
+ ```
480
+
481
+ Then configure Claude Desktop to connect via `mcp-remote`:
482
+
483
+ ```json
484
+ {
485
+ "mcpServers": {
486
+ "coverband": {
487
+ "command": "npx",
488
+ "args": ["mcp-remote", "http://localhost:9023"]
489
+ }
490
+ }
491
+ }
492
+ ```
493
+
494
+ #### Configuring Claude Code
495
+
496
+ Add a `.mcp.json` file to your project root:
497
+
498
+ **Option 1: Stdio transport (recommended)**
499
+
500
+ ```json
501
+ {
502
+ "mcpServers": {
503
+ "coverband": {
504
+ "command": "bundle",
505
+ "args": ["exec", "coverband-mcp"]
506
+ }
507
+ }
508
+ }
509
+ ```
510
+
511
+ **Option 2: HTTP transport**
512
+
513
+ ```json
514
+ {
515
+ "mcpServers": {
516
+ "coverband": {
517
+ "command": "npx",
518
+ "args": ["mcp-remote", "http://localhost:9023"]
519
+ }
520
+ }
521
+ }
522
+ ```
523
+
524
+ #### Environment Variables
525
+
526
+ | Variable | Description | Default |
527
+ |----------|-------------|---------|
528
+ | `COVERBAND_MCP_HTTP` | Enable HTTP transport instead of stdio | `false` |
529
+ | `COVERBAND_MCP_PORT` | Port for HTTP server | `9023` |
530
+ | `COVERBAND_REDIS_URL` | Redis URL for coverage data | `localhost:6379` |
531
+
378
532
  ### Dead Method Scanning (ruby 2.6+)
379
533
 
380
534
  Rake task that outputs dead methods based on current coverage data:
@@ -399,14 +553,14 @@ Outputs:
399
553
 
400
554
  # Prerequisites
401
555
 
402
- - Coverband 3.0.X+ requires Ruby 2.3+
556
+ - Ruby 3.1+
403
557
  - Coverband currently requires Redis for production usage
404
558
 
405
559
  ### Ruby and Rails Version Support
406
560
 
407
561
  We will match Heroku & Ruby's support lifetime, supporting the last 3 major Ruby releases. For details see [supported runtimes](https://devcenter.heroku.com/articles/ruby-support#supported-runtimes).
408
562
 
409
- For Rails, we will follow the policy of the [Rails team maintenance policy](https://guides.rubyonrails.org/maintenance_policy.html). We officially support the last two major release versions, while providing minimal support (major bugs / security fixes) for an additional version. This means at the moment we primarily target Rails 6.x, 5.x, and will try to keep current functionality working for Rails 4.x but may release new features that do not work on that target.
563
+ For Rails, we will follow the policy of the [Rails team maintenance policy](https://guides.rubyonrails.org/maintenance_policy.html). We officially support the last two major release versions, while providing minimal support (major bugs / security fixes) for an additional version. At the moment we primarily target Rails 7.0+.
410
564
 
411
565
  ### JRuby Support
412
566
 
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RuboCop::RakeTask.new
8
8
 
9
9
  task default: %i[test]
10
10
 
11
- task "test:all": %i[rubocop test forked_tests benchmarks:memory benchmarks]
11
+ task "test:all": %i[test forked_tests benchmarks:memory benchmarks]
12
12
 
13
13
  task :test
14
14
  require "rake/testtask"
data/agents.md ADDED
@@ -0,0 +1,217 @@
1
+ # AI Agent Guidelines for Coverband Development
2
+
3
+ This document provides guidance for AI coding agents working on the Coverband project. Following these guidelines ensures code quality and consistency.
4
+
5
+ ## Project Overview
6
+
7
+ Coverband is a Ruby gem that provides rack middleware to measure production code usage (LOC runtime usage). The project uses:
8
+ - **Ruby**: >= 3.1
9
+ - **Test Framework**: Minitest (version ~> 5.0)
10
+ - **Code Style**: StandardRB
11
+ - **CI/CD**: GitHub Actions
12
+
13
+ ## Testing Requirements
14
+
15
+ ### Running Tests
16
+
17
+ All code changes MUST pass the test suite before considering work complete. The project has multiple test targets:
18
+
19
+ #### Standard Test Suite
20
+ ```bash
21
+ bundle exec rake test
22
+ ```
23
+ This runs the main integration and unit tests located in:
24
+ - `test/integration/**/*_test.rb`
25
+ - `test/coverband/**/*_test.rb`
26
+
27
+ #### Forked Tests
28
+ ```bash
29
+ bundle exec rake forked_tests
30
+ ```
31
+ Runs tests that require forked processes (Rails integration tests):
32
+ - `test/forked/**/*_test.rb`
33
+
34
+ Note: Forked tests are not supported on JRuby.
35
+
36
+ #### Full Test Suite
37
+ ```bash
38
+ bundle exec rake test:all
39
+ ```
40
+ Runs all tests including benchmarks and memory tests.
41
+
42
+ #### Default Task
43
+ ```bash
44
+ bundle exec rake
45
+ ```
46
+ Equivalent to `bundle exec rake test`
47
+
48
+ ### Test Framework Details
49
+
50
+ - Uses **Minitest** with **Mocha** for mocking
51
+ - Test files follow the pattern `*_test.rb`
52
+ - Rails integration tests use **Capybara** for browser testing
53
+ - Forked tests use `minitest-fork_executor` for parallel execution
54
+
55
+ ### Test Configuration
56
+
57
+ Key test dependencies:
58
+ - `minitest ~> 5.0` (pinned for compatibility with minitest-fork_executor)
59
+ - `mocha` for mocking/stubbing
60
+ - `minitest-stub-const` for constant stubbing
61
+ - `capybara` for integration testing
62
+ - `rack-test` for Rack testing
63
+
64
+ ## Code Style Requirements
65
+
66
+ ### StandardRB
67
+
68
+ All code MUST pass StandardRB linting before considering work complete.
69
+
70
+ ```bash
71
+ bundle exec standardrb --format github
72
+ ```
73
+
74
+ #### Auto-fix Style Issues
75
+ ```bash
76
+ bundle exec standardrb --fix
77
+ ```
78
+
79
+ ### Configuration
80
+
81
+ StandardRB configuration is in `.standard.yml`:
82
+ - Ruby version: 3.1
83
+ - Parallel execution enabled
84
+ - Some rules are disabled for compatibility with older Ruby versions
85
+ - Test files have relaxed rules (see `.standard.yml` for specifics)
86
+
87
+ ### Common Style Requirements
88
+
89
+ 1. **Module Inclusions**: Add an empty line after `extend` or `include` statements
90
+ 2. **Frozen String Literals**: All Ruby files should start with `# frozen_string_literal: true`
91
+ 3. **Line Length**: Follow StandardRB defaults (no manual line length configuration needed)
92
+
93
+ ## AI Agent Workflow
94
+
95
+ When making code changes, follow this workflow:
96
+
97
+ ### 1. Make Code Changes
98
+ Implement the requested feature or bug fix.
99
+
100
+ ### 2. Run Tests
101
+ ```bash
102
+ bundle exec rake test
103
+ ```
104
+
105
+ If working on Rails integration or forked features:
106
+ ```bash
107
+ bundle exec rake test:all
108
+ ```
109
+
110
+ ### 3. Fix Any Test Failures
111
+ - Read test output carefully
112
+ - Fix issues in the code
113
+ - Re-run tests until all pass
114
+
115
+ ### 4. Check Code Style
116
+ ```bash
117
+ bundle exec standardrb --format github
118
+ ```
119
+
120
+ ### 5. Auto-fix Style Issues (if any)
121
+ ```bash
122
+ bundle exec standardrb --fix
123
+ ```
124
+
125
+ ### 6. Verify Everything Passes
126
+ ```bash
127
+ bundle exec rake test
128
+ bundle exec standardrb --format github
129
+ ```
130
+
131
+ ### 7. Only Then Consider Work Complete
132
+ Do NOT mark work as complete or hand back to the user until:
133
+ - ✅ All tests pass
134
+ - ✅ StandardRB reports no violations
135
+
136
+ ## Common Issues and Solutions
137
+
138
+ ### Mocha Configuration
139
+ - Use only Mocha 3.x compatible configuration options
140
+ - Valid options: `stubbing_method_unnecessarily`, `stubbing_non_public_method`
141
+ - Invalid options (removed): `stubbing_method_on_nil`, `stubbing_method_on_non_mock_object`, `stubbing_non_existent_method`
142
+
143
+ ### Rails Constant Checks
144
+ When checking if Rails is defined:
145
+ ```ruby
146
+ # ✅ Correct
147
+ if defined?(Rails) && Rails.respond_to?(:version)
148
+ # ...
149
+ end
150
+
151
+ # ❌ Wrong (doesn't protect against undefined constant)
152
+ if Rails&.respond_to?(:version)
153
+ # ...
154
+ end
155
+ ```
156
+
157
+ ### Minitest Version
158
+ - Must use Minitest ~> 5.0 for compatibility with `minitest-fork_executor`
159
+ - Minitest 6.0+ is not compatible with the fork executor
160
+
161
+ ## CI/CD
162
+
163
+ The project uses GitHub Actions for CI. On every push/PR:
164
+ 1. Tests run against multiple Ruby versions (3.1, 3.2, 3.3, 3.4, ruby-head)
165
+ 2. Tests run against multiple Rails versions (7.0, 7.1, 7.2, 8.0)
166
+ 3. Tests run against multiple Redis versions (4, 5, 6, 7)
167
+ 4. StandardRB runs separately to check code style
168
+
169
+ Your local testing should match CI requirements:
170
+ - All tests must pass
171
+ - StandardRB must report no violations
172
+
173
+ ## Additional Notes
174
+
175
+ - The project uses Redis as the default storage backend
176
+ - Rails 8.0 requires Ruby 3.2+
177
+ - Test coverage data is stored in `/tmp` during tests
178
+ - Use `test_helper.rb` for common test setup
179
+ - Use `rails_test_helper.rb` for Rails-specific test setup
180
+
181
+ ## Example Complete Workflow
182
+
183
+ ```bash
184
+ # 1. Make changes to code
185
+ vim lib/coverband/some_file.rb
186
+
187
+ # 2. Run tests
188
+ bundle exec rake test
189
+
190
+ # 3. Fix any failures, re-run until passing
191
+ bundle exec rake test
192
+
193
+ # 4. Check style
194
+ bundle exec standardrb --format github
195
+
196
+ # 5. Auto-fix any style issues
197
+ bundle exec standardrb --fix
198
+
199
+ # 6. Final verification
200
+ bundle exec rake test
201
+ bundle exec standardrb --format github
202
+
203
+ # 7. All green? Work is complete! ✅
204
+ ```
205
+
206
+ ## Quick Reference
207
+
208
+ | Command | Purpose |
209
+ |---------|---------|
210
+ | `bundle exec rake` | Run main test suite (default) |
211
+ | `bundle exec rake test` | Run main test suite |
212
+ | `bundle exec rake forked_tests` | Run forked/Rails integration tests |
213
+ | `bundle exec rake test:all` | Run all tests including benchmarks |
214
+ | `bundle exec standardrb --format github` | Check code style |
215
+ | `bundle exec standardrb --fix` | Auto-fix style issues |
216
+
217
+ Remember: **Tests and style checks must pass before work is considered complete!**
data/bin/coverband-mcp ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "coverband/mcp"
6
+
7
+ # Ensure Coverband is configured
8
+ Coverband.configure unless Coverband.configured?
9
+
10
+ # Security check and warning
11
+ unless Coverband.configuration.mcp_enabled?
12
+ puts "❌ ERROR: MCP is not enabled for security reasons."
13
+ puts "To enable MCP access, configure Coverband with:"
14
+ puts
15
+ puts "Coverband.configure do |config|"
16
+ puts " config.mcp_enabled = true"
17
+ puts " config.mcp_password = 'your-secure-password' # Recommended"
18
+ puts " config.mcp_allowed_environments = %w[development staging production] # As needed"
19
+ puts "end"
20
+ puts
21
+ puts "Or set environment variables:"
22
+ puts " COVERBAND_MCP_PASSWORD=your-secure-password"
23
+ puts
24
+ puts "Current environment: #{(defined?(Rails) && Rails.respond_to?(:env) && Rails.env) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"}"
25
+ exit 1
26
+ end
27
+
28
+ # Display security status
29
+ puts "🔐 SECURITY STATUS:"
30
+ if Coverband.configuration.mcp_password
31
+ puts " ✅ Authentication: Enabled (password protected)"
32
+ else
33
+ puts " ⚠️ Authentication: DISABLED - Consider setting mcp_password for production use"
34
+ end
35
+ env = (defined?(Rails) && Rails.respond_to?(:env) && Rails.env) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
36
+ puts " 📍 Environment: #{env}"
37
+ puts " 🌍 Allowed environments: #{Coverband.configuration.mcp_allowed_environments.join(", ")}"
38
+ puts
39
+
40
+ # Start the MCP server with stdio transport
41
+ server = Coverband::MCP::Server.new
42
+ server.run_stdio