rspec-tracer 0.9.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,8 +22,6 @@ module RSpecTracer
22
22
  @reporter = RSpecTracer::Reporter.new
23
23
  @filtered_examples = {}
24
24
 
25
- return if @cache.run_id.nil?
26
-
27
25
  @cache.load_cache_for_run
28
26
  filter_examples_to_run
29
27
  end
@@ -72,7 +70,6 @@ module RSpecTracer
72
70
  @reporter.register_deleted_examples(@cache.all_examples)
73
71
  end
74
72
 
75
- # rubocop:disable Metrics/AbcSize
76
73
  def generate_missed_coverage
77
74
  missed_coverage = Hash.new do |files_coverage, file_path|
78
75
  files_coverage[file_path] = Hash.new do |strength, line_number|
@@ -99,7 +96,6 @@ module RSpecTracer
99
96
 
100
97
  missed_coverage
101
98
  end
102
- # rubocop:enable Metrics/AbcSize
103
99
 
104
100
  def register_dependency(examples_coverage)
105
101
  filtered_files = Set.new
@@ -145,25 +141,6 @@ module RSpecTracer
145
141
  @reporter.register_examples_coverage(examples_coverage)
146
142
  end
147
143
 
148
- def generate_report
149
- @reporter.generate_last_run_report
150
- generate_examples_status_report
151
-
152
- %i[all_files all_examples dependency examples_coverage reverse_dependency].each do |report_type|
153
- starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
154
-
155
- send("generate_#{report_type}_report")
156
-
157
- ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
158
- elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)
159
-
160
- puts "RSpec tracer generated #{report_type.to_s.tr('_', ' ')} report (took #{elpased})" if RSpecTracer.verbose?
161
- end
162
-
163
- @reporter.write_reports
164
- @reporter.print_duplicate_examples
165
- end
166
-
167
144
  def non_zero_exit_code?
168
145
  !@reporter.duplicate_examples.empty? &&
169
146
  ENV.fetch('RSPEC_TRACER_FAIL_ON_DUPLICATES', 'true') == 'true'
@@ -183,9 +160,9 @@ module RSpecTracer
183
160
  filter_by_files_changed
184
161
 
185
162
  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
186
- elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)
163
+ elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
187
164
 
188
- puts "RSpec tracer processed cache (took #{elpased})" if RSpecTracer.verbose?
165
+ puts "RSpec tracer processed cache (took #{elapsed})" if RSpecTracer.verbose?
189
166
  end
190
167
 
191
168
  def filter_by_example_status
@@ -311,92 +288,5 @@ module RSpecTracer
311
288
 
312
289
  true
313
290
  end
314
-
315
- def generate_examples_status_report
316
- starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
317
-
318
- generate_flaky_examples_report
319
- generate_failed_examples_report
320
- generate_pending_examples_report
321
-
322
- ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
323
- elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)
324
-
325
- puts "RSpec tracer generated flaky, failed, and pending examples report (took #{elpased})" if RSpecTracer.verbose?
326
- end
327
-
328
- def generate_all_files_report
329
- @cache.all_files.each_pair do |file_name, data|
330
- next if @reporter.all_files.key?(file_name) ||
331
- @reporter.file_deleted?(file_name)
332
-
333
- @reporter.all_files[file_name] = data
334
- end
335
- end
336
-
337
- def generate_all_examples_report
338
- @cache.all_examples.each_pair do |example_id, data|
339
- next if @reporter.all_examples.key?(example_id) ||
340
- @reporter.example_deleted?(example_id)
341
-
342
- @reporter.all_examples[example_id] = data
343
- end
344
- end
345
-
346
- def generate_flaky_examples_report
347
- @reporter.possibly_flaky_examples.each do |example_id|
348
- next if @reporter.example_deleted?(example_id)
349
- next unless @cache.flaky_examples.include?(example_id) ||
350
- @reporter.example_passed?(example_id)
351
-
352
- @reporter.register_flaky_example(example_id)
353
- end
354
- end
355
-
356
- def generate_failed_examples_report
357
- @cache.failed_examples.each do |example_id|
358
- next if @reporter.example_deleted?(example_id) ||
359
- @reporter.all_examples.key?(example_id)
360
-
361
- @reporter.register_failed_example(example_id)
362
- end
363
- end
364
-
365
- def generate_pending_examples_report
366
- @cache.pending_examples.each do |example_id|
367
- next if @reporter.example_deleted?(example_id) ||
368
- @reporter.all_examples.key?(example_id)
369
-
370
- @reporter.register_pending_example(example_id)
371
- end
372
- end
373
-
374
- def generate_dependency_report
375
- @cache.dependency.each_pair do |example_id, data|
376
- next if @reporter.dependency.key?(example_id) ||
377
- @reporter.example_deleted?(example_id)
378
-
379
- @reporter.dependency[example_id] = data.reject do |file_name|
380
- @reporter.file_deleted?(file_name)
381
- end
382
- end
383
-
384
- @reporter.dependency.transform_values!(&:to_a)
385
- end
386
-
387
- def generate_examples_coverage_report
388
- @cache.cached_examples_coverage.each_pair do |example_id, data|
389
- next if @reporter.examples_coverage.key?(example_id) ||
390
- @reporter.example_deleted?(example_id)
391
-
392
- @reporter.examples_coverage[example_id] = data.reject do |file_name|
393
- @reporter.file_deleted?(file_name)
394
- end
395
- end
396
- end
397
-
398
- def generate_reverse_dependency_report
399
- @reporter.generate_reverse_dependency_report
400
- end
401
291
  end
402
292
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RSpecTracer
4
- VERSION = '0.9.3'
4
+ VERSION = '1.0.0'
5
5
  end
data/lib/rspec_tracer.rb CHANGED
@@ -13,11 +13,16 @@ require 'set'
13
13
  require_relative 'rspec_tracer/configuration'
14
14
  RSpecTracer.extend RSpecTracer::Configuration
15
15
 
16
+ require_relative 'rspec_tracer/coverage_merger'
16
17
  require_relative 'rspec_tracer/coverage_reporter'
18
+ require_relative 'rspec_tracer/coverage_writer'
17
19
  require_relative 'rspec_tracer/defaults'
18
20
  require_relative 'rspec_tracer/example'
19
21
  require_relative 'rspec_tracer/html_reporter/reporter'
20
22
  require_relative 'rspec_tracer/remote_cache/cache'
23
+ require_relative 'rspec_tracer/report_generator'
24
+ require_relative 'rspec_tracer/report_merger'
25
+ require_relative 'rspec_tracer/report_writer'
21
26
  require_relative 'rspec_tracer/rspec_reporter'
22
27
  require_relative 'rspec_tracer/rspec_runner'
23
28
  require_relative 'rspec_tracer/ruby_coverage'
@@ -34,10 +39,12 @@ module RSpecTracer
34
39
  RSpecTracer.running = false
35
40
  RSpecTracer.pid = Process.pid
36
41
 
37
- puts 'Started RSpec tracer'
42
+ return if RUBY_ENGINE == 'jruby' && !valid_jruby_opts?
38
43
 
39
- configure(&block) if block
44
+ puts "Started RSpec tracer (pid: #{RSpecTracer.pid})"
40
45
 
46
+ parallel_tests_setup
47
+ configure(&block) if block
41
48
  initial_setup
42
49
  end
43
50
 
@@ -80,6 +87,8 @@ module RSpecTracer
80
87
 
81
88
  ::Kernel.exit(1) if runner.non_zero_exit_code?
82
89
  ensure
90
+ FileUtils.rm_f(RSpecTracer.parallel_tests_lock_file) if parallel_tests_last_process?
91
+
83
92
  RSpecTracer.running = false
84
93
  end
85
94
 
@@ -109,6 +118,14 @@ module RSpecTracer
109
118
  return @coverage_reporter if defined?(@coverage_reporter)
110
119
  end
111
120
 
121
+ def coverage_merger
122
+ return @coverage_merger if defined?(@coverage_merger)
123
+ end
124
+
125
+ def report_merger
126
+ return @report_merger if defined?(@report_merger)
127
+ end
128
+
112
129
  def trace_point
113
130
  return @trace_point if defined?(@trace_point)
114
131
  end
@@ -125,8 +142,28 @@ module RSpecTracer
125
142
  return @simplecov if defined?(@simplecov)
126
143
  end
127
144
 
145
+ def parallel_tests?
146
+ return @parallel_tests if defined?(@parallel_tests)
147
+ end
148
+
128
149
  private
129
150
 
151
+ def valid_jruby_opts?
152
+ require 'jruby'
153
+
154
+ return true if Java::OrgJruby::RubyInstanceConfig.FULL_TRACE_ENABLED &&
155
+ JRuby.runtime.object_space_enabled?
156
+
157
+ puts <<-WARN.strip.gsub(/\s+/, ' ')
158
+ RSpec Tracer is not running as it requires debug and object space enabled. Use
159
+ command line options "--debug" and "-X+O" or set the "debug.fullTrace=true" and
160
+ "objectspace.enabled=true" options in your .jrubyrc file. You can also use
161
+ JRUBY_OPTS="--debug -X+O".
162
+ WARN
163
+
164
+ false
165
+ end
166
+
130
167
  def initial_setup
131
168
  unless setup_rspec
132
169
  puts 'Could not find a running RSpec process'
@@ -141,6 +178,36 @@ module RSpecTracer
141
178
  @coverage_reporter = RSpecTracer::CoverageReporter.new
142
179
  end
143
180
 
181
+ def parallel_tests_setup
182
+ @parallel_tests = !(ENV['TEST_ENV_NUMBER'] && ENV['PARALLEL_TEST_GROUPS']).nil?
183
+
184
+ return unless parallel_tests?
185
+
186
+ require 'parallel_tests' unless defined?(ParallelTests)
187
+
188
+ @coverage_merger = RSpecTracer::CoverageMerger.new
189
+ @report_merger = RSpecTracer::ReportMerger.new
190
+ rescue LoadError => e
191
+ puts "Failed to load parallel tests (Error: #{e.message})"
192
+ ensure
193
+ track_parallel_tests_test_env_number
194
+ end
195
+
196
+ def track_parallel_tests_test_env_number
197
+ return unless parallel_tests?
198
+
199
+ File.open(RSpecTracer.parallel_tests_lock_file, File::RDWR | File::CREAT, 0o644) do |f|
200
+ f.flock(File::LOCK_EX)
201
+
202
+ test_num = [f.read.to_i, ENV['TEST_ENV_NUMBER'].to_i].max
203
+
204
+ f.rewind
205
+ f.write("#{test_num}\n")
206
+ f.flush
207
+ f.truncate(f.pos)
208
+ end
209
+ end
210
+
144
211
  def setup_rspec
145
212
  runners = ObjectSpace.each_object(::RSpec::Core::Runner) do |runner|
146
213
  runner_clazz = runner.singleton_class
@@ -184,15 +251,23 @@ module RSpecTracer
184
251
  end
185
252
 
186
253
  simplecov? ? run_simplecov_exit_task : run_coverage_exit_task
254
+
255
+ run_parallel_tests_exit_tasks
187
256
  end
188
257
 
189
258
  def generate_reports
190
- puts 'RSpec tracer is generating reports'
259
+ puts "RSpec tracer is generating reports (pid: #{RSpecTracer.pid})"
191
260
 
192
261
  process_dependency
193
262
  process_coverage
194
- runner.generate_report
195
- RSpecTracer::HTMLReporter::Reporter.new.generate_report
263
+
264
+ RSpecTracer::ReportGenerator.new(runner.reporter, runner.cache).generate_report
265
+
266
+ report_writer = RSpecTracer::ReportWriter.new(RSpecTracer.cache_path, runner.reporter)
267
+ report_writer.write_report
268
+ report_writer.print_duplicate_examples
269
+
270
+ RSpecTracer::HTMLReporter::Reporter.new(RSpecTracer.report_path, runner.reporter).generate_report
196
271
  end
197
272
 
198
273
  def process_dependency
@@ -204,9 +279,9 @@ module RSpecTracer
204
279
  runner.register_untraced_dependency(@traced_files)
205
280
 
206
281
  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
207
- elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)
282
+ elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
208
283
 
209
- puts "RSpec tracer processed dependency (took #{elpased})" if RSpecTracer.verbose?
284
+ puts "RSpec tracer processed dependency (took #{elapsed})" if RSpecTracer.verbose?
210
285
  end
211
286
 
212
287
  def process_coverage
@@ -217,9 +292,9 @@ module RSpecTracer
217
292
  runner.register_examples_coverage(coverage_reporter.examples_coverage)
218
293
 
219
294
  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
220
- elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)
295
+ elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
221
296
 
222
- puts "RSpec tracer processed coverage (took #{elpased})" if RSpecTracer.verbose?
297
+ puts "RSpec tracer processed coverage (took #{elapsed})" if RSpecTracer.verbose?
223
298
  end
224
299
 
225
300
  def run_simplecov_exit_task
@@ -239,34 +314,129 @@ module RSpecTracer
239
314
  coverage_reporter.generate_final_coverage
240
315
 
241
316
  file_name = File.join(RSpecTracer.coverage_path, 'coverage.json')
317
+ coverage_writer = RSpecTracer::CoverageWriter.new(file_name, coverage_reporter)
318
+
319
+ coverage_writer.write_report
320
+
321
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
322
+
323
+ coverage_writer.print_stats(ending - starting)
324
+ end
325
+
326
+ def run_parallel_tests_exit_tasks
327
+ return unless parallel_tests_executed?
328
+
329
+ merge_parallel_tests_reports
330
+ write_parallel_tests_merged_report
331
+ merge_parallel_tests_coverage_reports
332
+ write_parallel_tests_coverage_report
333
+ purge_parallel_tests_reports
334
+ end
335
+
336
+ def merge_parallel_tests_reports
337
+ return unless parallel_tests_executed?
338
+
339
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
340
+ reports_dir = []
242
341
 
243
- write_coverage_report(file_name)
342
+ 1.upto(ENV['PARALLEL_TEST_GROUPS'].to_i) do |test_num|
343
+ cache_path = File.dirname(RSpecTracer.cache_path)
344
+ cache_dir = File.join(cache_path, "parallel_tests_#{test_num}")
345
+
346
+ next unless File.directory?(cache_dir)
347
+
348
+ run_id = JSON.parse(File.read(File.join(cache_dir, 'last_run.json')))['run_id']
349
+
350
+ reports_dir << File.join(cache_dir, run_id)
351
+ end
352
+
353
+ report_merger.merge(reports_dir)
244
354
 
245
355
  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
246
- elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)
356
+ elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
247
357
 
248
- print_coverage_stats(file_name, elpased)
358
+ puts "\nRSpec tracer merged parallel tests reports (took #{elapsed})"
249
359
  end
250
360
 
251
- def write_coverage_report(file_name)
252
- report = {
253
- RSpecTracer: {
254
- coverage: coverage_reporter.coverage,
255
- timestamp: Time.now.utc.to_i
256
- }
257
- }
361
+ def write_parallel_tests_merged_report
362
+ return unless parallel_tests_executed?
363
+
364
+ report_dir = File.dirname(RSpecTracer.cache_path)
258
365
 
259
- File.write(file_name, JSON.pretty_generate(report))
366
+ RSpecTracer::ReportWriter.new(report_dir, report_merger).write_report
367
+
368
+ report_dir = File.dirname(RSpecTracer.report_path)
369
+
370
+ RSpecTracer::HTMLReporter::Reporter.new(report_dir, report_merger).generate_report
260
371
  end
261
372
 
262
- def print_coverage_stats(file_name, elpased)
263
- stat = coverage_reporter.coverage_stat
373
+ def merge_parallel_tests_coverage_reports
374
+ return unless parallel_tests_executed? && !simplecov?
375
+
376
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
377
+ reports_dir = []
378
+
379
+ 1.upto(ENV['PARALLEL_TEST_GROUPS'].to_i) do |test_num|
380
+ coverage_path = File.dirname(RSpecTracer.coverage_path)
381
+ coverage_dir = File.join(coverage_path, "parallel_tests_#{test_num}")
382
+
383
+ reports_dir << coverage_dir if File.directory?(coverage_dir)
384
+ end
385
+
386
+ coverage_merger.merge(reports_dir)
387
+
388
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
389
+ elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
390
+
391
+ puts "RSpec tracer merged parallel tests coverage reports (took #{elapsed})"
392
+ end
393
+
394
+ def write_parallel_tests_coverage_report
395
+ return unless parallel_tests_executed? && !simplecov?
396
+
397
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
398
+
399
+ coverage_path = File.dirname(RSpecTracer.coverage_path)
400
+ file_name = File.join(coverage_path, 'coverage.json')
401
+ coverage_writer = RSpecTracer::CoverageWriter.new(file_name, coverage_merger)
402
+
403
+ coverage_writer.write_report
404
+
405
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
406
+
407
+ coverage_writer.print_stats(ending - starting)
408
+ end
409
+
410
+ def purge_parallel_tests_reports
411
+ return unless parallel_tests_executed?
412
+
413
+ 1.upto(ENV['PARALLEL_TEST_GROUPS'].to_i) do |test_num|
414
+ [RSpecTracer.cache_path, RSpecTracer.coverage_path, RSpecTracer.report_path].each do |path|
415
+ FileUtils.rm_rf(File.join(File.dirname(path), "parallel_tests_#{test_num}"))
416
+ end
417
+ end
418
+ end
419
+
420
+ def parallel_tests_executed?
421
+ return false unless parallel_tests? && parallel_tests_last_process?
422
+
423
+ ParallelTests.wait_for_other_processes_to_finish
424
+
425
+ true
426
+ end
427
+
428
+ def parallel_tests_last_process?
429
+ return false unless parallel_tests?
430
+
431
+ max_test_num = 0
432
+
433
+ File.open(RSpecTracer.parallel_tests_lock_file, 'r') do |f|
434
+ f.flock(File::LOCK_SH)
435
+
436
+ max_test_num = f.read.to_i
437
+ end
264
438
 
265
- puts <<-REPORT.strip.gsub(/\s+/, ' ')
266
- Coverage report generated for RSpecTracer to #{file_name}. #{stat[:covered_lines]}
267
- / #{stat[:total_lines]} LOC (#{stat[:covered_percent]}%) covered
268
- (took #{elpased})
269
- REPORT
439
+ ENV['TEST_ENV_NUMBER'].to_i == max_test_num
270
440
  end
271
441
  end
272
442
  end
metadata CHANGED
@@ -1,55 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abhimanyu Singh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-03 00:00:00.000000000 Z
11
+ date: 2021-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.1'
20
17
  - - ">="
21
18
  - !ruby/object:Gem::Version
22
19
  version: 1.1.0
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '1.1'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '1.1'
30
27
  - - ">="
31
28
  - !ruby/object:Gem::Version
32
29
  version: 1.1.0
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rspec-core
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '3.6'
40
37
  - - ">="
41
38
  - !ruby/object:Gem::Version
42
39
  version: 3.6.0
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '3.6'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '3.6'
50
47
  - - ">="
51
48
  - !ruby/object:Gem::Version
52
49
  version: 3.6.0
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '3.6'
53
53
  description: RSpec Tracer is a specs dependency analyzer, flaky tests detector, tests
54
54
  accelerator, and coverage reporter tool for RSpec. It maintains a list of files
55
55
  for each test, enabling itself to skip tests in the subsequent runs if none of the
@@ -67,7 +67,9 @@ files:
67
67
  - lib/rspec_tracer.rb
68
68
  - lib/rspec_tracer/cache.rb
69
69
  - lib/rspec_tracer/configuration.rb
70
+ - lib/rspec_tracer/coverage_merger.rb
70
71
  - lib/rspec_tracer/coverage_reporter.rb
72
+ - lib/rspec_tracer/coverage_writer.rb
71
73
  - lib/rspec_tracer/defaults.rb
72
74
  - lib/rspec_tracer/example.rb
73
75
  - lib/rspec_tracer/filter.rb
@@ -101,6 +103,9 @@ files:
101
103
  - lib/rspec_tracer/remote_cache/cache.rb
102
104
  - lib/rspec_tracer/remote_cache/repo.rb
103
105
  - lib/rspec_tracer/remote_cache/validator.rb
106
+ - lib/rspec_tracer/report_generator.rb
107
+ - lib/rspec_tracer/report_merger.rb
108
+ - lib/rspec_tracer/report_writer.rb
104
109
  - lib/rspec_tracer/reporter.rb
105
110
  - lib/rspec_tracer/rspec_reporter.rb
106
111
  - lib/rspec_tracer/rspec_runner.rb
@@ -114,7 +119,7 @@ licenses:
114
119
  - MIT
115
120
  metadata:
116
121
  homepage_uri: https://github.com/avmnu-sng/rspec-tracer
117
- source_code_uri: https://github.com/avmnu-sng/rspec-tracer/tree/v0.9.3
122
+ source_code_uri: https://github.com/avmnu-sng/rspec-tracer/tree/v1.0.0
118
123
  changelog_uri: https://github.com/avmnu-sng/rspec-tracer/blob/main/CHANGELOG.md
119
124
  bug_tracker_uri: https://github.com/avmnu-sng/rspec-tracer/issues
120
125
  post_install_message:
@@ -132,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
137
  - !ruby/object:Gem::Version
133
138
  version: '0'
134
139
  requirements: []
135
- rubygems_version: 3.2.26
140
+ rubygems_version: 3.0.9
136
141
  signing_key:
137
142
  specification_version: 4
138
143
  summary: RSpec Tracer is a specs dependency analyzer, flaky tests detector, tests