rspec-tracer 1.2.3 → 2.0.0.pre.2

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +384 -67
  3. data/README.md +454 -429
  4. data/bin/rspec-tracer +15 -0
  5. data/lib/rspec_tracer/cache/Rakefile +43 -0
  6. data/lib/rspec_tracer/cli/cache_clear.rb +111 -0
  7. data/lib/rspec_tracer/cli/cache_info.rb +104 -0
  8. data/lib/rspec_tracer/cli/doctor.rb +284 -0
  9. data/lib/rspec_tracer/cli/explain.rb +158 -0
  10. data/lib/rspec_tracer/cli/report_open.rb +82 -0
  11. data/lib/rspec_tracer/cli.rb +116 -0
  12. data/lib/rspec_tracer/configuration.rb +1196 -3
  13. data/lib/rspec_tracer/engine.rb +1168 -0
  14. data/lib/rspec_tracer/example.rb +141 -11
  15. data/lib/rspec_tracer/filter.rb +35 -0
  16. data/lib/rspec_tracer/line_stub.rb +61 -0
  17. data/lib/rspec_tracer/load_config.rb +2 -2
  18. data/lib/rspec_tracer/logger.rb +15 -0
  19. data/lib/rspec_tracer/rails/README.md +78 -0
  20. data/lib/rspec_tracer/rails/i18n_tracking.rb +137 -0
  21. data/lib/rspec_tracer/rails/notifications.rb +263 -0
  22. data/lib/rspec_tracer/rails/preset.rb +94 -0
  23. data/lib/rspec_tracer/rails/railtie.rb +22 -0
  24. data/lib/rspec_tracer/rails.rb +15 -0
  25. data/lib/rspec_tracer/remote_cache/README.md +140 -0
  26. data/lib/rspec_tracer/remote_cache/Rakefile +35 -11
  27. data/lib/rspec_tracer/remote_cache/archive.rb +137 -0
  28. data/lib/rspec_tracer/remote_cache/backend.rb +73 -0
  29. data/lib/rspec_tracer/remote_cache/git_ancestry.rb +241 -0
  30. data/lib/rspec_tracer/remote_cache/local_fs_backend.rb +439 -0
  31. data/lib/rspec_tracer/remote_cache/redis_backend.rb +554 -0
  32. data/lib/rspec_tracer/remote_cache/s3_backend.rb +712 -0
  33. data/lib/rspec_tracer/remote_cache/user_tasks.rb +436 -0
  34. data/lib/rspec_tracer/remote_cache/validator.rb +40 -62
  35. data/lib/rspec_tracer/remote_cache.rb +22 -0
  36. data/lib/rspec_tracer/reporters/README.md +103 -0
  37. data/lib/rspec_tracer/reporters/base.rb +87 -0
  38. data/lib/rspec_tracer/reporters/coverage_json_reporter.rb +338 -0
  39. data/lib/rspec_tracer/reporters/html/.gitignore +19 -0
  40. data/lib/rspec_tracer/reporters/html/.prettierignore +4 -0
  41. data/lib/rspec_tracer/reporters/html/.prettierrc.json +9 -0
  42. data/lib/rspec_tracer/reporters/html/README.md +80 -0
  43. data/lib/rspec_tracer/reporters/html/dist/assets/index.css +2 -0
  44. data/lib/rspec_tracer/reporters/html/dist/assets/index.js +1 -0
  45. data/lib/rspec_tracer/reporters/html/dist/index.html +24 -0
  46. data/lib/rspec_tracer/reporters/html/eslint.config.js +62 -0
  47. data/lib/rspec_tracer/reporters/html/package-lock.json +4941 -0
  48. data/lib/rspec_tracer/reporters/html/package.json +29 -0
  49. data/lib/rspec_tracer/reporters/html/src/app.jsx +130 -0
  50. data/lib/rspec_tracer/reporters/html/src/components/AllExamples.jsx +86 -0
  51. data/lib/rspec_tracer/reporters/html/src/components/DuplicateExamples.jsx +68 -0
  52. data/lib/rspec_tracer/reporters/html/src/components/ExamplesDependency.jsx +78 -0
  53. data/lib/rspec_tracer/reporters/html/src/components/FilesDependency.jsx +72 -0
  54. data/lib/rspec_tracer/reporters/html/src/components/FlakyExamples.jsx +42 -0
  55. data/lib/rspec_tracer/reporters/html/src/components/ReportTable.jsx +131 -0
  56. data/lib/rspec_tracer/reporters/html/src/components/SearchBar.jsx +19 -0
  57. data/lib/rspec_tracer/reporters/html/src/index.html +23 -0
  58. data/lib/rspec_tracer/reporters/html/src/main.jsx +37 -0
  59. data/lib/rspec_tracer/reporters/html/src/styles.css +434 -0
  60. data/lib/rspec_tracer/reporters/html/vite.config.js +42 -0
  61. data/lib/rspec_tracer/reporters/html_reporter.rb +266 -0
  62. data/lib/rspec_tracer/reporters/json_reporter.rb +88 -0
  63. data/lib/rspec_tracer/reporters/payload_builder.rb +235 -0
  64. data/lib/rspec_tracer/reporters/registry.rb +120 -0
  65. data/lib/rspec_tracer/reporters/terminal_reporter.rb +264 -0
  66. data/lib/rspec_tracer/rspec/README.md +73 -0
  67. data/lib/rspec_tracer/rspec/installation.rb +97 -0
  68. data/lib/rspec_tracer/rspec/metadata.rb +96 -0
  69. data/lib/rspec_tracer/rspec/parallel_tests.rb +459 -0
  70. data/lib/rspec_tracer/rspec/reporter_hook.rb +84 -0
  71. data/lib/rspec_tracer/rspec/runner_hook.rb +239 -0
  72. data/lib/rspec_tracer/source_file.rb +24 -7
  73. data/lib/rspec_tracer/storage/README.md +35 -0
  74. data/lib/rspec_tracer/storage/backend.rb +130 -0
  75. data/lib/rspec_tracer/storage/json_backend.rb +884 -0
  76. data/lib/rspec_tracer/storage/lazy_snapshot.rb +65 -0
  77. data/lib/rspec_tracer/storage/schema.rb +50 -0
  78. data/lib/rspec_tracer/storage/serializer/json.rb +41 -0
  79. data/lib/rspec_tracer/storage/serializer/msgpack.rb +167 -0
  80. data/lib/rspec_tracer/storage/snapshot.rb +141 -0
  81. data/lib/rspec_tracer/storage/sqlite_backend.rb +693 -0
  82. data/lib/rspec_tracer/time_formatter.rb +37 -18
  83. data/lib/rspec_tracer/tracker/README.md +36 -0
  84. data/lib/rspec_tracer/tracker/coverage_adapter.rb +174 -0
  85. data/lib/rspec_tracer/tracker/declared_globs.rb +100 -0
  86. data/lib/rspec_tracer/tracker/dependency_graph.rb +134 -0
  87. data/lib/rspec_tracer/tracker/env_matcher.rb +127 -0
  88. data/lib/rspec_tracer/tracker/env_snapshot.rb +77 -0
  89. data/lib/rspec_tracer/tracker/example_registry.rb +153 -0
  90. data/lib/rspec_tracer/tracker/file_digest.rb +61 -0
  91. data/lib/rspec_tracer/tracker/filter.rb +127 -0
  92. data/lib/rspec_tracer/tracker/input.rb +99 -0
  93. data/lib/rspec_tracer/tracker/io_hooks/file.rb +55 -0
  94. data/lib/rspec_tracer/tracker/io_hooks/io.rb +24 -0
  95. data/lib/rspec_tracer/tracker/io_hooks/json.rb +23 -0
  96. data/lib/rspec_tracer/tracker/io_hooks/kernel.rb +26 -0
  97. data/lib/rspec_tracer/tracker/io_hooks/yaml.rb +38 -0
  98. data/lib/rspec_tracer/tracker/io_hooks.rb +195 -0
  99. data/lib/rspec_tracer/tracker/loaded_files_tracker.rb +295 -0
  100. data/lib/rspec_tracer/tracker/new_file_detector.rb +62 -0
  101. data/lib/rspec_tracer/tracker/whole_suite_invalidators.rb +96 -0
  102. data/lib/rspec_tracer/version.rb +4 -1
  103. data/lib/rspec_tracer.rb +231 -491
  104. metadata +94 -43
  105. data/lib/rspec_tracer/cache.rb +0 -207
  106. data/lib/rspec_tracer/coverage_merger.rb +0 -42
  107. data/lib/rspec_tracer/coverage_reporter.rb +0 -187
  108. data/lib/rspec_tracer/coverage_writer.rb +0 -58
  109. data/lib/rspec_tracer/html_reporter/Rakefile +0 -18
  110. data/lib/rspec_tracer/html_reporter/assets/javascripts/application.js +0 -56
  111. data/lib/rspec_tracer/html_reporter/assets/javascripts/libraries/jquery.js +0 -10881
  112. data/lib/rspec_tracer/html_reporter/assets/javascripts/plugins/datatables.js +0 -15381
  113. data/lib/rspec_tracer/html_reporter/assets/stylesheets/application.css +0 -196
  114. data/lib/rspec_tracer/html_reporter/assets/stylesheets/plugins/datatables.css +0 -459
  115. data/lib/rspec_tracer/html_reporter/assets/stylesheets/plugins/jquery-ui.css +0 -436
  116. data/lib/rspec_tracer/html_reporter/assets/stylesheets/print.css +0 -92
  117. data/lib/rspec_tracer/html_reporter/assets/stylesheets/reset.css +0 -265
  118. data/lib/rspec_tracer/html_reporter/public/application.css +0 -5
  119. data/lib/rspec_tracer/html_reporter/public/application.js +0 -6
  120. data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_asc.png +0 -0
  121. data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_asc_disabled.png +0 -0
  122. data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_both.png +0 -0
  123. data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_desc.png +0 -0
  124. data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_desc_disabled.png +0 -0
  125. data/lib/rspec_tracer/html_reporter/public/favicon.png +0 -0
  126. data/lib/rspec_tracer/html_reporter/public/loading.gif +0 -0
  127. data/lib/rspec_tracer/html_reporter/reporter.rb +0 -242
  128. data/lib/rspec_tracer/html_reporter/views/duplicate_examples.erb +0 -34
  129. data/lib/rspec_tracer/html_reporter/views/examples.erb +0 -58
  130. data/lib/rspec_tracer/html_reporter/views/examples_dependency.erb +0 -36
  131. data/lib/rspec_tracer/html_reporter/views/files_dependency.erb +0 -36
  132. data/lib/rspec_tracer/html_reporter/views/flaky_examples.erb +0 -38
  133. data/lib/rspec_tracer/html_reporter/views/layout.erb +0 -38
  134. data/lib/rspec_tracer/remote_cache/aws.rb +0 -176
  135. data/lib/rspec_tracer/remote_cache/cache.rb +0 -75
  136. data/lib/rspec_tracer/remote_cache/repo.rb +0 -210
  137. data/lib/rspec_tracer/report_generator.rb +0 -158
  138. data/lib/rspec_tracer/report_merger.rb +0 -68
  139. data/lib/rspec_tracer/report_writer.rb +0 -141
  140. data/lib/rspec_tracer/reporter.rb +0 -204
  141. data/lib/rspec_tracer/rspec_reporter.rb +0 -41
  142. data/lib/rspec_tracer/rspec_runner.rb +0 -56
  143. data/lib/rspec_tracer/ruby_coverage.rb +0 -9
  144. data/lib/rspec_tracer/runner.rb +0 -278
@@ -1,204 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpecTracer
4
- class Reporter
5
- attr_reader :all_examples, :interrupted_examples, :duplicate_examples,
6
- :possibly_flaky_examples, :flaky_examples, :pending_examples,
7
- :skipped_examples, :failed_examples, :all_files, :modified_files,
8
- :deleted_files, :dependency, :examples_coverage
9
-
10
- attr_accessor :reverse_dependency, :last_run
11
-
12
- def initialize
13
- initialize_examples
14
- initialize_files
15
- initialize_dependency
16
- initialize_coverage
17
- end
18
-
19
- def register_example(example)
20
- @all_examples[example[:example_id]] = example
21
- @duplicate_examples[example[:example_id]] << example
22
- end
23
-
24
- def deregister_duplicate_examples
25
- @duplicate_examples.select! { |_, examples| examples.count > 1 }
26
-
27
- return if @duplicate_examples.empty?
28
-
29
- @all_examples.reject! { |example_id, _| @duplicate_examples.key?(example_id) }
30
- end
31
-
32
- def on_example_skipped(example_id)
33
- @skipped_examples << example_id
34
- end
35
-
36
- def on_example_passed(example_id, result)
37
- return if @duplicate_examples.key?(example_id)
38
-
39
- @passed_examples << example_id
40
- @all_examples[example_id][:execution_result] = formatted_execution_result(result)
41
- end
42
-
43
- def on_example_failed(example_id, result)
44
- return if @duplicate_examples.key?(example_id)
45
-
46
- @failed_examples << example_id
47
- @all_examples[example_id][:execution_result] = formatted_execution_result(result)
48
- end
49
-
50
- def on_example_pending(example_id, result)
51
- return if @duplicate_examples.key?(example_id)
52
-
53
- @pending_examples << example_id
54
- @all_examples[example_id][:execution_result] = formatted_execution_result(result)
55
- end
56
-
57
- def register_interrupted_examples
58
- @all_examples.each_pair do |example_id, example|
59
- next if example.key?(:execution_result)
60
-
61
- @interrupted_examples << example_id
62
- end
63
-
64
- return if @interrupted_examples.empty?
65
-
66
- RSpecTracer.logger.info "RSpec tracer is not processing #{@interrupted_examples.count} interrupted examples"
67
- end
68
-
69
- def register_deleted_examples(seen_examples)
70
- @deleted_examples = seen_examples.keys.to_set - (@skipped_examples | @all_examples.keys)
71
- @deleted_examples -= @interrupted_examples
72
-
73
- @deleted_examples.select! do |example_id|
74
- example = seen_examples[example_id]
75
-
76
- file_changed?(example[:file_name]) || file_changed?(example[:rerun_file_name])
77
- end
78
- end
79
-
80
- def register_possibly_flaky_example(example_id)
81
- @possibly_flaky_examples << example_id
82
- end
83
-
84
- def register_flaky_example(example_id)
85
- @flaky_examples << example_id
86
- end
87
-
88
- def register_failed_example(example_id)
89
- @failed_examples << example_id
90
- end
91
-
92
- def register_pending_example(example_id)
93
- @pending_examples << example_id
94
- end
95
-
96
- def duplicate_example?(example_id)
97
- @duplicate_examples.key?(example_id)
98
- end
99
-
100
- def example_interrupted?(example_id)
101
- @interrupted_examples.include?(example_id)
102
- end
103
-
104
- def example_passed?(example_id)
105
- @passed_examples.include?(example_id)
106
- end
107
-
108
- def example_skipped?(example_id)
109
- @skipped_examples.include?(example_id)
110
- end
111
-
112
- def example_failed?(example_id)
113
- @failed_examples.include?(example_id)
114
- end
115
-
116
- def example_pending?(example_id)
117
- @pending_examples.include?(example_id)
118
- end
119
-
120
- def example_deleted?(example_id)
121
- @deleted_examples.include?(example_id)
122
- end
123
-
124
- def register_source_file(source_file)
125
- @all_files[source_file[:file_name]] = source_file
126
- end
127
-
128
- def on_file_deleted(file_name)
129
- @deleted_files << file_name
130
- end
131
-
132
- def on_file_modified(file_name)
133
- @modified_files << file_name
134
- end
135
-
136
- def file_deleted?(file_name)
137
- @deleted_files.include?(file_name)
138
- end
139
-
140
- def file_modified?(file_name)
141
- @modified_files.include?(file_name)
142
- end
143
-
144
- def file_changed?(file_name)
145
- file_deleted?(file_name) || file_modified?(file_name)
146
- end
147
-
148
- def register_dependency(example_id, file_name)
149
- @dependency[example_id] << file_name
150
- end
151
-
152
- def register_examples_coverage(examples_coverage)
153
- @examples_coverage = examples_coverage
154
- end
155
-
156
- private
157
-
158
- def initialize_examples
159
- @all_examples = {}
160
- @duplicate_examples = Hash.new { |examples, example_id| examples[example_id] = [] }
161
- @interrupted_examples = Set.new
162
- @passed_examples = Set.new
163
- @possibly_flaky_examples = Set.new
164
- @flaky_examples = Set.new
165
- @failed_examples = Set.new
166
- @skipped_examples = Set.new
167
- @pending_examples = Set.new
168
- @deleted_examples = Set.new
169
- end
170
-
171
- def initialize_files
172
- @all_files = {}
173
- @modified_files = Set.new
174
- @deleted_files = Set.new
175
- end
176
-
177
- def initialize_dependency
178
- @dependency = Hash.new { |hash, key| hash[key] = Set.new }
179
- @reverse_dependency = Hash.new do |examples, file_name|
180
- examples[file_name] = {
181
- example_count: 0,
182
- examples: Hash.new(0)
183
- }
184
- end
185
- end
186
-
187
- def initialize_coverage
188
- @examples_coverage = Hash.new do |examples, example_id|
189
- examples[example_id] = Hash.new do |files, file_name|
190
- files[file_name] = {}
191
- end
192
- end
193
- end
194
-
195
- def formatted_execution_result(result)
196
- {
197
- started_at: result.started_at.utc,
198
- finished_at: result.finished_at.utc,
199
- run_time: result.run_time,
200
- status: result.status.to_s
201
- }
202
- end
203
- end
204
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpecTracer
4
- module RSpecReporter
5
- def example_started(example)
6
- RSpecTracer.coverage_reporter.record_coverage
7
- RSpecTracer.start_example_trace
8
-
9
- super
10
- end
11
-
12
- def example_finished(example)
13
- example_id = example.metadata[:rspec_tracer_example_id]
14
- RSpecTracer.stop_example_trace(example_id)
15
- RSpecTracer.coverage_reporter.compute_diff(example_id)
16
-
17
- super
18
- end
19
-
20
- def example_passed(example)
21
- example_id = example.metadata[:rspec_tracer_example_id]
22
- RSpecTracer.runner.on_example_passed(example_id, example.execution_result)
23
-
24
- super
25
- end
26
-
27
- def example_failed(example)
28
- example_id = example.metadata[:rspec_tracer_example_id]
29
- RSpecTracer.runner.on_example_failed(example_id, example.execution_result)
30
-
31
- super
32
- end
33
-
34
- def example_pending(example)
35
- example_id = example.metadata[:rspec_tracer_example_id]
36
- RSpecTracer.runner.on_example_pending(example_id, example.execution_result)
37
-
38
- super
39
- end
40
- end
41
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpecTracer
4
- module RSpecRunner
5
- def run_specs(example_groups)
6
- actual_count = RSpec.world.example_count
7
-
8
- if _no_examples?(actual_count)
9
- super
10
-
11
- return
12
- end
13
-
14
- starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
15
- filtered_examples, filtered_example_groups = RSpecTracer.filter_examples
16
-
17
- if _duplicate_examples?
18
- super([])
19
-
20
- return
21
- end
22
-
23
- RSpec.world.instance_variable_set(:@filtered_examples, filtered_examples)
24
- RSpec.world.instance_variable_set(:@example_groups, filtered_example_groups)
25
-
26
- current_count = RSpec.world.example_count
27
- ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
28
- elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
29
-
30
- RSpecTracer.logger.info <<-EXAMPLES.strip.gsub(/\s+/, ' ')
31
- RSpec tracer is running #{current_count} examples (actual: #{actual_count},
32
- skipped: #{actual_count - current_count}) (took #{elapsed})
33
- EXAMPLES
34
-
35
- RSpecTracer.running = true
36
-
37
- super(filtered_example_groups)
38
- end
39
-
40
- def _no_examples?(actual_count)
41
- return false unless actual_count.zero?
42
-
43
- RSpecTracer.running = true
44
- RSpecTracer.no_examples = true
45
- end
46
-
47
- def _duplicate_examples?
48
- return false if RSpecTracer.runner.reporter.duplicate_examples.empty?
49
-
50
- RSpecTracer.report_writer.print_duplicate_examples
51
-
52
- RSpecTracer.running = true
53
- RSpecTracer.duplicate_examples = RSpecTracer.fail_on_duplicates
54
- end
55
- end
56
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpecTracer
4
- module RubyCoverage
5
- def result
6
- RSpecTracer.coverage_reporter.coverage
7
- end
8
- end
9
- end
@@ -1,278 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'cache'
4
- require_relative 'reporter'
5
-
6
- module RSpecTracer
7
- class Runner
8
- EXAMPLE_RUN_REASON = {
9
- explicit_run: 'Explicit run',
10
- no_cache: 'No cache',
11
- interrupted: 'Interrupted previously',
12
- flaky_example: 'Flaky example',
13
- failed_example: 'Failed previously',
14
- pending_example: 'Pending previously',
15
- files_changed: 'Files changed'
16
- }.freeze
17
-
18
- attr_reader :cache, :reporter
19
-
20
- def initialize
21
- @cache = RSpecTracer::Cache.new
22
- @reporter = RSpecTracer::Reporter.new
23
- @filtered_examples = {}
24
-
25
- @cache.load_cache_for_run
26
- filter_examples_to_run
27
- end
28
-
29
- def run_example?(example_id)
30
- return true if RSpecTracer.run_all_examples
31
-
32
- !@cache.all_examples.key?(example_id) || @filtered_examples.key?(example_id)
33
- end
34
-
35
- def run_example_reason(example_id)
36
- return EXAMPLE_RUN_REASON[:explicit_run] if RSpecTracer.run_all_examples
37
-
38
- @filtered_examples[example_id] || EXAMPLE_RUN_REASON[:no_cache]
39
- end
40
-
41
- def register_example(example)
42
- @reporter.register_example(example)
43
- end
44
-
45
- def deregister_duplicate_examples
46
- @reporter.deregister_duplicate_examples
47
- end
48
-
49
- def on_example_skipped(example_id)
50
- @reporter.on_example_skipped(example_id)
51
- end
52
-
53
- def on_example_passed(example_id, execution_result)
54
- @reporter.on_example_passed(example_id, execution_result)
55
- end
56
-
57
- def on_example_failed(example_id, execution_result)
58
- @reporter.on_example_failed(example_id, execution_result)
59
- end
60
-
61
- def on_example_pending(example_id, execution_result)
62
- @reporter.on_example_pending(example_id, execution_result)
63
- end
64
-
65
- def register_interrupted_examples
66
- @reporter.register_interrupted_examples
67
- end
68
-
69
- def register_deleted_examples
70
- @reporter.register_deleted_examples(@cache.all_examples)
71
- end
72
-
73
- # rubocop:disable Metrics/PerceivedComplexity
74
- def generate_missed_coverage
75
- missed_coverage = Hash.new do |files_coverage, file_path|
76
- files_coverage[file_path] = Hash.new do |strength, line_number|
77
- strength[line_number] = 0
78
- end
79
- end
80
-
81
- (@cache.cached_examples_coverage || {}).each_pair do |example_id, example_coverage|
82
- example_coverage.each_pair do |file_path, line_coverage|
83
- next if @reporter.example_interrupted?(example_id) ||
84
- @reporter.duplicate_example?(example_id)
85
-
86
- next unless @reporter.example_skipped?(example_id)
87
-
88
- file_name = RSpecTracer::SourceFile.file_name(file_path)
89
-
90
- next if @reporter.file_deleted?(file_name)
91
-
92
- line_coverage.each_pair do |line_number, strength|
93
- missed_coverage[file_path][line_number] += strength || 0
94
- end
95
- end
96
- end
97
-
98
- missed_coverage
99
- end
100
- # rubocop:enable Metrics/PerceivedComplexity
101
-
102
- def register_dependency(examples_coverage)
103
- filtered_files = Set.new
104
-
105
- examples_coverage.each_pair do |example_id, example_coverage|
106
- next if @reporter.example_interrupted?(example_id) ||
107
- @reporter.duplicate_example?(example_id)
108
-
109
- register_example_files_dependency(example_id)
110
-
111
- example_coverage.each_key do |file_path|
112
- next if filtered_files.include?(file_path)
113
-
114
- filtered_files << file_path unless register_file_dependency(example_id, file_path)
115
- end
116
- end
117
-
118
- @reporter.pending_examples.each do |example_id|
119
- register_example_files_dependency(example_id)
120
- end
121
- end
122
-
123
- def register_traced_dependency(examples_traced_files)
124
- rspec_required_files = fetch_rspec_required_files
125
-
126
- examples_traced_files.each_pair do |example_id, traced_files|
127
- required_files = traced_files | rspec_required_files
128
-
129
- required_files.each { |file_path| register_file_dependency(example_id, file_path) }
130
- end
131
- end
132
-
133
- def register_examples_coverage(examples_coverage)
134
- @reporter.register_examples_coverage(examples_coverage)
135
- end
136
-
137
- private
138
-
139
- def filter_examples_to_run
140
- starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
141
- @changed_files = fetch_changed_files
142
-
143
- filter_by_example_status
144
- filter_by_files_changed
145
-
146
- ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
147
- elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
148
-
149
- RSpecTracer.logger.debug "RSpec tracer processed cache (took #{elapsed})"
150
- end
151
-
152
- def filter_by_example_status
153
- add_previously_interrupted_examples
154
- add_previously_flaky_examples
155
- add_previously_failed_examples
156
- add_previously_pending_examples
157
- end
158
-
159
- def filter_by_files_changed
160
- @cache.dependency.each_pair do |example_id, files|
161
- next if @filtered_examples.key?(example_id)
162
- next unless @changed_files.intersect?(files)
163
-
164
- @filtered_examples[example_id] = EXAMPLE_RUN_REASON[:files_changed]
165
- end
166
- end
167
-
168
- def add_previously_interrupted_examples
169
- @cache.interrupted_examples.each do |example_id|
170
- @filtered_examples[example_id] = EXAMPLE_RUN_REASON[:interrupted]
171
- end
172
- end
173
-
174
- def add_previously_flaky_examples
175
- @cache.flaky_examples.each do |example_id|
176
- @filtered_examples[example_id] = EXAMPLE_RUN_REASON[:flaky_example]
177
-
178
- next unless @cache.dependency.key?(example_id)
179
- next if @changed_files.intersect?(@cache.dependency[example_id])
180
-
181
- @reporter.register_possibly_flaky_example(example_id)
182
- end
183
- end
184
-
185
- def add_previously_failed_examples
186
- @cache.failed_examples.each do |example_id|
187
- next if @filtered_examples.key?(example_id)
188
-
189
- @filtered_examples[example_id] = EXAMPLE_RUN_REASON[:failed_example]
190
-
191
- next unless @cache.dependency.key?(example_id)
192
- next if @changed_files.intersect?(@cache.dependency[example_id])
193
-
194
- @reporter.register_possibly_flaky_example(example_id)
195
- end
196
- end
197
-
198
- def add_previously_pending_examples
199
- @cache.pending_examples.each do |example_id|
200
- @filtered_examples[example_id] = EXAMPLE_RUN_REASON[:pending_example]
201
- end
202
- end
203
-
204
- def fetch_changed_files
205
- @cache.all_files.each_value do |cached_file|
206
- file_name = cached_file[:file_name]
207
- source_file = RSpecTracer::SourceFile.from_name(file_name)
208
-
209
- if source_file.nil?
210
- @reporter.on_file_deleted(file_name)
211
- elsif cached_file[:digest] != source_file[:digest]
212
- @reporter.on_file_modified(file_name)
213
- end
214
- end
215
-
216
- @reporter.modified_files | @reporter.deleted_files
217
- end
218
-
219
- def fetch_rspec_required_files
220
- rspec_root = RSpec::Core::RubyProject.root
221
- rspec_path = RSpec.configuration.default_path
222
-
223
- RSpec.configuration.requires.each_with_object([]) do |file_name, required_files|
224
- file_name = "#{file_name}.rb" if File.extname(file_name).empty?
225
- file_path = File.join(rspec_root, rspec_path, file_name)
226
-
227
- required_files << file_path if File.file?(file_path)
228
- end
229
- end
230
-
231
- def register_example_files_dependency(example_id)
232
- return if @reporter.example_interrupted?(example_id) ||
233
- @reporter.duplicate_example?(example_id)
234
-
235
- example = @reporter.all_examples[example_id]
236
-
237
- register_example_file_dependency(example_id, example[:file_name])
238
-
239
- return if example[:rerun_file_name] == example[:file_name]
240
-
241
- register_example_file_dependency(example_id, example[:rerun_file_name])
242
- end
243
-
244
- def register_example_file_dependency(example_id, file_name)
245
- return if @reporter.example_interrupted?(example_id) ||
246
- @reporter.duplicate_example?(example_id)
247
-
248
- source_file = RSpecTracer::SourceFile.from_name(file_name)
249
-
250
- if source_file.nil?
251
- RSpecTracer.logger.debug "Skipping missing source file #{file_name} for example #{example_id}"
252
- return
253
- end
254
-
255
- @reporter.register_source_file(source_file)
256
- @reporter.register_dependency(example_id, file_name)
257
- end
258
-
259
- def register_file_dependency(example_id, file_path)
260
- return if @reporter.example_interrupted?(example_id) ||
261
- @reporter.duplicate_example?(example_id)
262
-
263
- source_file = RSpecTracer::SourceFile.from_path(file_path)
264
-
265
- if source_file.nil?
266
- RSpecTracer.logger.debug "Skipping missing source file #{file_path} for example #{example_id}"
267
- return false
268
- end
269
-
270
- return false if RSpecTracer.filters.any? { |filter| filter.match?(source_file) }
271
-
272
- @reporter.register_source_file(source_file)
273
- @reporter.register_dependency(example_id, source_file[:file_name])
274
-
275
- true
276
- end
277
- end
278
- end