rspec-tracer 1.2.2 → 2.0.0.pre.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 +4 -4
- data/CHANGELOG.md +197 -45
- data/README.md +439 -429
- data/bin/rspec-tracer +15 -0
- data/lib/rspec_tracer/cache/Rakefile +43 -0
- data/lib/rspec_tracer/cli/cache_clear.rb +98 -0
- data/lib/rspec_tracer/cli/cache_info.rb +103 -0
- data/lib/rspec_tracer/cli/doctor.rb +275 -0
- data/lib/rspec_tracer/cli/explain.rb +148 -0
- data/lib/rspec_tracer/cli/report_open.rb +82 -0
- data/lib/rspec_tracer/cli.rb +116 -0
- data/lib/rspec_tracer/configuration.rb +1100 -3
- data/lib/rspec_tracer/engine.rb +1076 -0
- data/lib/rspec_tracer/example.rb +21 -6
- data/lib/rspec_tracer/filter.rb +35 -0
- data/lib/rspec_tracer/line_stub.rb +61 -0
- data/lib/rspec_tracer/load_config.rb +2 -2
- data/lib/rspec_tracer/logger.rb +15 -0
- data/lib/rspec_tracer/rails/README.md +78 -0
- data/lib/rspec_tracer/rails/i18n_tracking.rb +137 -0
- data/lib/rspec_tracer/rails/notifications.rb +263 -0
- data/lib/rspec_tracer/rails/preset.rb +94 -0
- data/lib/rspec_tracer/rails/railtie.rb +22 -0
- data/lib/rspec_tracer/rails.rb +15 -0
- data/lib/rspec_tracer/remote_cache/README.md +140 -0
- data/lib/rspec_tracer/remote_cache/Rakefile +35 -11
- data/lib/rspec_tracer/remote_cache/archive.rb +137 -0
- data/lib/rspec_tracer/remote_cache/backend.rb +73 -0
- data/lib/rspec_tracer/remote_cache/git_ancestry.rb +241 -0
- data/lib/rspec_tracer/remote_cache/local_fs_backend.rb +439 -0
- data/lib/rspec_tracer/remote_cache/redis_backend.rb +554 -0
- data/lib/rspec_tracer/remote_cache/s3_backend.rb +712 -0
- data/lib/rspec_tracer/remote_cache/user_tasks.rb +397 -0
- data/lib/rspec_tracer/remote_cache/validator.rb +40 -62
- data/lib/rspec_tracer/remote_cache.rb +22 -0
- data/lib/rspec_tracer/reporters/README.md +103 -0
- data/lib/rspec_tracer/reporters/base.rb +87 -0
- data/lib/rspec_tracer/reporters/coverage_json_reporter.rb +338 -0
- data/lib/rspec_tracer/reporters/html/.gitignore +19 -0
- data/lib/rspec_tracer/reporters/html/.prettierignore +4 -0
- data/lib/rspec_tracer/reporters/html/.prettierrc.json +9 -0
- data/lib/rspec_tracer/reporters/html/README.md +80 -0
- data/lib/rspec_tracer/reporters/html/dist/assets/index.css +2 -0
- data/lib/rspec_tracer/reporters/html/dist/assets/index.js +1 -0
- data/lib/rspec_tracer/reporters/html/dist/index.html +24 -0
- data/lib/rspec_tracer/reporters/html/eslint.config.js +62 -0
- data/lib/rspec_tracer/reporters/html/package-lock.json +4941 -0
- data/lib/rspec_tracer/reporters/html/package.json +29 -0
- data/lib/rspec_tracer/reporters/html/src/app.jsx +130 -0
- data/lib/rspec_tracer/reporters/html/src/components/AllExamples.jsx +86 -0
- data/lib/rspec_tracer/reporters/html/src/components/DuplicateExamples.jsx +68 -0
- data/lib/rspec_tracer/reporters/html/src/components/ExamplesDependency.jsx +78 -0
- data/lib/rspec_tracer/reporters/html/src/components/FilesDependency.jsx +72 -0
- data/lib/rspec_tracer/reporters/html/src/components/FlakyExamples.jsx +42 -0
- data/lib/rspec_tracer/reporters/html/src/components/ReportTable.jsx +131 -0
- data/lib/rspec_tracer/reporters/html/src/components/SearchBar.jsx +19 -0
- data/lib/rspec_tracer/reporters/html/src/index.html +23 -0
- data/lib/rspec_tracer/reporters/html/src/main.jsx +37 -0
- data/lib/rspec_tracer/reporters/html/src/styles.css +434 -0
- data/lib/rspec_tracer/reporters/html/vite.config.js +42 -0
- data/lib/rspec_tracer/reporters/html_reporter.rb +266 -0
- data/lib/rspec_tracer/reporters/json_reporter.rb +88 -0
- data/lib/rspec_tracer/reporters/payload_builder.rb +235 -0
- data/lib/rspec_tracer/reporters/registry.rb +120 -0
- data/lib/rspec_tracer/reporters/terminal_reporter.rb +264 -0
- data/lib/rspec_tracer/rspec/README.md +73 -0
- data/lib/rspec_tracer/rspec/installation.rb +97 -0
- data/lib/rspec_tracer/rspec/metadata.rb +96 -0
- data/lib/rspec_tracer/rspec/parallel_tests.rb +459 -0
- data/lib/rspec_tracer/rspec/reporter_hook.rb +84 -0
- data/lib/rspec_tracer/rspec/runner_hook.rb +178 -0
- data/lib/rspec_tracer/source_file.rb +24 -7
- data/lib/rspec_tracer/storage/README.md +35 -0
- data/lib/rspec_tracer/storage/backend.rb +68 -0
- data/lib/rspec_tracer/storage/json_backend.rb +866 -0
- data/lib/rspec_tracer/storage/lazy_snapshot.rb +65 -0
- data/lib/rspec_tracer/storage/schema.rb +43 -0
- data/lib/rspec_tracer/storage/serializer/json.rb +41 -0
- data/lib/rspec_tracer/storage/serializer/msgpack.rb +90 -0
- data/lib/rspec_tracer/storage/snapshot.rb +127 -0
- data/lib/rspec_tracer/storage/sqlite_backend.rb +686 -0
- data/lib/rspec_tracer/time_formatter.rb +37 -18
- data/lib/rspec_tracer/tracker/README.md +36 -0
- data/lib/rspec_tracer/tracker/coverage_adapter.rb +174 -0
- data/lib/rspec_tracer/tracker/declared_globs.rb +100 -0
- data/lib/rspec_tracer/tracker/dependency_graph.rb +134 -0
- data/lib/rspec_tracer/tracker/env_matcher.rb +127 -0
- data/lib/rspec_tracer/tracker/env_snapshot.rb +77 -0
- data/lib/rspec_tracer/tracker/example_registry.rb +153 -0
- data/lib/rspec_tracer/tracker/file_digest.rb +61 -0
- data/lib/rspec_tracer/tracker/filter.rb +127 -0
- data/lib/rspec_tracer/tracker/input.rb +99 -0
- data/lib/rspec_tracer/tracker/io_hooks/file.rb +55 -0
- data/lib/rspec_tracer/tracker/io_hooks/io.rb +24 -0
- data/lib/rspec_tracer/tracker/io_hooks/json.rb +23 -0
- data/lib/rspec_tracer/tracker/io_hooks/kernel.rb +26 -0
- data/lib/rspec_tracer/tracker/io_hooks/yaml.rb +38 -0
- data/lib/rspec_tracer/tracker/io_hooks.rb +195 -0
- data/lib/rspec_tracer/tracker/loaded_files_tracker.rb +295 -0
- data/lib/rspec_tracer/tracker/new_file_detector.rb +62 -0
- data/lib/rspec_tracer/tracker/whole_suite_invalidators.rb +96 -0
- data/lib/rspec_tracer/version.rb +4 -1
- data/lib/rspec_tracer.rb +232 -381
- metadata +93 -43
- data/lib/rspec_tracer/cache.rb +0 -207
- data/lib/rspec_tracer/coverage_merger.rb +0 -42
- data/lib/rspec_tracer/coverage_reporter.rb +0 -187
- data/lib/rspec_tracer/coverage_writer.rb +0 -58
- data/lib/rspec_tracer/html_reporter/Rakefile +0 -18
- data/lib/rspec_tracer/html_reporter/assets/javascripts/application.js +0 -56
- data/lib/rspec_tracer/html_reporter/assets/javascripts/libraries/jquery.js +0 -10881
- data/lib/rspec_tracer/html_reporter/assets/javascripts/plugins/datatables.js +0 -15381
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/application.css +0 -196
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/plugins/datatables.css +0 -459
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/plugins/jquery-ui.css +0 -436
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/print.css +0 -92
- data/lib/rspec_tracer/html_reporter/assets/stylesheets/reset.css +0 -265
- data/lib/rspec_tracer/html_reporter/public/application.css +0 -5
- data/lib/rspec_tracer/html_reporter/public/application.js +0 -6
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_asc.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_asc_disabled.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_both.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_desc.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/datatables/images/sort_desc_disabled.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/favicon.png +0 -0
- data/lib/rspec_tracer/html_reporter/public/loading.gif +0 -0
- data/lib/rspec_tracer/html_reporter/reporter.rb +0 -242
- data/lib/rspec_tracer/html_reporter/views/duplicate_examples.erb +0 -34
- data/lib/rspec_tracer/html_reporter/views/examples.erb +0 -58
- data/lib/rspec_tracer/html_reporter/views/examples_dependency.erb +0 -36
- data/lib/rspec_tracer/html_reporter/views/files_dependency.erb +0 -36
- data/lib/rspec_tracer/html_reporter/views/flaky_examples.erb +0 -38
- data/lib/rspec_tracer/html_reporter/views/layout.erb +0 -38
- data/lib/rspec_tracer/remote_cache/aws.rb +0 -176
- data/lib/rspec_tracer/remote_cache/cache.rb +0 -75
- data/lib/rspec_tracer/remote_cache/repo.rb +0 -210
- data/lib/rspec_tracer/report_generator.rb +0 -158
- data/lib/rspec_tracer/report_merger.rb +0 -68
- data/lib/rspec_tracer/report_writer.rb +0 -141
- data/lib/rspec_tracer/reporter.rb +0 -204
- data/lib/rspec_tracer/rspec_reporter.rb +0 -41
- data/lib/rspec_tracer/rspec_runner.rb +0 -56
- data/lib/rspec_tracer/ruby_coverage.rb +0 -9
- data/lib/rspec_tracer/runner.rb +0 -278
data/README.md
CHANGED
|
@@ -1,498 +1,508 @@
|
|
|
1
|
-
|
|
1
|
+
# rspec-tracer
|
|
2
2
|
|
|
3
|
-
[](https://github.com/avmnu-sng/rspec-tracer/actions/workflows/ci.yml)
|
|
4
4
|
[](https://badge.fury.io/rb/rspec-tracer)
|
|
5
|
-
|
|
6
|
-
](https://codecov.io/gh/avmnu-sng/rspec-tracer)
|
|
6
|
+
[](https://avmnu-sng.github.io/rspec-tracer/)
|
|
7
|
+
|
|
8
|
+
**RSpec Tracer** is a specs dependency analyzer, flaky-test detector,
|
|
9
|
+
test accelerator, and coverage reporter for RSpec. It records the
|
|
10
|
+
inputs every example consumes — Ruby files (via `Coverage`), file
|
|
11
|
+
I/O (via prepended `File` / `IO` / `YAML` / `JSON` hooks), Rails
|
|
12
|
+
template + AR notifications, and user-declared globs — then re-runs
|
|
13
|
+
only the examples whose inputs changed since the last run.
|
|
14
|
+
|
|
15
|
+
It never skips:
|
|
16
|
+
- **Failed**, **flaky**, or **pending** examples.
|
|
17
|
+
- Examples whose dependent inputs changed (the whole point).
|
|
18
|
+
|
|
19
|
+
📚 **Full documentation site**: [avmnu-sng.github.io/rspec-tracer](https://avmnu-sng.github.io/rspec-tracer/) — YARD API reference, sample HTML report, cookbook, and per-version coverage report.
|
|
20
|
+
|
|
21
|
+
For a complete account of the input taxonomy and how the engine fits
|
|
22
|
+
together, read [`ARCHITECTURE.md`](ARCHITECTURE.md).
|
|
23
|
+
|
|
24
|
+
## Table of contents
|
|
25
|
+
|
|
26
|
+
- [Quick start](#quick-start)
|
|
27
|
+
- [How it works](#how-it-works)
|
|
28
|
+
- [Per-example `tracks:` DSL](#per-example-tracks-dsl)
|
|
29
|
+
- [Rails quick start](#rails-quick-start)
|
|
30
|
+
- [Configuring CI](#configuring-ci)
|
|
31
|
+
- [Remote cache backends](#remote-cache-backends)
|
|
32
|
+
- [Pluggable storage](#pluggable-storage)
|
|
33
|
+
- [Command-line tools](#command-line-tools)
|
|
34
|
+
- [SimpleCov interop](#simplecov-interop)
|
|
35
|
+
- [FAQ + comparison](#faq--comparison)
|
|
36
|
+
- [Reports](#reports)
|
|
37
|
+
- [Documentation + coverage](#documentation--coverage)
|
|
38
|
+
- [Help and community](#help-and-community)
|
|
39
|
+
- [Section anchor map (1.x → 2.0)](#section-anchor-map-1x--20)
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
Requires Ruby 3.1+ and rspec-core 3.12+. Rails 7.0+ when using Rails;
|
|
44
|
+
Rails 8.0 needs Ruby 3.2+. JRuby 9.4 is supported.
|
|
45
|
+
|
|
46
|
+
1. Add the gem:
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
# 2.0 is in pre-release. Pin to the pre-release version explicitly;
|
|
50
|
+
# switch to '~> 2.0' once 2.0.0 final ships.
|
|
51
|
+
gem 'rspec-tracer', '= 2.0.0.pre.1', group: :test, require: false
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`bundle install` will resolve the pre-release version. You can
|
|
55
|
+
also install ad-hoc with `gem install rspec-tracer --pre`.
|
|
56
|
+
|
|
57
|
+
2. Add the canonical directories to your `.gitignore`:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
rspec_tracer.lock
|
|
61
|
+
rspec_tracer_cache/
|
|
62
|
+
rspec_tracer_coverage/
|
|
63
|
+
rspec_tracer_report/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
3. Load and start at the very top of `spec_helper.rb` /
|
|
67
|
+
`rails_helper.rb`, **before any application code:**
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
require 'rspec_tracer'
|
|
71
|
+
RSpecTracer.start
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
With SimpleCov, start SimpleCov first (load order is part of the
|
|
75
|
+
contract):
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
require 'simplecov'
|
|
79
|
+
SimpleCov.start
|
|
80
|
+
require 'rspec_tracer'
|
|
81
|
+
RSpecTracer.start
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
4. Run your suite. After the run, open
|
|
85
|
+
`rspec_tracer_report/index.html` for the HTML report, and
|
|
86
|
+
`rspec_tracer_report/report.json` for machine-readable output.
|
|
87
|
+
|
|
88
|
+
The terminal prints a one-line summary with cache size and the
|
|
89
|
+
reasons examples re-ran:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
rspec-tracer: 1,820 examples · 42 re-run · 1,778 skipped (97% cached)
|
|
93
|
+
by reason: 38 Files changed · 4 Failed previously
|
|
94
|
+
cache: rspec_tracer_cache (14.4 MiB; +6.7 KiB vs prev run)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## How it works
|
|
98
|
+
|
|
99
|
+
Every test is a pure function of its inputs; the tracker's job is to
|
|
100
|
+
identify every input and hash it. Inputs come from six buckets:
|
|
101
|
+
|
|
102
|
+
1. **Ruby-executed source** — observed via Ruby's `Coverage` module.
|
|
103
|
+
2. **File I/O** (`File.read`, `YAML.load_file`, etc.) — observed via
|
|
104
|
+
`Module#prepend` hooks.
|
|
105
|
+
3. **Framework events** — Rails template renders + (opt-in) AR
|
|
106
|
+
schema-touching queries via `ActiveSupport::Notifications`.
|
|
107
|
+
4. **Declared globs** — what you tell the tracker to track via
|
|
108
|
+
`track_files` / `tracks:` / `track_rails_defaults`.
|
|
109
|
+
5. **Whole-suite invalidators** — `Gemfile.lock`, `.ruby-version`,
|
|
110
|
+
`.rspec-tracer`, the rspec-tracer gem version itself.
|
|
111
|
+
6. **Truly unobservable inputs** — env-var branches, refinements
|
|
112
|
+
in unexecuted files. Use `track_env` / `tracks: { env: ... }`
|
|
113
|
+
to declare them; the tracker can't auto-detect them.
|
|
114
|
+
|
|
115
|
+
A digest of every observed input is stored per-example. The next run
|
|
116
|
+
loads the cached digest set, recomputes per-input digests, and skips
|
|
117
|
+
examples whose inputs are unchanged.
|
|
118
|
+
|
|
119
|
+
Read [`ARCHITECTURE.md`](ARCHITECTURE.md) for the full layer
|
|
120
|
+
structure (Tracker / Storage / RemoteCache / Reporters), data flows,
|
|
121
|
+
and extension protocols.
|
|
122
|
+
|
|
123
|
+
### Per-example precision under Rails `config.eager_load`
|
|
124
|
+
|
|
125
|
+
A precision tradeoff worth knowing before you run a suite that uses
|
|
126
|
+
Rails:
|
|
127
|
+
|
|
128
|
+
- **`config.eager_load = false`** in test env — per-example precision
|
|
129
|
+
works as designed. Files autoloaded during an example land in
|
|
130
|
+
per-example deps; editing one re-runs only the examples that
|
|
131
|
+
touched it.
|
|
132
|
+
- **`config.eager_load = true`** (Rails default for CI tests to
|
|
133
|
+
mirror prod) — all `app/` files load at boot and land in the
|
|
134
|
+
whole-suite invalidator set. Editing any `app/` file re-runs
|
|
135
|
+
every example. **Safe** (never misses a dep) but **coarser** than
|
|
136
|
+
per-example attribution.
|
|
137
|
+
|
|
138
|
+
If your CI suite runs with `eager_load = true` and your `app/`-edit
|
|
139
|
+
cycle is bottlenecked by whole-suite re-runs, set `config.eager_load
|
|
140
|
+
= false` in test env to recover per-example precision. A future 2.1
|
|
141
|
+
enhancement (working name: `track_class_attribution`) will install
|
|
142
|
+
class-dispatch tracking to trim the invalidator scope under
|
|
143
|
+
eager-loaded test environments — see
|
|
144
|
+
[`CHANGELOG.md`](CHANGELOG.md) "Deferred to 2.1" for the planned
|
|
145
|
+
contract.
|
|
146
|
+
|
|
147
|
+
## Per-example `tracks:` DSL
|
|
148
|
+
|
|
149
|
+
Annotate any describe / context / example with extra inputs the
|
|
150
|
+
tracker can't auto-observe — config files baked at boot, env-var
|
|
151
|
+
branches, non-Ruby deps:
|
|
94
152
|
|
|
95
153
|
```ruby
|
|
96
|
-
|
|
97
|
-
|
|
154
|
+
RSpec.describe AdminController,
|
|
155
|
+
tracks: { files: 'app/policies/**/*.rb',
|
|
156
|
+
env: 'ROLE_CONFIG' } do
|
|
157
|
+
it 'gates on the feature flag' do
|
|
158
|
+
# ...
|
|
159
|
+
end
|
|
160
|
+
end
|
|
98
161
|
```
|
|
99
162
|
|
|
100
|
-
|
|
163
|
+
| Key | Value shape | Semantics |
|
|
164
|
+
|----------|-----------------------------------|------------------------------------------------------------------------|
|
|
165
|
+
| `:files` | String glob OR Array of strings | Each matched file is attached as a `:declared`-kind dep on the example. |
|
|
166
|
+
| `:env` | String name OR Array OR wildcard | Each named env var is digested at finalize. Missing env reads as empty. |
|
|
101
167
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
interrupt the execution in between and the process did not complete correctly.
|
|
106
|
-
In such a case, you must delete the lock file before the next run.
|
|
168
|
+
**Wildcards** (`'RAILS_*'`, `'*_TOKEN'`, `'*'`) expand against the
|
|
169
|
+
live ENV at register time; the persisted snapshot only carries
|
|
170
|
+
concrete keys.
|
|
107
171
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
172
|
+
**Cascade.** Nested groups contribute additively. A parent's
|
|
173
|
+
`tracks: { files: 'a/*' }` and a child's `tracks: { env: 'B' }` both
|
|
174
|
+
attach to the child's examples; the child does not clobber the parent
|
|
175
|
+
on any shared key.
|
|
111
176
|
|
|
112
|
-
|
|
177
|
+
**Use `track_files` / `track_env` for the global case.** Files /
|
|
178
|
+
env vars **every** test depends on (`Gemfile.lock`, `AUTH_TOKEN`,
|
|
179
|
+
`RAILS_ENV`) belong in `.rspec-tracer`:
|
|
113
180
|
|
|
114
|
-
To enable RSpec Tracer to share cache between different builds on CI, update the
|
|
115
|
-
Rakefile in your project to have the following:
|
|
116
|
-
```ruby
|
|
117
|
-
spec = Gem::Specification.find_by_name('rspec-tracer')
|
|
118
|
-
|
|
119
|
-
load "#{spec.gem_dir}/lib/rspec_tracer/remote_cache/Rakefile"
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Before running tests, download the remote cache using the following rake task:
|
|
123
|
-
```sh
|
|
124
|
-
bundle exec rake rspec_tracer:remote_cache:download
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
After running tests, upload the local cache using the following rake task:
|
|
128
|
-
```sh
|
|
129
|
-
bundle exec rake rspec_tracer:remote_cache:upload
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
You must set the following environment variables:
|
|
133
|
-
|
|
134
|
-
- **`GIT_DEFAULT_BRANCH`** is the default branch name for the repo, e.g., `main` or `master`.
|
|
135
|
-
|
|
136
|
-
- **`GIT_BRANCH`** is the git branch name you are running the CI build on.
|
|
137
|
-
|
|
138
|
-
- **`TEST_SUITES`** is the total number of different test suites you are running.
|
|
139
|
-
```sh
|
|
140
|
-
export TEST_SUITES=8
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
- **`TEST_SUITE_ID`** is the CI build ID. If you have a large set of tests to run,
|
|
144
|
-
it is recommended to run them in separate groups. This way, RSpec Tracer is not
|
|
145
|
-
overwhelmed with loading massive cached data in the memory. Also, it generates and
|
|
146
|
-
uses cache for specific test suites and not merge them.
|
|
147
|
-
```sh
|
|
148
|
-
TEST_SUITE_ID=1 bundle exec rspec spec/models
|
|
149
|
-
TEST_SUITE_ID=2 bundle exec rspec spec/helpers
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
- **`USE_TEST_SUITE_ID_CACHE`** (optional, default unset) changes how the remote
|
|
153
|
-
cache validator treats per-suite caches. When set to the exact string `"true"`,
|
|
154
|
-
the validator accepts the current `TEST_SUITE_ID`'s cache independently of the
|
|
155
|
-
other suites' state — so if one suite aborts mid-CI, the remaining suites can
|
|
156
|
-
still reuse their own cached results on the next run. When unset (the default),
|
|
157
|
-
1.1.x behaviour is preserved byte-for-byte: the validator requires every
|
|
158
|
-
`TEST_SUITES` slot to be present before accepting any cache.
|
|
159
|
-
```sh
|
|
160
|
-
export TEST_SUITES=3
|
|
161
|
-
export TEST_SUITE_ID=1
|
|
162
|
-
export USE_TEST_SUITE_ID_CACHE=true
|
|
163
|
-
bundle exec rspec spec/models
|
|
164
|
-
```
|
|
165
|
-
Only the literal string `"true"` activates the flag; `"1"`, `"yes"`, or any
|
|
166
|
-
other truthy value keeps the default behaviour.
|
|
167
|
-
|
|
168
|
-
## Advanced Configuration
|
|
169
|
-
|
|
170
|
-
Configuration settings must be defined in **`.rspec-tracer`** file:
|
|
171
181
|
```ruby
|
|
172
182
|
RSpecTracer.configure do
|
|
173
|
-
|
|
183
|
+
track_files 'config/locales/**/*.yml', 'db/schema.rb', 'Gemfile.lock'
|
|
184
|
+
track_env 'AUTH_TOKEN', 'DATABASE_URL', 'RAILS_*'
|
|
174
185
|
end
|
|
175
186
|
```
|
|
176
187
|
|
|
177
|
-
|
|
178
|
-
common settings across projects.
|
|
179
|
-
|
|
180
|
-
### Available Settings
|
|
181
|
-
|
|
182
|
-
- **`root dir`** to set the project root. The default value is the current working
|
|
183
|
-
directory.
|
|
188
|
+
## Rails quick start
|
|
184
189
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
You can also set the **`RSPEC_TRACER_CACHE_DIR`** environment variable.
|
|
190
|
-
|
|
191
|
-
- **`coverage_dir dir`** to set the coverage reports directory. The default is the
|
|
192
|
-
`./rspec_tracer_coverage`. You can also set the **`RSPEC_TRACER_COVERAGE_DIR`**
|
|
193
|
-
environment variable.
|
|
194
|
-
|
|
195
|
-
- **`report_dir dir`** to set the HTML reports directory. The default is the
|
|
196
|
-
`./rspec_tracer_report`. You can also set the **`RSPEC_TRACER_REPORT_DIR`**
|
|
197
|
-
environment variable.
|
|
198
|
-
|
|
199
|
-
- **`reports_s3_path uri`** to set the AWS S3 URI for all the reports from the current
|
|
200
|
-
run. You can also set the **`RSPEC_TRACER_REPORTS_S3_PATH`** environment variable.
|
|
201
|
-
|
|
202
|
-
- **`use_local_aws bool_flag`** to use the `awslocal` AWS CLI with `LocalStack`. You can
|
|
203
|
-
also set the **`RSPEC_TRACER_USE_LOCAL_AWS`** environment variable.
|
|
204
|
-
|
|
205
|
-
- **`upload_non_ci_reports bool_flag`** to upload execution reports in a non-CI
|
|
206
|
-
environment. You can also set the **`RSPEC_TRACER_UPLOAD_NON_CI_REPORTS`** environment
|
|
207
|
-
variable.
|
|
208
|
-
|
|
209
|
-
- **`run_all_examples bool_flag`** to always run all the examples irrespective of cache.
|
|
210
|
-
You can also set the **`RSPEC_TRACER_RUN_ALL_EXAMPLES`** environment variable.
|
|
211
|
-
|
|
212
|
-
- **`fail_on_duplicates bool_flag`** to fail with a non-zero exit code in case of
|
|
213
|
-
duplicate examples. The default value is `true`. You can also set the **`RSPEC_TRACER_FAIL_ON_DUPLICATES`**
|
|
214
|
-
environment variable.
|
|
215
|
-
|
|
216
|
-
- **`lock_file file`** to set the lock file when executing with `parallel_tests`. The default
|
|
217
|
-
value is `./rspec_tracer.lock`. You can also set the **`RSPEC_TRACER_LOCK_FILE`** environment
|
|
218
|
-
variable.
|
|
219
|
-
|
|
220
|
-
- **`log_level level`** to set the log level. The default value is `info`. The possible
|
|
221
|
-
values are `off`, `debug`, `info`, `warn`, and `error`. You can also set the
|
|
222
|
-
**`RSPEC_TRACER_LOG_LEVEL`** environment variable.
|
|
223
|
-
|
|
224
|
-
- **`add_filter filter`** to apply filters on the source files to exclude them
|
|
225
|
-
from the dependent files list.
|
|
226
|
-
|
|
227
|
-
- **`filters.clear`** to remove the configured dependent files filters so far.
|
|
228
|
-
|
|
229
|
-
- **`add_coverage_filter filter`** to apply filters on the source files to exclude
|
|
230
|
-
them from the coverage report.
|
|
190
|
+
```ruby
|
|
191
|
+
# spec/rails_helper.rb
|
|
192
|
+
require 'simplecov' # if used; load BEFORE rspec_tracer
|
|
193
|
+
SimpleCov.start
|
|
231
194
|
|
|
232
|
-
|
|
195
|
+
require 'rspec_tracer'
|
|
196
|
+
RSpecTracer.start
|
|
233
197
|
|
|
234
|
-
|
|
235
|
-
|
|
198
|
+
require File.expand_path('../config/environment', __dir__)
|
|
199
|
+
require 'rspec/rails'
|
|
200
|
+
```
|
|
236
201
|
|
|
237
202
|
```ruby
|
|
203
|
+
# .rspec-tracer
|
|
238
204
|
RSpecTracer.configure do
|
|
239
|
-
|
|
240
|
-
root '/tmp/my_project'
|
|
241
|
-
|
|
242
|
-
# Clear existing filters
|
|
243
|
-
filters.clear
|
|
244
|
-
# Add dependent files filter
|
|
245
|
-
add_filter %r{^/tasks/}
|
|
246
|
-
|
|
247
|
-
# Clear existing coverage filters
|
|
248
|
-
coverage_filters.clear
|
|
249
|
-
# Add coverage files filter
|
|
250
|
-
add_coverage_filter %w[/features/ /spec/ /tests/]
|
|
251
|
-
|
|
252
|
-
# Define glob to track files in the coverage report
|
|
253
|
-
coverage_track_files '{app,lib}/**/*.rb'
|
|
205
|
+
track_rails_defaults
|
|
254
206
|
end
|
|
255
207
|
```
|
|
256
208
|
|
|
257
|
-
|
|
209
|
+
`track_rails_defaults` attaches the common Rails-side declared globs:
|
|
210
|
+
views, locales, fixtures, factories, helpers, config. Drop a
|
|
211
|
+
specific glob to hand attribution off to the per-example subscribers
|
|
212
|
+
instead:
|
|
258
213
|
|
|
259
|
-
By default, RSpec Tracer ignores all the files outside of the project root directory -
|
|
260
|
-
otherwise you would end up with the source files in the gems you are using in the
|
|
261
|
-
project. It also applies the following filters:
|
|
262
214
|
```ruby
|
|
263
215
|
RSpecTracer.configure do
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
/spec/
|
|
272
|
-
/test/
|
|
273
|
-
/vendor/bundle/
|
|
274
|
-
].freeze
|
|
216
|
+
# Templates → render_template.action_view subscriber attributes
|
|
217
|
+
# them per-example. Schema → opt-in sql.active_record observer
|
|
218
|
+
# attributes db/schema.rb + db/structure.sql per AR-touching
|
|
219
|
+
# example (read the Narrow AR-schema attribution section before
|
|
220
|
+
# enabling).
|
|
221
|
+
track_rails_defaults except: [:views, :schema]
|
|
222
|
+
track_ar_schema_notifications
|
|
275
223
|
end
|
|
276
224
|
```
|
|
277
225
|
|
|
278
|
-
|
|
226
|
+
Supported Rails matrix: 7.0 / 7.1 / 7.2 / 8.0 (8.0 requires Ruby
|
|
227
|
+
3.2+). On JRuby use `JRUBY_OPTS="--debug -X+O"` and the JDBC
|
|
228
|
+
adapter (`gem 'activerecord-jdbcsqlite3-adapter', '~> 71.0',
|
|
229
|
+
platforms: :jruby` for Rails 7.1; track the major to your Rails
|
|
230
|
+
line).
|
|
279
231
|
|
|
280
|
-
|
|
281
|
-
be Regexp-matched against each source file's name relative to the project root),
|
|
282
|
-
a block or by passing in your own Filter class.
|
|
232
|
+
### Narrow AR-schema attribution
|
|
283
233
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
add_filter '/helpers/'
|
|
290
|
-
end
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
- **Regex Filter**: The regex filter removes all files that have a successful name
|
|
294
|
-
match against the given regex expression. This simple regex filter will remove
|
|
295
|
-
all files that start with `%r{^/helper/}` in their name:
|
|
296
|
-
```ruby
|
|
297
|
-
RSpecTracer.configure do
|
|
298
|
-
add_filter %r{^/helpers/}
|
|
299
|
-
end
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
- **Block Filter**: Block filters receive a `Hash` object and expect your block
|
|
303
|
-
to return either **true** (if the file is to be removed from the result) or **false**
|
|
304
|
-
(if the result should be kept). In the below example, the filter will remove all
|
|
305
|
-
files that match `"/helpers/"` in their path.
|
|
306
|
-
```ruby
|
|
307
|
-
RSpecTracer.configure do
|
|
308
|
-
add_filter do |source_file|
|
|
309
|
-
source_file[:file_path].include?('/helpers/')
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
You can also use `source_file[:name]` to define the return value of the block
|
|
315
|
-
filter for the given source file.
|
|
234
|
+
`track_ar_schema_notifications` promises per-example attribution of
|
|
235
|
+
`db/schema.rb` via the `sql.active_record` subscriber. **The narrow
|
|
236
|
+
promise only holds when no per-example AR cleanup mechanism fires
|
|
237
|
+
queries inside the per-example bucket.** Common Rails setups trip
|
|
238
|
+
this:
|
|
316
239
|
|
|
317
|
-
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
end
|
|
322
|
-
```
|
|
240
|
+
- `use_transactional_fixtures = true` (Rails default) — per-example
|
|
241
|
+
BEGIN/COMMIT fires `sql.active_record`.
|
|
242
|
+
- DatabaseCleaner `:truncation` / `:deletion` / `:transaction` in
|
|
243
|
+
`around` hooks — cleanup queries fire inside the bucket.
|
|
323
244
|
|
|
324
|
-
|
|
245
|
+
Either case attributes `db/schema.rb` to every AR-touching example
|
|
246
|
+
(safe, but widens invalidation). A boot-time warn fires when the
|
|
247
|
+
precondition is unmet so you don't discover this from a confused
|
|
248
|
+
cache-hit-rate chart later.
|
|
325
249
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
250
|
+
For genuinely narrow attribution: set `use_transactional_fixtures =
|
|
251
|
+
false` and use sequence-based factories (or another non-AR cleanup
|
|
252
|
+
mechanism that doesn't fire `sql.active_record` inside the example
|
|
253
|
+
window).
|
|
329
254
|
|
|
330
|
-
|
|
331
|
-
- The example full description
|
|
332
|
-
- The spec file location, i.e., file name and line number
|
|
333
|
-
- All the shared examples and contexts
|
|
255
|
+
### Working with parallel_tests
|
|
334
256
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
module_function
|
|
257
|
+
Supported out of the box. The tracker writes to per-worker
|
|
258
|
+
directories and merges at finalize on the elected last worker. If you
|
|
259
|
+
interrupt a run mid-flight, delete the lock file:
|
|
339
260
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
def mul(a, b) a * b; end
|
|
343
|
-
end
|
|
261
|
+
```sh
|
|
262
|
+
rm -f rspec_tracer.lock && bundle exec parallel_rspec
|
|
344
263
|
```
|
|
345
264
|
|
|
346
|
-
|
|
347
|
-
```ruby
|
|
348
|
-
RSpec.describe Calculator do
|
|
349
|
-
describe '#add' do
|
|
350
|
-
[
|
|
351
|
-
[1, 2, 3],
|
|
352
|
-
[0, 0, 0],
|
|
353
|
-
[5, 32, 37],
|
|
354
|
-
[-1, -8, -9],
|
|
355
|
-
[10, -10, 0]
|
|
356
|
-
].each { |a, b, r| it { expect(described_class.add(a, b)).to eq(r) } }
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
describe '#sub' do
|
|
360
|
-
[
|
|
361
|
-
[1, 2, -1],
|
|
362
|
-
[10, 0, 10],
|
|
363
|
-
[37, 5, 32],
|
|
364
|
-
[-1, -8, 7],
|
|
365
|
-
[10, 10, 0]
|
|
366
|
-
].each do |a, b, r|
|
|
367
|
-
it 'performs subtraction' do
|
|
368
|
-
expect(described_class.sub(a, b)).to eq(r)
|
|
369
|
-
end
|
|
370
|
-
end
|
|
371
|
-
end
|
|
265
|
+
## Configuring CI
|
|
372
266
|
|
|
373
|
-
|
|
374
|
-
[
|
|
375
|
-
[1, 2, -2],
|
|
376
|
-
[10, 0, 0],
|
|
377
|
-
[5, 7, 35],
|
|
378
|
-
[-1, -8, 8],
|
|
379
|
-
[10, 10, 100]
|
|
380
|
-
].each do |a, b, r|
|
|
381
|
-
it "multiplies #{a} and #{b} to #{r}" do
|
|
382
|
-
expect(described_class.mul(a, b)).to eq(r)
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
end
|
|
387
|
-
```
|
|
267
|
+
The 1.x flow is preserved bit-for-bit. In your project's `Rakefile`:
|
|
388
268
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
Calculator
|
|
393
|
-
#mul
|
|
394
|
-
multiplies 5 and 7 to 35
|
|
395
|
-
multiplies 10 and 10 to 100
|
|
396
|
-
multiplies 10 and 0 to 0
|
|
397
|
-
multiplies 1 and 2 to -2 (FAILED - 1)
|
|
398
|
-
multiplies -1 and -8 to 8
|
|
399
|
-
#add
|
|
400
|
-
example at ./spec/calculator_spec.rb:13
|
|
401
|
-
example at ./spec/calculator_spec.rb:13
|
|
402
|
-
example at ./spec/calculator_spec.rb:13
|
|
403
|
-
example at ./spec/calculator_spec.rb:13
|
|
404
|
-
example at ./spec/calculator_spec.rb:13
|
|
405
|
-
#sub
|
|
406
|
-
performs subtraction
|
|
407
|
-
performs subtraction
|
|
408
|
-
performs subtraction
|
|
409
|
-
performs subtraction
|
|
410
|
-
performs subtraction
|
|
269
|
+
```ruby
|
|
270
|
+
spec = Gem::Specification.find_by_name('rspec-tracer')
|
|
271
|
+
load "#{spec.gem_dir}/lib/rspec_tracer/remote_cache/Rakefile"
|
|
411
272
|
```
|
|
412
273
|
|
|
413
|
-
|
|
414
|
-
`Calculator#sub` group examples.
|
|
274
|
+
Then in your CI pipeline:
|
|
415
275
|
|
|
276
|
+
```sh
|
|
277
|
+
bundle exec rake rspec_tracer:remote_cache:download
|
|
278
|
+
bundle exec rspec
|
|
279
|
+
bundle exec rake rspec_tracer:remote_cache:upload
|
|
416
280
|
```
|
|
417
|
-
================================================================================
|
|
418
|
-
IMPORTANT NOTICE -- RSPEC TRACER COULD NOT IDENTIFY SOME EXAMPLES UNIQUELY
|
|
419
|
-
================================================================================
|
|
420
|
-
RSpec tracer could not uniquely identify the following 10 examples:
|
|
421
|
-
- Example ID: eabd51a899db4f64d5839afe96004f03 (5 examples)
|
|
422
|
-
* Calculator#add (spec/calculator_spec.rb:13)
|
|
423
|
-
* Calculator#add (spec/calculator_spec.rb:13)
|
|
424
|
-
* Calculator#add (spec/calculator_spec.rb:13)
|
|
425
|
-
* Calculator#add (spec/calculator_spec.rb:13)
|
|
426
|
-
* Calculator#add (spec/calculator_spec.rb:13)
|
|
427
|
-
- Example ID: 72171b502c5a42b9aa133f165cf09ec2 (5 examples)
|
|
428
|
-
* Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
|
|
429
|
-
* Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
|
|
430
|
-
* Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
|
|
431
|
-
* Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
|
|
432
|
-
* Calculator#sub performs subtraction (spec/calculator_spec.rb:24)
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
## Demo
|
|
436
|
-
|
|
437
|
-
**First Run**
|
|
438
|
-

|
|
439
|
-
|
|
440
|
-
**Next Run**
|
|
441
|
-

|
|
442
|
-
|
|
443
|
-
You get the following three reports:
|
|
444
|
-
|
|
445
|
-
### All Examples Report
|
|
446
281
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
282
|
+
With these env vars:
|
|
283
|
+
|
|
284
|
+
- **`GIT_DEFAULT_BRANCH`** — your repo's default branch (`main` /
|
|
285
|
+
`master`).
|
|
286
|
+
- **`GIT_BRANCH`** — the branch the build is on.
|
|
287
|
+
- **`TEST_SUITES`** — total number of suite shards (when sharding).
|
|
288
|
+
- **`TEST_SUITE_ID`** — current shard identifier.
|
|
289
|
+
- **`RSPEC_TRACER_REMOTE_CACHE_URI`** — the remote-cache URI
|
|
290
|
+
(`s3://bucket/prefix`, `file:///tmp/cache`, `redis://host`).
|
|
291
|
+
|
|
292
|
+
### Caching rspec-tracer in CI
|
|
293
|
+
|
|
294
|
+
If you don't have S3 — or only need cache between runs of a single
|
|
295
|
+
workflow — GitHub Actions' built-in cache is a drop-in storage
|
|
296
|
+
substrate. Restore `rspec_tracer_cache/` before specs, run the
|
|
297
|
+
suite, let the post-step save it back. A reference workflow lives at
|
|
298
|
+
[`.github/workflows/example-tracer-cache.yml`](.github/workflows/example-tracer-cache.yml).
|
|
299
|
+
The cache step:
|
|
300
|
+
|
|
301
|
+
```yaml
|
|
302
|
+
- name: Restore rspec-tracer cache
|
|
303
|
+
uses: actions/cache@v5
|
|
304
|
+
with:
|
|
305
|
+
path: rspec_tracer_cache
|
|
306
|
+
key: >-
|
|
307
|
+
${{ runner.os
|
|
308
|
+
}}-${{ hashFiles('.ruby-version')
|
|
309
|
+
}}-${{ hashFiles('Gemfile.lock')
|
|
310
|
+
}}-rspec-tracer-cache
|
|
311
|
+
restore-keys: |
|
|
312
|
+
${{ runner.os }}-${{ hashFiles('.ruby-version') }}-
|
|
313
|
+
${{ runner.os }}-
|
|
314
|
+
```
|
|
454
315
|
|
|
455
|
-
|
|
316
|
+
The 4-component cache key (`runner.os` + Ruby version + the
|
|
317
|
+
rspec-tracer gem's own version + your project's Gemfile lock)
|
|
318
|
+
invalidates when something would make the previous run's decisions
|
|
319
|
+
incorrect: native gem binaries differ across runner OSes, Ruby ABI
|
|
320
|
+
changes invalidate native extensions, a tracer upgrade can change the
|
|
321
|
+
cache schema, and gem-set drift is the most common cache-staleness
|
|
322
|
+
trigger.
|
|
456
323
|
|
|
457
|
-
|
|
324
|
+
**The pattern translates 1:1 to CircleCI, GitLab CI, Buildkite, and
|
|
325
|
+
Heroku CI**; only the YAML envelope is GHA-specific. See
|
|
326
|
+
[`docs/CI_RECIPES.md`](docs/CI_RECIPES.md) for per-provider recipes.
|
|
458
327
|
|
|
459
|
-
|
|
328
|
+
## Remote cache backends
|
|
460
329
|
|
|
461
|
-
|
|
330
|
+
Three backends ship in 2.0. Pick one in `.rspec-tracer`:
|
|
462
331
|
|
|
463
|
-
|
|
332
|
+
```ruby
|
|
333
|
+
RSpecTracer.configure do
|
|
334
|
+
# S3 (preserves 1.x layout; supports awslocal / LocalStack).
|
|
335
|
+
remote_cache_backend :s3, local: false
|
|
464
336
|
|
|
465
|
-
|
|
466
|
-
|
|
337
|
+
# Filesystem-backed (no S3 needed).
|
|
338
|
+
# remote_cache_backend :local_fs, root: '/tmp/rspec-tracer-cache'
|
|
467
339
|
|
|
468
|
-
|
|
340
|
+
# Redis (with optional per-key TTL + PR-branch tracking sidecar).
|
|
341
|
+
# remote_cache_backend :redis, url: ENV['REDIS_URL'], ttl: 7 * 86_400
|
|
342
|
+
end
|
|
343
|
+
```
|
|
469
344
|
|
|
470
|
-
|
|
345
|
+
The `rake rspec_tracer:remote_cache:*` task surface is unchanged —
|
|
346
|
+
backend selection happens in config; the rake tasks dispatch
|
|
347
|
+
identically.
|
|
471
348
|
|
|
472
|
-
|
|
349
|
+
## Pluggable storage
|
|
473
350
|
|
|
474
|
-
|
|
351
|
+
Two on-disk storage formats:
|
|
475
352
|
|
|
476
|
-
|
|
353
|
+
```ruby
|
|
354
|
+
RSpecTracer.configure do
|
|
355
|
+
# JSON (default) — preserves the 1.x 10-file layout per run.
|
|
356
|
+
storage_backend :json
|
|
477
357
|
|
|
478
|
-
|
|
358
|
+
# SQLite — single-file database. Faster cold reads above ~5,000
|
|
359
|
+
# examples. JRuby auto-falls-back to :json with a one-time warn.
|
|
360
|
+
# storage_backend :sqlite
|
|
361
|
+
end
|
|
362
|
+
```
|
|
479
363
|
|
|
480
|
-
|
|
364
|
+
Or override per-run via env: `RSPEC_TRACER_STORAGE=sqlite`.
|
|
481
365
|
|
|
482
|
-
|
|
366
|
+
## Command-line tools
|
|
483
367
|
|
|
484
|
-
|
|
368
|
+
`bin/rspec-tracer` exposes five sub-commands:
|
|
485
369
|
|
|
486
|
-
|
|
370
|
+
```sh
|
|
371
|
+
bin/rspec-tracer doctor # diagnose config + environment
|
|
372
|
+
bin/rspec-tracer cache:info # size, last run, invalidation stats
|
|
373
|
+
bin/rspec-tracer cache:clear # rm cache dirs
|
|
374
|
+
bin/rspec-tracer report:open # open the HTML report
|
|
375
|
+
bin/rspec-tracer explain <id> # why is <example_id> scheduled to (re-)run?
|
|
376
|
+
```
|
|
487
377
|
|
|
488
|
-
|
|
378
|
+
The CLI is opt-in for local-dev convenience. The
|
|
379
|
+
`rake rspec_tracer:remote_cache:*` tasks remain first-class for CI
|
|
380
|
+
integration — nothing in the CLI replaces them.
|
|
489
381
|
|
|
490
|
-
|
|
382
|
+
## SimpleCov interop
|
|
491
383
|
|
|
492
|
-
|
|
384
|
+
**Load order is part of the contract.** SimpleCov first, then
|
|
385
|
+
rspec-tracer:
|
|
493
386
|
|
|
494
|
-
|
|
387
|
+
```ruby
|
|
388
|
+
require 'simplecov'
|
|
389
|
+
SimpleCov.start
|
|
495
390
|
|
|
496
|
-
|
|
391
|
+
require 'rspec_tracer'
|
|
392
|
+
RSpecTracer.start
|
|
393
|
+
```
|
|
497
394
|
|
|
498
|
-
|
|
395
|
+
If you call `require 'simplecov'` but skip `SimpleCov.start` before
|
|
396
|
+
`RSpecTracer.start`, a boot-time warn fires pointing this out
|
|
397
|
+
(silent-degradation breaks coverage output).
|
|
398
|
+
|
|
399
|
+
**Branch coverage works alongside rspec-tracer in 2.0.** The 1.x
|
|
400
|
+
caveat ("SimpleCov would not report branch coverage results even
|
|
401
|
+
when enabled") is no longer applicable — the coverage emission
|
|
402
|
+
decoupled from SimpleCov's branch-tracking. Re-enable
|
|
403
|
+
`enable_coverage :branch` in your `SimpleCov.start` block and you get
|
|
404
|
+
both.
|
|
405
|
+
|
|
406
|
+
Filter chains compose: SimpleCov's `add_filter` / `coverage_filters`
|
|
407
|
+
control SimpleCov's HTML output; rspec-tracer's `add_filter` /
|
|
408
|
+
`add_coverage_filter` control which files contribute to the
|
|
409
|
+
dependency graph.
|
|
410
|
+
|
|
411
|
+
## FAQ + comparison
|
|
412
|
+
|
|
413
|
+
**Why not just SimpleCov filtering?** SimpleCov tells you which
|
|
414
|
+
*files* are covered. rspec-tracer tells you which *examples* depend
|
|
415
|
+
on which inputs, so it can skip the ones whose inputs didn't change.
|
|
416
|
+
The two solve adjacent problems; you typically want both.
|
|
417
|
+
|
|
418
|
+
**Knapsack / Knapsack Pro / Test Boosters?** Those are test-splitting
|
|
419
|
+
tools — they shard your suite across CI workers. rspec-tracer is
|
|
420
|
+
orthogonal: it skips already-passing examples on a single worker.
|
|
421
|
+
Compose them: shard with Knapsack, then skip with rspec-tracer.
|
|
422
|
+
A composition smoke spec (`spec/regressions/knapsack_coexistence_spec.rb`)
|
|
423
|
+
proves they coexist.
|
|
424
|
+
|
|
425
|
+
**`RSpec::Retry` / `RSpec::Rerun`?** Retries flaky failures.
|
|
426
|
+
rspec-tracer detects flaky examples (same inputs, different outcomes)
|
|
427
|
+
and refuses to skip them on the next run. Compose: retry to make a
|
|
428
|
+
flaky suite green, let rspec-tracer flag the flakes for you to
|
|
429
|
+
actually fix.
|
|
430
|
+
|
|
431
|
+
**Monorepo with N apps?** Set per-app `cache_dir` in each app's
|
|
432
|
+
`.rspec-tracer` (the default `rspec_tracer_cache/` would otherwise
|
|
433
|
+
collide across apps).
|
|
434
|
+
|
|
435
|
+
**`tracks:` vs `track_rails_defaults` overlap?** When both attribute
|
|
436
|
+
the same file to an example, the declared-glob attribution wins.
|
|
437
|
+
Deterministic; see [`ARCHITECTURE.md`](ARCHITECTURE.md) "Input
|
|
438
|
+
taxonomy" for the rule.
|
|
439
|
+
|
|
440
|
+
## Reports
|
|
441
|
+
|
|
442
|
+
After the run, `rspec_tracer_report/index.html` opens five HTML
|
|
443
|
+
reports:
|
|
444
|
+
|
|
445
|
+
- **All Examples** — basic test info (id, status, duration, the inputs
|
|
446
|
+
the example consumed).
|
|
447
|
+
- **Duplicate Examples** — pairs RSpec couldn't uniquely identify
|
|
448
|
+
(file:line collisions; only appears when duplicates are present).
|
|
449
|
+
- **Flaky Examples** — examples that passed after previously failing
|
|
450
|
+
without any dependency change. The tracker refuses to skip these
|
|
451
|
+
on subsequent runs.
|
|
452
|
+
- **Examples Dependency** — per-example file dependency lists; the
|
|
453
|
+
"what does this test depend on?" view.
|
|
454
|
+
- **Files Dependency** — the inverse: "what tests run if I change
|
|
455
|
+
this file?" The unique-to-rspec-tracer report that makes refactors
|
|
456
|
+
safer.
|
|
457
|
+
|
|
458
|
+
Plus a machine-readable `rspec_tracer_report/report.json` for CI
|
|
459
|
+
dashboards and the terminal one-liner shown in [Quick start](#quick-start).
|
|
460
|
+
|
|
461
|
+
## Documentation + coverage
|
|
462
|
+
|
|
463
|
+
- **Docs site**: [avmnu-sng.github.io/rspec-tracer](https://avmnu-sng.github.io/rspec-tracer/)
|
|
464
|
+
publishes a YARD API reference, the cookbook, internals deep-dives,
|
|
465
|
+
and the sample HTML report for every rolling main + tagged release.
|
|
466
|
+
The landing page lets you switch versions; per-version subpaths look
|
|
467
|
+
like `/main/yard/`, `/main/demo/`, `/v2.0.0.pre.1/yard/`, etc.
|
|
468
|
+
|
|
469
|
+
- **Coverage**: tracked by [Codecov](https://codecov.io/gh/avmnu-sng/rspec-tracer)
|
|
470
|
+
(per-PR delta + diff-coverage gate ≥ 90%; project history). Multi-
|
|
471
|
+
suite resultsets (`unit`, `edge-cases`, `regressions-plain`, `fuzz`)
|
|
472
|
+
merge via SimpleCov.collate in the CI `coverage` job; the same
|
|
473
|
+
merger runs locally via `task coverage:merge` after `task test:*`
|
|
474
|
+
runs (open `coverage/index.html` for the local HTML report).
|
|
475
|
+
|
|
476
|
+
## Help and community
|
|
477
|
+
|
|
478
|
+
- **Bug reports + feature requests** — [GitHub Issues](https://github.com/avmnu-sng/rspec-tracer/issues).
|
|
479
|
+
Include Ruby / Rails / RSpec / SimpleCov versions and your
|
|
480
|
+
`.rspec-tracer` config.
|
|
481
|
+
- **Usage questions, design discussion, "how do I X?"** — [GitHub Discussions](https://github.com/avmnu-sng/rspec-tracer/discussions).
|
|
482
|
+
- **Roadmap** — [`ROADMAP.md`](ROADMAP.md) at repo root + the live
|
|
483
|
+
[project board](https://github.com/users/avmnu-sng/projects).
|
|
484
|
+
- **Architecture deep-dive** — [`ARCHITECTURE.md`](ARCHITECTURE.md).
|
|
485
|
+
- **Upgrading from 1.x** — [`UPGRADING.md`](UPGRADING.md).
|
|
486
|
+
- **Contributing** — [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md).
|
|
487
|
+
|
|
488
|
+
Released under the [MIT License](LICENSE). Everyone interacting in
|
|
489
|
+
the project is expected to follow the
|
|
490
|
+
[Code of Conduct](.github/CODE_OF_CONDUCT.md).
|
|
491
|
+
|
|
492
|
+
## Section anchor map (1.x → 2.0)
|
|
493
|
+
|
|
494
|
+
The README was restructured in 2.0. If you bookmarked a 1.x section,
|
|
495
|
+
here's where its content lives now:
|
|
496
|
+
|
|
497
|
+
| 1.x anchor | 2.0 anchor |
|
|
498
|
+
|---------------------------------------|---------------------------------------------------------|
|
|
499
|
+
| `#getting-started` | [Quick start](#quick-start) |
|
|
500
|
+
| `#working-with-jruby` | [Quick start](#quick-start) (JRuby noted under floors in [`UPGRADING.md`](UPGRADING.md)) |
|
|
501
|
+
| `#working-with-parallel-tests` | [Working with parallel_tests](#working-with-parallel_tests) under Rails quick start |
|
|
502
|
+
| `#configuring-ci` | [Configuring CI](#configuring-ci) |
|
|
503
|
+
| `#caching-rspec-tracer-in-ci` | [Caching rspec-tracer in CI](#caching-rspec-tracer-in-ci) |
|
|
504
|
+
| `#advanced-configuration` | Split between [Per-example `tracks:` DSL](#per-example-tracks-dsl), [Pluggable storage](#pluggable-storage), and [`UPGRADING.md`](UPGRADING.md) |
|
|
505
|
+
| `#available-settings` | Inline across the new sections; see also [`ARCHITECTURE.md`](ARCHITECTURE.md) |
|
|
506
|
+
| `#filters` | Inline under [SimpleCov interop](#simplecov-interop) and the configuration DSL examples |
|
|
507
|
+
| `#duplicate-examples` | [Reports](#reports) under "Duplicate Examples" |
|
|
508
|
+
| `#demo` | [Reports](#reports) |
|