testsift 0.0.1

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 (113) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +22 -0
  3. data/LICENSE +22 -0
  4. data/README.md +572 -0
  5. data/bin/testsift +15 -0
  6. data/lib/testsift/cache/Rakefile +43 -0
  7. data/lib/testsift/cli/blast_radius.rb +318 -0
  8. data/lib/testsift/cli/cache_clear.rb +114 -0
  9. data/lib/testsift/cli/cache_info.rb +106 -0
  10. data/lib/testsift/cli/doctor.rb +307 -0
  11. data/lib/testsift/cli/explain.rb +273 -0
  12. data/lib/testsift/cli/report_open.rb +90 -0
  13. data/lib/testsift/cli/snapshot_helpers.rb +119 -0
  14. data/lib/testsift/cli.rb +219 -0
  15. data/lib/testsift/configuration.rb +1467 -0
  16. data/lib/testsift/defaults.rb +11 -0
  17. data/lib/testsift/engine/snapshot_builder.rb +117 -0
  18. data/lib/testsift/engine.rb +896 -0
  19. data/lib/testsift/example.rb +188 -0
  20. data/lib/testsift/filter.rb +103 -0
  21. data/lib/testsift/line_stub.rb +62 -0
  22. data/lib/testsift/load_config.rb +15 -0
  23. data/lib/testsift/load_default_config.rb +46 -0
  24. data/lib/testsift/load_global_config.rb +33 -0
  25. data/lib/testsift/load_local_config.rb +17 -0
  26. data/lib/testsift/logger.rb +59 -0
  27. data/lib/testsift/rails/README.md +78 -0
  28. data/lib/testsift/rails/i18n_tracking.rb +137 -0
  29. data/lib/testsift/rails/notifications.rb +263 -0
  30. data/lib/testsift/rails/preset.rb +94 -0
  31. data/lib/testsift/rails/railtie.rb +22 -0
  32. data/lib/testsift/rails.rb +15 -0
  33. data/lib/testsift/remote_cache/README.md +140 -0
  34. data/lib/testsift/remote_cache/Rakefile +61 -0
  35. data/lib/testsift/remote_cache/archive.rb +137 -0
  36. data/lib/testsift/remote_cache/backend.rb +73 -0
  37. data/lib/testsift/remote_cache/git_ancestry.rb +241 -0
  38. data/lib/testsift/remote_cache/local_fs_backend.rb +439 -0
  39. data/lib/testsift/remote_cache/redis_backend.rb +554 -0
  40. data/lib/testsift/remote_cache/s3_backend.rb +712 -0
  41. data/lib/testsift/remote_cache/user_tasks.rb +436 -0
  42. data/lib/testsift/remote_cache/validator.rb +50 -0
  43. data/lib/testsift/remote_cache.rb +22 -0
  44. data/lib/testsift/reporters/README.md +103 -0
  45. data/lib/testsift/reporters/base.rb +87 -0
  46. data/lib/testsift/reporters/coverage_json_reporter.rb +338 -0
  47. data/lib/testsift/reporters/html/.gitignore +19 -0
  48. data/lib/testsift/reporters/html/.prettierignore +4 -0
  49. data/lib/testsift/reporters/html/.prettierrc.json +9 -0
  50. data/lib/testsift/reporters/html/README.md +80 -0
  51. data/lib/testsift/reporters/html/dist/assets/index.css +2 -0
  52. data/lib/testsift/reporters/html/dist/assets/index.js +1 -0
  53. data/lib/testsift/reporters/html/dist/index.html +24 -0
  54. data/lib/testsift/reporters/html/eslint.config.js +62 -0
  55. data/lib/testsift/reporters/html/package-lock.json +4910 -0
  56. data/lib/testsift/reporters/html/package.json +29 -0
  57. data/lib/testsift/reporters/html/src/app.jsx +130 -0
  58. data/lib/testsift/reporters/html/src/components/AllExamples.jsx +86 -0
  59. data/lib/testsift/reporters/html/src/components/DuplicateExamples.jsx +68 -0
  60. data/lib/testsift/reporters/html/src/components/ExamplesDependency.jsx +78 -0
  61. data/lib/testsift/reporters/html/src/components/FilesDependency.jsx +72 -0
  62. data/lib/testsift/reporters/html/src/components/FlakyExamples.jsx +42 -0
  63. data/lib/testsift/reporters/html/src/components/ReportTable.jsx +131 -0
  64. data/lib/testsift/reporters/html/src/components/SearchBar.jsx +19 -0
  65. data/lib/testsift/reporters/html/src/index.html +23 -0
  66. data/lib/testsift/reporters/html/src/main.jsx +37 -0
  67. data/lib/testsift/reporters/html/src/styles.css +434 -0
  68. data/lib/testsift/reporters/html/vite.config.js +42 -0
  69. data/lib/testsift/reporters/html_reporter.rb +266 -0
  70. data/lib/testsift/reporters/json_reporter.rb +88 -0
  71. data/lib/testsift/reporters/payload_builder.rb +241 -0
  72. data/lib/testsift/reporters/registry.rb +120 -0
  73. data/lib/testsift/reporters/terminal_reporter.rb +264 -0
  74. data/lib/testsift/rspec/README.md +73 -0
  75. data/lib/testsift/rspec/installation.rb +97 -0
  76. data/lib/testsift/rspec/metadata.rb +96 -0
  77. data/lib/testsift/rspec/parallel_tests.rb +459 -0
  78. data/lib/testsift/rspec/rails_setup.rb +42 -0
  79. data/lib/testsift/rspec/reporter_hook.rb +90 -0
  80. data/lib/testsift/rspec/runner_hook.rb +253 -0
  81. data/lib/testsift/source_file.rb +56 -0
  82. data/lib/testsift/storage/README.md +35 -0
  83. data/lib/testsift/storage/backend.rb +130 -0
  84. data/lib/testsift/storage/json_backend.rb +884 -0
  85. data/lib/testsift/storage/lazy_snapshot.rb +65 -0
  86. data/lib/testsift/storage/schema.rb +50 -0
  87. data/lib/testsift/storage/serializer/json.rb +41 -0
  88. data/lib/testsift/storage/serializer/msgpack.rb +167 -0
  89. data/lib/testsift/storage/snapshot.rb +141 -0
  90. data/lib/testsift/storage/sqlite_backend.rb +709 -0
  91. data/lib/testsift/time_formatter.rb +74 -0
  92. data/lib/testsift/tracker/README.md +36 -0
  93. data/lib/testsift/tracker/coverage_adapter.rb +180 -0
  94. data/lib/testsift/tracker/declared_globs.rb +100 -0
  95. data/lib/testsift/tracker/dependency_graph.rb +134 -0
  96. data/lib/testsift/tracker/env_matcher.rb +127 -0
  97. data/lib/testsift/tracker/env_snapshot.rb +77 -0
  98. data/lib/testsift/tracker/example_registry.rb +153 -0
  99. data/lib/testsift/tracker/file_digest.rb +61 -0
  100. data/lib/testsift/tracker/filter.rb +127 -0
  101. data/lib/testsift/tracker/input.rb +99 -0
  102. data/lib/testsift/tracker/io_hooks/file.rb +55 -0
  103. data/lib/testsift/tracker/io_hooks/io.rb +24 -0
  104. data/lib/testsift/tracker/io_hooks/json.rb +23 -0
  105. data/lib/testsift/tracker/io_hooks/kernel.rb +26 -0
  106. data/lib/testsift/tracker/io_hooks/yaml.rb +38 -0
  107. data/lib/testsift/tracker/io_hooks.rb +195 -0
  108. data/lib/testsift/tracker/loaded_files_tracker.rb +290 -0
  109. data/lib/testsift/tracker/new_file_detector.rb +62 -0
  110. data/lib/testsift/tracker/whole_suite_invalidators.rb +96 -0
  111. data/lib/testsift/version.rb +7 -0
  112. data/lib/testsift.rb +335 -0
  113. metadata +193 -0
data/lib/testsift.rb ADDED
@@ -0,0 +1,335 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+
5
+ require 'digest/md5'
6
+ require 'docile'
7
+ require 'fileutils'
8
+ require 'forwardable'
9
+ require 'json'
10
+ require 'pathname'
11
+ require 'set'
12
+
13
+ require_relative 'testsift/defaults'
14
+ require_relative 'testsift/engine'
15
+ require_relative 'testsift/example'
16
+ # Reporters must load before load_config so the Configuration DSL's
17
+ # `add_reporter` can validate symbol names against
18
+ # `Reporters::Registry::BUILT_INS` when a user `.testsift` calls
19
+ # it at configure time.
20
+ require_relative 'testsift/reporters/base'
21
+ require_relative 'testsift/reporters/payload_builder'
22
+ require_relative 'testsift/reporters/coverage_json_reporter'
23
+ require_relative 'testsift/reporters/json_reporter'
24
+ require_relative 'testsift/reporters/terminal_reporter'
25
+ require_relative 'testsift/reporters/html_reporter'
26
+ require_relative 'testsift/reporters/registry'
27
+ require_relative 'testsift/load_config'
28
+ # RemoteCache is loaded lazily from its Rakefile shim (user-driven),
29
+ # not at gem-load time. The user-facing tasks `testsift:remote_cache:*`
30
+ # pull in `lib/testsift/remote_cache.rb` when the user's Rakefile
31
+ # loads the shim. Test-suite runs that never invoke a cache task pay
32
+ # zero load cost for aws/git subshell code.
33
+ require_relative 'testsift/rspec/installation'
34
+ require_relative 'testsift/rspec/parallel_tests'
35
+ require_relative 'testsift/rspec/rails_setup'
36
+ require_relative 'testsift/source_file'
37
+ require_relative 'testsift/time_formatter'
38
+ require_relative 'testsift/version'
39
+
40
+ # Top-level entry point. Drives the lifecycle:
41
+ #
42
+ # TestSift.start
43
+ # -> RSpec::Installation.install! (prepend RunnerHook + ReporterHook)
44
+ # -> setup_coverage (::Coverage.start unless SimpleCov owns it)
45
+ # -> setup_rails (detect ::Rails::VERSION)
46
+ # -> Engine.new.setup (observers + cache load + filter decisions)
47
+ #
48
+ # at_exit_behavior (installed via `at_exit` elsewhere in the boot
49
+ # flow) runs the finalize stack: Engine#finalize writes the 13-file
50
+ # snapshot via Storage::JsonBackend, Reporters::CoverageJsonReporter
51
+ # writes coverage.json (single owner, replacing the 1.x
52
+ # CoverageReporter + CoverageWriter pair retired in 2.0),
53
+ # ParallelTests#finalize! merges per-worker caches on the last worker.
54
+ module TestSift
55
+ class << self
56
+ # Internal attribute.
57
+ # @api private
58
+ attr_accessor :running, :pid, :no_examples, :duplicate_examples
59
+
60
+ # Boot the tracer. Idempotent — safe to call multiple times in a
61
+ # single process (subsequent calls return without re-installing
62
+ # hooks). Drives the lifecycle:
63
+ #
64
+ # * Installs the RSpec runner / reporter prepend chain.
65
+ # * Starts `::Coverage` unless SimpleCov already owns it.
66
+ # * Detects Rails (memoized in `TestSift.rails?`).
67
+ # * Builds the {TestSift::Engine} and installs observers.
68
+ #
69
+ # Must be called BEFORE any application code loads so the boot
70
+ # set captured by `Coverage.peek_result` is empty. With SimpleCov,
71
+ # call `SimpleCov.start` first; testsift warns at boot when
72
+ # SimpleCov is loaded but not started.
73
+ #
74
+ # @return [void]
75
+ def start
76
+ return if defined?(@started) && @started
77
+
78
+ TestSift.running = false
79
+ TestSift.pid = Process.pid
80
+ @run_started_at = ::Time.now.utc
81
+ @run_monotonic_start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
82
+ @started = true
83
+
84
+ TestSift.logger.debug "Started TestSift (pid: #{TestSift.pid})"
85
+
86
+ warn_on_simplecov_load_order_mistake
87
+
88
+ @parallel_tests = TestSift::RSpec::ParallelTests.active?
89
+ TestSift::RSpec::ParallelTests.setup! if parallel_tests?
90
+ initial_setup
91
+ end
92
+
93
+ # SimpleCov load-order is part of the documented contract -
94
+ # SimpleCov.start MUST run before TestSift.start when both are
95
+ # used together (see README §SimpleCov interop). When the user
96
+ # has SimpleCov loaded but not started, we'd silently call
97
+ # ::Coverage.start ourselves and SimpleCov's later setup would
98
+ # bolt onto a Coverage already in flight, with the user's
99
+ # add_filter calls applied after testsift started consuming
100
+ # data. Surface the load-order mistake at start time so the user
101
+ # gets a one-line warning instead of mysteriously-broken
102
+ # coverage output.
103
+ def warn_on_simplecov_load_order_mistake
104
+ return unless defined?(::SimpleCov)
105
+ return if ::SimpleCov.respond_to?(:running) && ::SimpleCov.running
106
+
107
+ TestSift.logger.warn(
108
+ 'SimpleCov is loaded but not started. ' \
109
+ 'Call SimpleCov.start before TestSift.start so the ' \
110
+ 'tracer respects SimpleCov\'s filter chain. See README ' \
111
+ 'section "Working with SimpleCov".'
112
+ )
113
+ end
114
+
115
+ # Internal method on the tracer pipeline.
116
+ # @api private
117
+ def at_exit_behavior
118
+ return unless TestSift.pid == Process.pid && TestSift.running
119
+
120
+ ::Kernel.exit(1) if duplicate_examples
121
+
122
+ run_exit_tasks
123
+ ensure
124
+ if TestSift::RSpec::ParallelTests.active? &&
125
+ TestSift::RSpec::ParallelTests.last_process?
126
+ TestSift::RSpec::ParallelTests.remove_lock_file!
127
+ end
128
+
129
+ TestSift.running = false
130
+ end
131
+
132
+ # The current {TestSift::Engine} instance, or nil if
133
+ # {.start} hasn't been called yet.
134
+ #
135
+ # @return [TestSift::Engine, nil]
136
+ def engine
137
+ @engine if defined?(@engine)
138
+ end
139
+
140
+ # True if SimpleCov was loaded AND running at the time
141
+ # {.start} was invoked. Determines whether testsift
142
+ # owns `::Coverage.start` itself (false) or defers to
143
+ # SimpleCov's coverage lifecycle (true).
144
+ #
145
+ # @return [Boolean]
146
+ def simplecov?
147
+ defined?(@simplecov) && @simplecov == true
148
+ end
149
+
150
+ # True if `parallel_tests` is in use (detected via
151
+ # `ParallelTests.active?` at {.start} time). Affects
152
+ # cache + report directory scoping (per-worker dirs)
153
+ # and finalize-time merging.
154
+ #
155
+ # @return [Boolean]
156
+ def parallel_tests?
157
+ defined?(@parallel_tests) && @parallel_tests == true
158
+ end
159
+
160
+ # True if Rails is loaded in this process (detected via
161
+ # `defined?(::Rails::VERSION)` at {.start} time). Memoized;
162
+ # subsequent Rails activations within the same run are not
163
+ # re-detected. Drives the auto-installation of Rails-side
164
+ # observers (template + AR notification subscribers).
165
+ #
166
+ # @return [Boolean]
167
+ def rails?
168
+ defined?(@rails) && @rails == true
169
+ end
170
+
171
+ private
172
+
173
+ # Internal method on the tracer pipeline.
174
+ # @api private
175
+ def initial_setup
176
+ TestSift::RSpec::Installation.install!
177
+
178
+ setup_coverage
179
+ setup_rails
180
+
181
+ @engine = TestSift::Engine.new(
182
+ configuration: TestSift,
183
+ read_cache_path: parallel_tests? ? File.dirname(TestSift.cache_path) : nil
184
+ )
185
+ @engine.setup
186
+ TestSift::RSpec::RailsSetup.install(engine: @engine, configuration: TestSift)
187
+ end
188
+
189
+ # Internal method on the tracer pipeline.
190
+ # @api private
191
+ def setup_coverage
192
+ @simplecov = defined?(SimpleCov) && SimpleCov.running
193
+
194
+ return if simplecov?
195
+
196
+ require 'coverage'
197
+
198
+ return if ::Coverage.respond_to?(:running?) && ::Coverage.running?
199
+
200
+ ::Coverage.start(**coverage_modes_for_start)
201
+ rescue RuntimeError
202
+ # ::Coverage.start raises if already started on some Rubies
203
+ # without a running? predicate; safe to ignore (matches
204
+ # Engine#ensure_coverage_started behavior).
205
+ nil
206
+ end
207
+
208
+ # Detects Rails by the presence of `::Rails::VERSION`. Users who
209
+ # require `testsift/rails` transitively load the Railtie (when
210
+ # Rails is also present); this method only sets the flag consumed
211
+ # by `TestSift.rails?`. Safe when Rails is absent - the
212
+ # `defined?` guard returns nil, flag stays false.
213
+ def setup_rails
214
+ @rails = defined?(::Rails::VERSION) && !::Rails::VERSION.nil?
215
+ end
216
+
217
+ # Internal method on the tracer pipeline.
218
+ # @api private
219
+ def run_exit_tasks
220
+ if TestSift.no_examples
221
+ TestSift.logger.info 'Skipped reports generation since all examples were filtered out'
222
+ else
223
+ snapshot = run_finalize
224
+ # Under parallel_tests, defer reporter emission until
225
+ # last-process finalize merges per-worker snapshots into the
226
+ # top-level cache. Each worker still persists its per-worker
227
+ # snapshot for the merge to consume. Earlier behavior had every
228
+ # worker emit reporters into testsift_report/parallel_tests_N/
229
+ # and purge_worker_dirs! removed those dirs - leaving the user
230
+ # with no usable terminal/JSON/HTML output. Now reporters fire
231
+ # ONCE at the merged top-level location.
232
+ emit_reporters(snapshot) if snapshot && !parallel_tests?
233
+ end
234
+
235
+ emit_coverage_json
236
+
237
+ TestSift::RSpec::ParallelTests.finalize! if parallel_tests?
238
+ end
239
+
240
+ # Engine-owned finalize path. Writes the 15-file JSON cache via
241
+ # Storage::JsonBackend. Per-example coverage deltas live on the
242
+ # Engine; 2.0 retired the CoverageReporter mid-flow piece (the
243
+ # legacy `coverage_reporter.generate_final_examples_coverage +
244
+ # merge_coverage(engine.merge_skipped_coverage(...))` is now folded
245
+ # into Reporters::CoverageJsonReporter#generate, which fires from
246
+ # `emit_coverage_json` after this method returns).
247
+ def run_finalize
248
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
249
+
250
+ snapshot = engine.finalize
251
+
252
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
253
+ elapsed = TestSift::TimeFormatter.format_time(ending - starting)
254
+
255
+ TestSift.logger.debug "TestSift persisted cache (took #{elapsed})"
256
+ snapshot
257
+ rescue StandardError => e
258
+ # Graceful-degradation contract per ARCHITECTURE.md
259
+ # section Cache corruption recovery: never propagate storage errors
260
+ # into the user's test suite. Read-only cache_path, disk-full
261
+ # mid-write, permission flips between runs - log and skip
262
+ # report emission. The caller (run_exit_tasks) checks for nil
263
+ # before calling emit_reporters; coverage / parallel_tests
264
+ # finalize paths run independently downstream.
265
+ TestSift.logger.warn(
266
+ "testsift: cache persistence failed (#{e.class}: #{e.message}); " \
267
+ 'skipping report generation. Verify cache_path is writable.'
268
+ )
269
+ nil
270
+ end
271
+
272
+ # Fire the configured reporters against the persisted
273
+ # Snapshot. Fires per-worker under parallel_tests (same cadence as
274
+ # coverage.json emission); each worker produces its own report.json
275
+ # under its per-worker report_dir. The Registry rescues every
276
+ # reporter individually, so a buggy reporter warns and continues -
277
+ # never propagates a non-zero exit into the user's test suite
278
+ # (graceful degradation contract, same as Storage backends).
279
+ def emit_reporters(snapshot)
280
+ TestSift::Reporters::Registry.emit_all(
281
+ configuration: TestSift,
282
+ snapshot: snapshot,
283
+ report_dir: TestSift.report_path,
284
+ run_metadata: build_run_metadata
285
+ )
286
+ rescue StandardError => e
287
+ TestSift.logger.warn(
288
+ "testsift: reporter pipeline failed (#{e.class}: #{e.message})"
289
+ )
290
+ end
291
+
292
+ # Internal method on the tracer pipeline.
293
+ # @api private
294
+ def build_run_metadata
295
+ {
296
+ pid: TestSift.pid,
297
+ run_time: run_elapsed_seconds,
298
+ started_at: defined?(@run_started_at) ? @run_started_at : nil,
299
+ cache_path: TestSift.cache_path,
300
+ parallel_tests: TestSift.parallel_tests?,
301
+ rails: TestSift.rails?
302
+ }
303
+ end
304
+
305
+ # Internal method on the tracer pipeline.
306
+ # @api private
307
+ def run_elapsed_seconds
308
+ return nil unless defined?(@run_monotonic_start) && @run_monotonic_start
309
+
310
+ (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @run_monotonic_start).round(4)
311
+ end
312
+
313
+ # Dedicated coverage.json firing path, parallel to the
314
+ # report-reporters Registry pipeline. Fires unconditionally - even
315
+ # when no examples ran (matches 1.x where coverage.json gets
316
+ # written with whatever boot-time peek_result returned + filter +
317
+ # stub). The emitter handles SimpleCov interop internally
318
+ # (installs `::Coverage.singleton_class.prepend` shim instead of
319
+ # writing coverage.json when SimpleCov is loaded).
320
+ def emit_coverage_json
321
+ return unless engine
322
+
323
+ TestSift::Reporters::CoverageJsonReporter.new(
324
+ snapshot: nil,
325
+ report_dir: TestSift.report_path,
326
+ run_metadata: build_run_metadata,
327
+ logger: TestSift.logger
328
+ ).generate
329
+ rescue StandardError => e
330
+ TestSift.logger.warn(
331
+ "testsift: coverage.json emit failed (#{e.class}: #{e.message})"
332
+ )
333
+ end
334
+ end
335
+ end
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: testsift
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Sala
8
+ - Abhimanyu Singh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2026-11-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: docile
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.4'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.4'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec-core
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '3.12'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '3.12'
42
+ description: TestSift records the inputs each RSpec example consumes -- using Ruby's
43
+ built-in coverage library plus explicit declarations -- and turns that record into
44
+ a flaky-test detector, a per-example dependency map, and optional CI acceleration
45
+ that skips the examples whose recorded inputs are unchanged. It never skips failed,
46
+ flaky, or pending examples.
47
+ email:
48
+ executables:
49
+ - testsift
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - CHANGELOG.md
54
+ - LICENSE
55
+ - README.md
56
+ - bin/testsift
57
+ - lib/testsift.rb
58
+ - lib/testsift/cache/Rakefile
59
+ - lib/testsift/cli.rb
60
+ - lib/testsift/cli/blast_radius.rb
61
+ - lib/testsift/cli/cache_clear.rb
62
+ - lib/testsift/cli/cache_info.rb
63
+ - lib/testsift/cli/doctor.rb
64
+ - lib/testsift/cli/explain.rb
65
+ - lib/testsift/cli/report_open.rb
66
+ - lib/testsift/cli/snapshot_helpers.rb
67
+ - lib/testsift/configuration.rb
68
+ - lib/testsift/defaults.rb
69
+ - lib/testsift/engine.rb
70
+ - lib/testsift/engine/snapshot_builder.rb
71
+ - lib/testsift/example.rb
72
+ - lib/testsift/filter.rb
73
+ - lib/testsift/line_stub.rb
74
+ - lib/testsift/load_config.rb
75
+ - lib/testsift/load_default_config.rb
76
+ - lib/testsift/load_global_config.rb
77
+ - lib/testsift/load_local_config.rb
78
+ - lib/testsift/logger.rb
79
+ - lib/testsift/rails.rb
80
+ - lib/testsift/rails/README.md
81
+ - lib/testsift/rails/i18n_tracking.rb
82
+ - lib/testsift/rails/notifications.rb
83
+ - lib/testsift/rails/preset.rb
84
+ - lib/testsift/rails/railtie.rb
85
+ - lib/testsift/remote_cache.rb
86
+ - lib/testsift/remote_cache/README.md
87
+ - lib/testsift/remote_cache/Rakefile
88
+ - lib/testsift/remote_cache/archive.rb
89
+ - lib/testsift/remote_cache/backend.rb
90
+ - lib/testsift/remote_cache/git_ancestry.rb
91
+ - lib/testsift/remote_cache/local_fs_backend.rb
92
+ - lib/testsift/remote_cache/redis_backend.rb
93
+ - lib/testsift/remote_cache/s3_backend.rb
94
+ - lib/testsift/remote_cache/user_tasks.rb
95
+ - lib/testsift/remote_cache/validator.rb
96
+ - lib/testsift/reporters/README.md
97
+ - lib/testsift/reporters/base.rb
98
+ - lib/testsift/reporters/coverage_json_reporter.rb
99
+ - lib/testsift/reporters/html/.gitignore
100
+ - lib/testsift/reporters/html/.prettierignore
101
+ - lib/testsift/reporters/html/.prettierrc.json
102
+ - lib/testsift/reporters/html/README.md
103
+ - lib/testsift/reporters/html/dist/assets/index.css
104
+ - lib/testsift/reporters/html/dist/assets/index.js
105
+ - lib/testsift/reporters/html/dist/index.html
106
+ - lib/testsift/reporters/html/eslint.config.js
107
+ - lib/testsift/reporters/html/package-lock.json
108
+ - lib/testsift/reporters/html/package.json
109
+ - lib/testsift/reporters/html/src/app.jsx
110
+ - lib/testsift/reporters/html/src/components/AllExamples.jsx
111
+ - lib/testsift/reporters/html/src/components/DuplicateExamples.jsx
112
+ - lib/testsift/reporters/html/src/components/ExamplesDependency.jsx
113
+ - lib/testsift/reporters/html/src/components/FilesDependency.jsx
114
+ - lib/testsift/reporters/html/src/components/FlakyExamples.jsx
115
+ - lib/testsift/reporters/html/src/components/ReportTable.jsx
116
+ - lib/testsift/reporters/html/src/components/SearchBar.jsx
117
+ - lib/testsift/reporters/html/src/index.html
118
+ - lib/testsift/reporters/html/src/main.jsx
119
+ - lib/testsift/reporters/html/src/styles.css
120
+ - lib/testsift/reporters/html/vite.config.js
121
+ - lib/testsift/reporters/html_reporter.rb
122
+ - lib/testsift/reporters/json_reporter.rb
123
+ - lib/testsift/reporters/payload_builder.rb
124
+ - lib/testsift/reporters/registry.rb
125
+ - lib/testsift/reporters/terminal_reporter.rb
126
+ - lib/testsift/rspec/README.md
127
+ - lib/testsift/rspec/installation.rb
128
+ - lib/testsift/rspec/metadata.rb
129
+ - lib/testsift/rspec/parallel_tests.rb
130
+ - lib/testsift/rspec/rails_setup.rb
131
+ - lib/testsift/rspec/reporter_hook.rb
132
+ - lib/testsift/rspec/runner_hook.rb
133
+ - lib/testsift/source_file.rb
134
+ - lib/testsift/storage/README.md
135
+ - lib/testsift/storage/backend.rb
136
+ - lib/testsift/storage/json_backend.rb
137
+ - lib/testsift/storage/lazy_snapshot.rb
138
+ - lib/testsift/storage/schema.rb
139
+ - lib/testsift/storage/serializer/json.rb
140
+ - lib/testsift/storage/serializer/msgpack.rb
141
+ - lib/testsift/storage/snapshot.rb
142
+ - lib/testsift/storage/sqlite_backend.rb
143
+ - lib/testsift/time_formatter.rb
144
+ - lib/testsift/tracker/README.md
145
+ - lib/testsift/tracker/coverage_adapter.rb
146
+ - lib/testsift/tracker/declared_globs.rb
147
+ - lib/testsift/tracker/dependency_graph.rb
148
+ - lib/testsift/tracker/env_matcher.rb
149
+ - lib/testsift/tracker/env_snapshot.rb
150
+ - lib/testsift/tracker/example_registry.rb
151
+ - lib/testsift/tracker/file_digest.rb
152
+ - lib/testsift/tracker/filter.rb
153
+ - lib/testsift/tracker/input.rb
154
+ - lib/testsift/tracker/io_hooks.rb
155
+ - lib/testsift/tracker/io_hooks/file.rb
156
+ - lib/testsift/tracker/io_hooks/io.rb
157
+ - lib/testsift/tracker/io_hooks/json.rb
158
+ - lib/testsift/tracker/io_hooks/kernel.rb
159
+ - lib/testsift/tracker/io_hooks/yaml.rb
160
+ - lib/testsift/tracker/loaded_files_tracker.rb
161
+ - lib/testsift/tracker/new_file_detector.rb
162
+ - lib/testsift/tracker/whole_suite_invalidators.rb
163
+ - lib/testsift/version.rb
164
+ homepage: https://github.com/salasebas/testsift
165
+ licenses:
166
+ - MIT
167
+ metadata:
168
+ homepage_uri: https://github.com/salasebas/testsift
169
+ source_code_uri: https://github.com/salasebas/testsift/tree/v0.0.1
170
+ changelog_uri: https://github.com/salasebas/testsift/blob/v0.0.1/CHANGELOG.md
171
+ bug_tracker_uri: https://github.com/salasebas/testsift/issues
172
+ rubygems_mfa_required: 'true'
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: 3.1.0
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubygems_version: 3.5.22
189
+ signing_key:
190
+ specification_version: 4
191
+ summary: 'Affected-test selection for RSpec: re-run only the examples whose recorded
192
+ inputs changed, with flaky-test detection and a per-example dependency map.'
193
+ test_files: []