Module: RSpecTracer::CLI::Explain Private
- Defined in:
- lib/rspec_tracer/cli/explain.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 explain <example>` — show why a given example is scheduled to run or skip on the next rspec invocation. Reads the most recent run’s JSON files (all_examples.json + dependency.json + failed_examples.json + flaky_examples.json) to surface the dependency set, last-run status, and the run-decision reason.
Class Method Summary collapse
-
.find_example(all_examples, query) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.first_non_nil(meta, *keys) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.format_lines(meta) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.no_match(query, all_examples, stderr) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.print_dependency_summary(stdout, meta, run_dir) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.print_explanation(stdout, meta, run_dir) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.print_help(stdout) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.read_json(path) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.resolve_run_dir(cache_path, stderr) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.run(args, stdout: $stdout, stderr: $stderr) ⇒ Integer
private
Exit status (0 = explanation printed, 1 = example not found / cache missing).
Class Method Details
.find_example(all_examples, query) ⇒ 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.
92 93 94 95 96 97 98 99 100 |
# File 'lib/rspec_tracer/cli/explain.rb', line 92 def self.find_example(all_examples, query) return all_examples[query] if all_examples.key?(query) all_examples.find do |id, | = {} unless .is_a?(::Hash) desc = ['full_description'] || ['description'] || '' id.include?(query) || desc.include?(query) end&.last end |
.first_non_nil(meta, *keys) ⇒ 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.
128 129 130 131 |
# File 'lib/rspec_tracer/cli/explain.rb', line 128 def self.first_non_nil(, *keys) keys.each { |k| return [k] unless [k].nil? } nil end |
.format_lines(meta) ⇒ 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.
112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/rspec_tracer/cli/explain.rb', line 112 def self.format_lines() id = first_non_nil(, 'example_id', 'id') || '<unknown>' file = first_non_nil(, 'rerun_file_name', 'file_name') line = first_non_nil(, 'rerun_line_number', 'line_number') status = .dig('execution_result', 'status') || ['status'] || 'unknown' [ "id: #{id}", "description: #{first_non_nil(, 'full_description', 'description')}", "location: #{file}:#{line}", "last status: #{status}", "run reason: #{['run_reason'] || '<not recorded>'}" ] end |
.no_match(query, all_examples, stderr) ⇒ 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.
62 63 64 65 66 |
# File 'lib/rspec_tracer/cli/explain.rb', line 62 def self.no_match(query, all_examples, stderr) stderr.puts "explain: no example matching #{query.inspect}" stderr.puts " cache has #{all_examples.size} examples; pass an example_id or substring of description" 1 end |
.print_dependency_summary(stdout, meta, run_dir) ⇒ 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.
135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/rspec_tracer/cli/explain.rb', line 135 def self.print_dependency_summary(stdout, , run_dir) deps_path = File.join(run_dir, 'dependency.json') return unless File.file?(deps_path) deps = read_json(deps_path) id = ['example_id'] || ['id'] files = Array(deps[id]) stdout.puts "dependencies: #{files.size} files tracked" files.first(10).each { |f| stdout.puts " - #{f}" } stdout.puts " ... (#{files.size - 10} more)" if files.size > 10 end |
.print_explanation(stdout, meta, run_dir) ⇒ 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 |
# File 'lib/rspec_tracer/cli/explain.rb', line 104 def self.print_explanation(stdout, , run_dir) = {} unless .is_a?(::Hash) format_lines().each { |line| stdout.puts line } print_dependency_summary(stdout, , run_dir) 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.
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/rspec_tracer/cli/explain.rb', line 70 def self.print_help(stdout) stdout.puts <<~HELP Usage: rspec-tracer explain <example_id_or_substring> Show why an example is scheduled to run or skip. Matches against example_id exactly first, then falls back to a substring match on the example's full_description. Requires a prior rspec run. HELP 0 end |
.read_json(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.
83 84 85 86 87 88 |
# File 'lib/rspec_tracer/cli/explain.rb', line 83 def self.read_json(path) return {} unless File.file?(path) parsed = JSON.parse(File.read(path, encoding: 'UTF-8')) parsed.is_a?(Hash) ? parsed : {} end |
.resolve_run_dir(cache_path, stderr) ⇒ 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.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/rspec_tracer/cli/explain.rb', line 43 def self.resolve_run_dir(cache_path, stderr) last_run_path = File.join(cache_path, 'last_run.json') unless File.file?(last_run_path) stderr.puts "explain: no last_run.json at #{cache_path} — run rspec first" return nil end run_id = JSON.parse(File.read(last_run_path, encoding: 'UTF-8'))['run_id'] run_dir = File.join(cache_path, run_id.to_s) unless File.directory?(run_dir) stderr.puts "explain: run_id #{run_id} directory missing at #{run_dir}" return nil end run_dir 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 = explanation printed, 1 = example not found / cache missing).
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/rspec_tracer/cli/explain.rb', line 21 def self.run(args, stdout: $stdout, stderr: $stderr) return print_help(stdout) if args.empty? || args.include?('-h') || args.include?('--help') require 'rspec_tracer/load_config' cache_path = RSpecTracer.cache_path run_dir = resolve_run_dir(cache_path, stderr) return 1 if run_dir.nil? all_examples = read_json(File.join(run_dir, 'all_examples.json')) match = find_example(all_examples, args.first) return no_match(args.first, all_examples, stderr) if match.nil? print_explanation(stdout, match, run_dir) 0 rescue StandardError => e stderr.puts "explain: #{e.class}: #{e.}" 1 end |