Module: RSpecTracer::CLI::Doctor Private
- Defined in:
- lib/rspec_tracer/cli/doctor.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
‘rspec-tracer doctor` — diagnose config + environment. Reports Ruby + rspec-tracer versions, project root resolution, cache / coverage / report directory state, and SimpleCov / Rails presence. Exits 0 on healthy diagnosis, 1 if any check fails.
Constant Summary collapse
- REMOTE_CACHE_PROBES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
When remote_cache is configured, verify the backend is reachable from doctor’s vantage point so the user catches misconfig (typo’d S3 path / unreachable Redis URL / unwritable local-fs dir) BEFORE the next CI run fails. Best-effort: never FAIL the gate, just surface a WARN/INFO line.
{ s3: ->(opts) { remote_cache_s3_check(opts) }, local_fs: ->(opts) { remote_cache_local_fs_check(opts) }, redis: ->(opts) { remote_cache_redis_check(opts) } }.freeze
Class Method Summary collapse
-
.ar_schema_enabled? ⇒ Boolean
private
Internal helper for the tracer pipeline.
-
.ar_schema_narrow_attribution_check ⇒ Object
private
Surface the narrow-attribution precondition at diagnostic time.
-
.cache_path_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.cache_schema_version_check ⇒ Object
private
Surface a 1.x->2.0 cache mismatch BEFORE the user runs rspec and watches everything re-run mysteriously.
-
.coverage_path_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.git_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.path_check(label, path) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.print_help(stdout) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.project_root_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.rails_check ⇒ Object
private
See Doctor.simplecov_check for the doctor-runs-in-its-own- process rationale.
-
.rails_loaded? ⇒ Boolean
private
Internal helper for the tracer pipeline.
-
.remote_cache_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.remote_cache_entry ⇒ Object
private
Internal helper for the tracer pipeline.
-
.remote_cache_local_fs_check(opts) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.remote_cache_redis_check(opts) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.remote_cache_s3_check(opts) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.report_path_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.ruby_version_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.run(args, stdout: $stdout, stderr: $stderr) ⇒ Integer
private
Exit status (0 = healthy, 1 = any check FAILed; warnings keep status 0).
-
.simplecov_check ⇒ Object
private
‘bundle exec rspec-tracer doctor` runs in its own process via the gem’s ‘bin/rspec-tracer` binstub, NOT inside the user’s rspec boot — so app code never loads here and a bare ‘defined?(::SimpleCov)` check would falsely report “not loaded” on projects that DO have SimpleCov in their Gemfile.
-
.tracer_version_check ⇒ Object
private
Internal helper for the tracer pipeline.
-
.transactional_fixtures_default? ⇒ Boolean
private
Internal helper for the tracer pipeline.
Class Method Details
.ar_schema_enabled? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
258 259 260 261 262 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 258 def self.ar_schema_enabled? return false unless RSpecTracer.respond_to?(:track_ar_schema_notifications?) RSpecTracer.track_ar_schema_notifications? end |
.ar_schema_narrow_attribution_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Surface the narrow-attribution precondition at diagnostic time. When ‘track_ar_schema_notifications` is enabled AND Rails is loaded AND the rspec-rails default `use_transactional_fixtures
true` is in effect, per-example BEGIN/COMMIT fires
‘sql.active_record` inside the rspec-tracer bucket and attribution silently widens. Same shape as the boot-time warn in RSpecTracer.start, surfaced here so users running `rspec-tracer doctor` see the issue without having to boot a full rspec run first.
243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 243 def self.ar_schema_narrow_attribution_check return 'INFO AR schema: track_ar_schema_notifications not enabled' unless ar_schema_enabled? return 'INFO AR schema: Rails not loaded' unless rails_loaded? if transactional_fixtures_default? 'WARN AR schema: track_ar_schema_notifications + use_transactional_fixtures=true ' \ 'silently widens to whole-suite-on-schema-change. See README ' \ 'section "Narrow AR schema attribution".' else 'OK AR schema: narrow attribution preconditions look good' end end |
.cache_path_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
76 77 78 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 76 def self.cache_path_check path_check('cache_path:', RSpecTracer.cache_path) end |
.cache_schema_version_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Surface a 1.x->2.0 cache mismatch BEFORE the user runs rspec and watches everything re-run mysteriously. Reads the cached ‘last_run.json` (if any) and compares its `schema_version` against the gem’s ‘Schema::CURRENT`. Three outcomes: no cache yet (INFO), match (OK), or mismatch (WARN with the cold-run note). Never FAIL - schema mismatches are the documented cold-run path, not a hard error.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 148 def self.cache_schema_version_check require 'rspec_tracer/storage/schema' require 'json' cache_path = RSpecTracer.cache_path last_run_path = File.join(cache_path.to_s, 'last_run.json') unless File.file?(last_run_path) return 'INFO schema: no cache yet (next rspec run is cold; expected on first install)' end manifest = JSON.parse(File.read(last_run_path, encoding: 'UTF-8')) stored = manifest['schema_version'] current = RSpecTracer::Storage::Schema::CURRENT if stored == current "OK schema: v#{current} (matches gem)" else "WARN schema: stored v#{stored.inspect} != gem v#{current} " \ '(next rspec run is a cold run; expected on 1.x->2.0 upgrade)' end rescue StandardError => e "WARN schema: could not read cache manifest: #{e.class}: #{e.}" end |
.coverage_path_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
82 83 84 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 82 def self.coverage_path_check path_check('coverage_path:', RSpecTracer.coverage_path) end |
.git_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
104 105 106 107 108 109 110 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 104 def self.git_check if system('git', 'rev-parse', 'HEAD', out: File::NULL, err: File::NULL) 'OK git: HEAD reachable (remote_cache will work)' else 'WARN git: not in a git repo (remote_cache will degrade gracefully)' end end |
.path_check(label, path) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
94 95 96 97 98 99 100 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 94 def self.path_check(label, path) return "FAIL #{label} <missing>" if path.nil? || path.empty? return "FAIL #{label} #{path} (does not exist)" unless File.directory?(path) return "FAIL #{label} #{path} (not writable)" unless File.writable?(path) "OK #{label} #{path}" end |
.print_help(stdout) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
46 47 48 49 50 51 52 53 54 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 46 def self.print_help(stdout) stdout.puts <<~HELP Usage: rspec-tracer doctor Diagnose rspec-tracer config and environment. Prints a checklist of versions, paths, and integrations; exits 0 if all checks pass. HELP 0 end |
.project_root_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
70 71 72 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 70 def self.project_root_check "OK root: #{RSpecTracer.root}" end |
.rails_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
See simplecov_check for the doctor-runs-in-its-own- process rationale. Same three-state probe shape: loaded in this process / installed but not loaded / not installed.
132 133 134 135 136 137 138 139 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 132 def self.rails_check return "OK Rails: #{::Rails::VERSION::STRING}" if defined?(::Rails::VERSION) && !::Rails::VERSION.nil? spec = Gem.loaded_specs['rails'] return "INFO Rails: installed (v#{spec.version}; not loaded in doctor's process)" if spec 'INFO Rails: not installed (this is fine for non-Rails projects)' end |
.rails_loaded? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
266 267 268 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 266 def self.rails_loaded? defined?(::Rails::VERSION) && !::Rails::VERSION.nil? end |
.remote_cache_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
184 185 186 187 188 189 190 191 192 193 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 184 def self.remote_cache_check entry = remote_cache_entry return 'INFO remote_cache: not configured (skip)' unless entry backend, opts = entry probe = REMOTE_CACHE_PROBES[backend] return "INFO remote_cache: custom backend #{backend.inspect} (skipping reachability probe)" if probe.nil? instance_exec(opts, &probe) end |
.remote_cache_entry ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
197 198 199 200 201 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 197 def self.remote_cache_entry return nil unless RSpecTracer.respond_to?(:remote_cache_backend_entry) RSpecTracer.remote_cache_backend_entry end |
.remote_cache_local_fs_check(opts) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
215 216 217 218 219 220 221 222 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 215 def self.remote_cache_local_fs_check(opts) path = opts[:path] || opts['path'] return 'WARN remote_cache: :local_fs configured without :path' if path.nil? || path.empty? return "WARN remote_cache: :local_fs path #{path} does not exist" unless File.directory?(path) return "WARN remote_cache: :local_fs path #{path} not writable" unless File.writable?(path) "OK remote_cache: :local_fs path=#{path}" end |
.remote_cache_redis_check(opts) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
226 227 228 229 230 231 232 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 226 def self.remote_cache_redis_check(opts) url = opts[:url] || opts['url'] || ENV.fetch('RSPEC_TRACER_REMOTE_CACHE_URI', nil) return 'WARN remote_cache: :redis configured without :url' if url.nil? || url.empty? "OK remote_cache: :redis url=#{url} " \ '(reachability not probed locally; verified end-to-end on next CI run)' end |
.remote_cache_s3_check(opts) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
205 206 207 208 209 210 211 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 205 def self.remote_cache_s3_check(opts) bucket = opts[:bucket] || opts['bucket'] return 'WARN remote_cache: :s3 configured without :bucket' if bucket.nil? || bucket.empty? "OK remote_cache: :s3 bucket=#{bucket} " \ '(reachability not probed locally; verified end-to-end on next CI run)' end |
.report_path_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
88 89 90 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 88 def self.report_path_check path_check('report_path:', RSpecTracer.report_path) end |
.ruby_version_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
58 59 60 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 58 def self.ruby_version_check "OK ruby: #{RUBY_DESCRIPTION}" end |
.run(args, stdout: $stdout, stderr: $stderr) ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns exit status (0 = healthy, 1 = any check FAILed; warnings keep status 0).
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 17 def self.run(args, stdout: $stdout, stderr: $stderr) return print_help(stdout) if args.include?('-h') || args.include?('--help') require 'rspec_tracer/load_config' checks = [ ruby_version_check, tracer_version_check, project_root_check, cache_path_check, coverage_path_check, report_path_check, git_check, simplecov_check, rails_check, cache_schema_version_check, remote_cache_check, ar_schema_narrow_attribution_check ] checks.each { |line| stdout.puts line } ok = checks.none? { |line| line.start_with?('FAIL') } ok ? 0 : 1 rescue StandardError => e stderr.puts "doctor: #{e.class}: #{e.}" 1 end |
.simplecov_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
‘bundle exec rspec-tracer doctor` runs in its own process via the gem’s ‘bin/rspec-tracer` binstub, NOT inside the user’s rspec boot — so app code never loads here and a bare ‘defined?(::SimpleCov)` check would falsely report “not loaded” on projects that DO have SimpleCov in their Gemfile. Probe `Gem.loaded_specs` first to surface the “installed but not loaded in doctor’s process” case separately from “actually not installed.”
120 121 122 123 124 125 126 127 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 120 def self.simplecov_check return 'OK SimpleCov: loaded (interop active)' if defined?(::SimpleCov) spec = Gem.loaded_specs['simplecov'] return "INFO SimpleCov: installed (v#{spec.version}; not loaded in doctor's process)" if spec 'INFO SimpleCov: not installed (this is fine; SimpleCov is optional)' end |
.tracer_version_check ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
64 65 66 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 64 def self.tracer_version_check "OK rspec-tracer: #{RSpecTracer::VERSION}" end |
.transactional_fixtures_default? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Internal helper for the tracer pipeline.
272 273 274 275 276 277 278 279 280 281 |
# File 'lib/rspec_tracer/cli/doctor.rb', line 272 def self.transactional_fixtures_default? return false unless defined?(::RSpec) && ::RSpec.respond_to?(:configuration) cfg = ::RSpec.configuration return false unless cfg.respond_to?(:use_transactional_fixtures) cfg.use_transactional_fixtures != false rescue StandardError false end |