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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE +22 -0
- data/README.md +572 -0
- data/bin/testsift +15 -0
- data/lib/testsift/cache/Rakefile +43 -0
- data/lib/testsift/cli/blast_radius.rb +318 -0
- data/lib/testsift/cli/cache_clear.rb +114 -0
- data/lib/testsift/cli/cache_info.rb +106 -0
- data/lib/testsift/cli/doctor.rb +307 -0
- data/lib/testsift/cli/explain.rb +273 -0
- data/lib/testsift/cli/report_open.rb +90 -0
- data/lib/testsift/cli/snapshot_helpers.rb +119 -0
- data/lib/testsift/cli.rb +219 -0
- data/lib/testsift/configuration.rb +1467 -0
- data/lib/testsift/defaults.rb +11 -0
- data/lib/testsift/engine/snapshot_builder.rb +117 -0
- data/lib/testsift/engine.rb +896 -0
- data/lib/testsift/example.rb +188 -0
- data/lib/testsift/filter.rb +103 -0
- data/lib/testsift/line_stub.rb +62 -0
- data/lib/testsift/load_config.rb +15 -0
- data/lib/testsift/load_default_config.rb +46 -0
- data/lib/testsift/load_global_config.rb +33 -0
- data/lib/testsift/load_local_config.rb +17 -0
- data/lib/testsift/logger.rb +59 -0
- data/lib/testsift/rails/README.md +78 -0
- data/lib/testsift/rails/i18n_tracking.rb +137 -0
- data/lib/testsift/rails/notifications.rb +263 -0
- data/lib/testsift/rails/preset.rb +94 -0
- data/lib/testsift/rails/railtie.rb +22 -0
- data/lib/testsift/rails.rb +15 -0
- data/lib/testsift/remote_cache/README.md +140 -0
- data/lib/testsift/remote_cache/Rakefile +61 -0
- data/lib/testsift/remote_cache/archive.rb +137 -0
- data/lib/testsift/remote_cache/backend.rb +73 -0
- data/lib/testsift/remote_cache/git_ancestry.rb +241 -0
- data/lib/testsift/remote_cache/local_fs_backend.rb +439 -0
- data/lib/testsift/remote_cache/redis_backend.rb +554 -0
- data/lib/testsift/remote_cache/s3_backend.rb +712 -0
- data/lib/testsift/remote_cache/user_tasks.rb +436 -0
- data/lib/testsift/remote_cache/validator.rb +50 -0
- data/lib/testsift/remote_cache.rb +22 -0
- data/lib/testsift/reporters/README.md +103 -0
- data/lib/testsift/reporters/base.rb +87 -0
- data/lib/testsift/reporters/coverage_json_reporter.rb +338 -0
- data/lib/testsift/reporters/html/.gitignore +19 -0
- data/lib/testsift/reporters/html/.prettierignore +4 -0
- data/lib/testsift/reporters/html/.prettierrc.json +9 -0
- data/lib/testsift/reporters/html/README.md +80 -0
- data/lib/testsift/reporters/html/dist/assets/index.css +2 -0
- data/lib/testsift/reporters/html/dist/assets/index.js +1 -0
- data/lib/testsift/reporters/html/dist/index.html +24 -0
- data/lib/testsift/reporters/html/eslint.config.js +62 -0
- data/lib/testsift/reporters/html/package-lock.json +4910 -0
- data/lib/testsift/reporters/html/package.json +29 -0
- data/lib/testsift/reporters/html/src/app.jsx +130 -0
- data/lib/testsift/reporters/html/src/components/AllExamples.jsx +86 -0
- data/lib/testsift/reporters/html/src/components/DuplicateExamples.jsx +68 -0
- data/lib/testsift/reporters/html/src/components/ExamplesDependency.jsx +78 -0
- data/lib/testsift/reporters/html/src/components/FilesDependency.jsx +72 -0
- data/lib/testsift/reporters/html/src/components/FlakyExamples.jsx +42 -0
- data/lib/testsift/reporters/html/src/components/ReportTable.jsx +131 -0
- data/lib/testsift/reporters/html/src/components/SearchBar.jsx +19 -0
- data/lib/testsift/reporters/html/src/index.html +23 -0
- data/lib/testsift/reporters/html/src/main.jsx +37 -0
- data/lib/testsift/reporters/html/src/styles.css +434 -0
- data/lib/testsift/reporters/html/vite.config.js +42 -0
- data/lib/testsift/reporters/html_reporter.rb +266 -0
- data/lib/testsift/reporters/json_reporter.rb +88 -0
- data/lib/testsift/reporters/payload_builder.rb +241 -0
- data/lib/testsift/reporters/registry.rb +120 -0
- data/lib/testsift/reporters/terminal_reporter.rb +264 -0
- data/lib/testsift/rspec/README.md +73 -0
- data/lib/testsift/rspec/installation.rb +97 -0
- data/lib/testsift/rspec/metadata.rb +96 -0
- data/lib/testsift/rspec/parallel_tests.rb +459 -0
- data/lib/testsift/rspec/rails_setup.rb +42 -0
- data/lib/testsift/rspec/reporter_hook.rb +90 -0
- data/lib/testsift/rspec/runner_hook.rb +253 -0
- data/lib/testsift/source_file.rb +56 -0
- data/lib/testsift/storage/README.md +35 -0
- data/lib/testsift/storage/backend.rb +130 -0
- data/lib/testsift/storage/json_backend.rb +884 -0
- data/lib/testsift/storage/lazy_snapshot.rb +65 -0
- data/lib/testsift/storage/schema.rb +50 -0
- data/lib/testsift/storage/serializer/json.rb +41 -0
- data/lib/testsift/storage/serializer/msgpack.rb +167 -0
- data/lib/testsift/storage/snapshot.rb +141 -0
- data/lib/testsift/storage/sqlite_backend.rb +709 -0
- data/lib/testsift/time_formatter.rb +74 -0
- data/lib/testsift/tracker/README.md +36 -0
- data/lib/testsift/tracker/coverage_adapter.rb +180 -0
- data/lib/testsift/tracker/declared_globs.rb +100 -0
- data/lib/testsift/tracker/dependency_graph.rb +134 -0
- data/lib/testsift/tracker/env_matcher.rb +127 -0
- data/lib/testsift/tracker/env_snapshot.rb +77 -0
- data/lib/testsift/tracker/example_registry.rb +153 -0
- data/lib/testsift/tracker/file_digest.rb +61 -0
- data/lib/testsift/tracker/filter.rb +127 -0
- data/lib/testsift/tracker/input.rb +99 -0
- data/lib/testsift/tracker/io_hooks/file.rb +55 -0
- data/lib/testsift/tracker/io_hooks/io.rb +24 -0
- data/lib/testsift/tracker/io_hooks/json.rb +23 -0
- data/lib/testsift/tracker/io_hooks/kernel.rb +26 -0
- data/lib/testsift/tracker/io_hooks/yaml.rb +38 -0
- data/lib/testsift/tracker/io_hooks.rb +195 -0
- data/lib/testsift/tracker/loaded_files_tracker.rb +290 -0
- data/lib/testsift/tracker/new_file_detector.rb +62 -0
- data/lib/testsift/tracker/whole_suite_invalidators.rb +96 -0
- data/lib/testsift/version.rb +7 -0
- data/lib/testsift.rb +335 -0
- metadata +193 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
at_exit do
|
|
4
|
+
# `respond_to?` guards against a crash while `lib/testsift.rb`
|
|
5
|
+
# is still loading (e.g. a corrupt `.testsift` raising at
|
|
6
|
+
# config-load time): this hook registers before the module body
|
|
7
|
+
# that defines `at_exit_behavior` runs, so without the guard the
|
|
8
|
+
# original error would be shadowed by a NoMethodError backtrace
|
|
9
|
+
# from the half-loaded module.
|
|
10
|
+
TestSift.at_exit_behavior if TestSift.respond_to?(:at_exit_behavior)
|
|
11
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TestSift
|
|
4
|
+
class Engine
|
|
5
|
+
module SnapshotBuilder
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# Internal method on the tracer pipeline.
|
|
9
|
+
# @api private
|
|
10
|
+
def build_snapshot
|
|
11
|
+
run_id = Digest::MD5.hexdigest(@all_examples.keys.sort.to_json)
|
|
12
|
+
@run_id = run_id
|
|
13
|
+
|
|
14
|
+
TestSift::Storage::Snapshot.new(
|
|
15
|
+
schema_version: TestSift::Storage::Schema::CURRENT,
|
|
16
|
+
run_id: run_id,
|
|
17
|
+
all_examples: @all_examples,
|
|
18
|
+
duplicate_examples: duplicates_for_snapshot,
|
|
19
|
+
interrupted_examples: @registry.ids_with_status(:interrupted),
|
|
20
|
+
flaky_examples: @registry.ids_with_status(:flaky),
|
|
21
|
+
failed_examples: @registry.ids_with_status(:failed),
|
|
22
|
+
pending_examples: @registry.ids_with_status(:pending),
|
|
23
|
+
skipped_examples: @registry.ids_with_status(:skipped),
|
|
24
|
+
all_files: all_files_by_name,
|
|
25
|
+
dependency: dependency_by_name,
|
|
26
|
+
reverse_dependency: reverse_dependency_by_name,
|
|
27
|
+
examples_coverage: merge_examples_coverage_with_previous,
|
|
28
|
+
boot_set: @loaded_files_tracker.boot_set_digest_snapshot,
|
|
29
|
+
wsi_snapshot: @whole_suite_invalidators.digest_snapshot,
|
|
30
|
+
env_snapshot: env_snapshot_for_persistence,
|
|
31
|
+
env_dependency: env_dependency_for_persistence,
|
|
32
|
+
cache_hit_reason: @filtered_examples.values.tally,
|
|
33
|
+
filtered_examples: @filtered_examples
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Merge the current run's per-example coverage with the previous
|
|
38
|
+
# run's. Re-run examples contribute their freshly-computed map
|
|
39
|
+
# (record_coverage_delta overwrote per-line strengths, so
|
|
40
|
+
# @examples_coverage[id] is the authoritative new coverage).
|
|
41
|
+
# Skipped examples don't appear in @examples_coverage, so the
|
|
42
|
+
# prev map carries them forward unchanged. Previously in
|
|
43
|
+
# seed_state_from_previous; moved here so large caches don't
|
|
44
|
+
# pay the full examples_coverage materialization cost at setup
|
|
45
|
+
# time. Preserves 1.x semantics: the saved map is the union of
|
|
46
|
+
# (prev minus this-run's keys) + this-run's entries.
|
|
47
|
+
def merge_examples_coverage_with_previous
|
|
48
|
+
merged = {}
|
|
49
|
+
if @previous_snapshot
|
|
50
|
+
prev = @previous_snapshot.examples_coverage
|
|
51
|
+
if prev.is_a?(Hash)
|
|
52
|
+
prev.each { |id, cov| merged[id] = cov unless @examples_coverage.key?(id) }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
@examples_coverage.each { |id, cov| merged[id] = cov }
|
|
56
|
+
merged
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Snapshot only the env keys THIS run tracked - persisting keys
|
|
60
|
+
# that stopped being tracked (user removed `tracks: env: ...`
|
|
61
|
+
# between runs) would pin stale digests in the cache. Missing
|
|
62
|
+
# keys on the next load just trigger a one-time re-run for any
|
|
63
|
+
# example that reintroduces them, which is the correct behavior.
|
|
64
|
+
def env_snapshot_for_persistence
|
|
65
|
+
return {} if @env_snapshot.nil? || @tracked_env_names.empty?
|
|
66
|
+
|
|
67
|
+
@env_snapshot.digest_snapshot(@tracked_env_names)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Project the per-example `@tracks_env` map (Set<env_name> per
|
|
71
|
+
# example_id) into a JSON-friendly Hash[id => sorted Array] for
|
|
72
|
+
# persistence. Reporters consume this to render the env-
|
|
73
|
+
# dependency view on the Examples Dependency report. Empty sets
|
|
74
|
+
# drop out so the on-disk map stays narrow. Sort keeps the output
|
|
75
|
+
# deterministic for downstream diffs and golden tests.
|
|
76
|
+
def env_dependency_for_persistence
|
|
77
|
+
result = {}
|
|
78
|
+
@tracks_env.each do |example_id, names|
|
|
79
|
+
next if names.nil? || names.empty?
|
|
80
|
+
|
|
81
|
+
result[example_id] = names.to_a.sort
|
|
82
|
+
end
|
|
83
|
+
result
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Internal method on the tracer pipeline.
|
|
87
|
+
# @api private
|
|
88
|
+
def duplicates_for_snapshot
|
|
89
|
+
@duplicate_examples.select { |_, entries| entries.count > 1 }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Internal method on the tracer pipeline.
|
|
93
|
+
# @api private
|
|
94
|
+
def all_files_by_name
|
|
95
|
+
@all_files.each_with_object({}) do |(_, meta), acc|
|
|
96
|
+
acc[meta[:file_name]] = meta
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Internal method on the tracer pipeline.
|
|
101
|
+
# @api private
|
|
102
|
+
def dependency_by_name
|
|
103
|
+
@graph.example_ids.to_h do |id|
|
|
104
|
+
[id, @graph.paths_for(id).to_set { |p| path_to_file_name(p) }]
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Internal method on the tracer pipeline.
|
|
109
|
+
# @api private
|
|
110
|
+
def reverse_dependency_by_name
|
|
111
|
+
@graph.reverse_dependency_hash.each_with_object({}) do |(path, ids), acc|
|
|
112
|
+
acc[path_to_file_name(path)] = ids.to_set
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|