ripple_effect 0.1.0
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/.ripple-effect.yml.example +56 -0
- data/ARCHITECTURE.md +222 -0
- data/CHANGELOG.md +115 -0
- data/CODE_OF_CONDUCT.md +64 -0
- data/CONTRIBUTING.md +112 -0
- data/LICENSE.txt +21 -0
- data/README.md +305 -0
- data/SECURITY.md +73 -0
- data/docs/ANALYSIS_MODEL.md +275 -0
- data/docs/CLI.md +276 -0
- data/docs/CONFIGURATION.md +178 -0
- data/docs/DECISIONS.md +210 -0
- data/docs/PUBLIC_LAUNCH_CHECKLIST.md +105 -0
- data/docs/RELEASING.md +94 -0
- data/docs/TESTING.md +179 -0
- data/exe/ripple-effect +7 -0
- data/lib/ripple_effect/analyzer.rb +379 -0
- data/lib/ripple_effect/cache_store.rb +207 -0
- data/lib/ripple_effect/cli/application.rb +126 -0
- data/lib/ripple_effect/cli/command.rb +165 -0
- data/lib/ripple_effect/cli/diff_command.rb +76 -0
- data/lib/ripple_effect/cli/doctor_command.rb +106 -0
- data/lib/ripple_effect/cli/graph_command.rb +61 -0
- data/lib/ripple_effect/cli/inspect_command.rb +66 -0
- data/lib/ripple_effect/cli/tests_command.rb +109 -0
- data/lib/ripple_effect/cli/version_command.rb +46 -0
- data/lib/ripple_effect/confidence.rb +61 -0
- data/lib/ripple_effect/configuration.rb +264 -0
- data/lib/ripple_effect/diagnostic.rb +90 -0
- data/lib/ripple_effect/diff/changed_symbol_resolver.rb +292 -0
- data/lib/ripple_effect/diff/git.rb +175 -0
- data/lib/ripple_effect/diff/hunk.rb +80 -0
- data/lib/ripple_effect/edge.rb +114 -0
- data/lib/ripple_effect/error.rb +23 -0
- data/lib/ripple_effect/extractors/base.rb +292 -0
- data/lib/ripple_effect/extractors/rails_associations.rb +102 -0
- data/lib/ripple_effect/extractors/rails_callbacks.rb +144 -0
- data/lib/ripple_effect/extractors/rails_delegation.rb +121 -0
- data/lib/ripple_effect/extractors/rails_jobs.rb +131 -0
- data/lib/ripple_effect/extractors/rails_mailers.rb +120 -0
- data/lib/ripple_effect/extractors/rails_routes.rb +256 -0
- data/lib/ripple_effect/extractors/rails_views.rb +299 -0
- data/lib/ripple_effect/extractors/ruby_structure.rb +221 -0
- data/lib/ripple_effect/extractors/test_conventions.rb +135 -0
- data/lib/ripple_effect/formatters/dot.rb +69 -0
- data/lib/ripple_effect/formatters/json.rb +43 -0
- data/lib/ripple_effect/formatters/text.rb +197 -0
- data/lib/ripple_effect/graph.rb +199 -0
- data/lib/ripple_effect/node.rb +153 -0
- data/lib/ripple_effect/project.rb +264 -0
- data/lib/ripple_effect/result.rb +147 -0
- data/lib/ripple_effect/risk.rb +167 -0
- data/lib/ripple_effect/static_index/adapter.rb +84 -0
- data/lib/ripple_effect/static_index/rubydex_adapter.rb +356 -0
- data/lib/ripple_effect/traversal/impact_walker.rb +153 -0
- data/lib/ripple_effect/version.rb +11 -0
- data/lib/ripple_effect.rb +89 -0
- metadata +155 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Public launch checklist
|
|
2
|
+
|
|
3
|
+
RippleEffect v0.1 is a **private build**. Work through this before making the
|
|
4
|
+
repository public or pushing to RubyGems.
|
|
5
|
+
|
|
6
|
+
## 1. Name verification: do this first
|
|
7
|
+
|
|
8
|
+
Everything else is wasted if the name is taken.
|
|
9
|
+
|
|
10
|
+
- [ ] **RubyGems:** `gem owner ripple_effect` / check
|
|
11
|
+
`https://rubygems.org/gems/ripple_effect` returns 404. A registry lookup is
|
|
12
|
+
authoritative; a web search is not.
|
|
13
|
+
*(As of this build, `gem search -r ripple_effect` returns no results: but
|
|
14
|
+
re-verify immediately before reserving, and reserve the name promptly.)*
|
|
15
|
+
- [ ] **GitHub:** the `ripple-effect` org or repo name is available.
|
|
16
|
+
- [ ] **Existing tools:** search for other developer tools called "Ripple Effect"
|
|
17
|
+
or similar, in Ruby and beyond, to avoid a confusing collision.
|
|
18
|
+
- [ ] **Trademark:** a basic search for conflicting marks in the software class.
|
|
19
|
+
- [ ] **Domain and social handles**, if you want them.
|
|
20
|
+
- [ ] Reserve the gem name with a `0.0.1` placeholder push once verified.
|
|
21
|
+
|
|
22
|
+
Update every reference if the name changes: gemspec, `lib/ripple_effect/`,
|
|
23
|
+
`exe/ripple-effect`, `.ripple-effect.yml`, module name, docs, and the
|
|
24
|
+
`tmp/ripple_effect/` cache directory.
|
|
25
|
+
|
|
26
|
+
## 2. Correctness and quality
|
|
27
|
+
|
|
28
|
+
Verified locally on macOS (arm64) at the time of writing:
|
|
29
|
+
|
|
30
|
+
- [x] `bundle exec rake` green. 435 examples, 0 failures.
|
|
31
|
+
- [x] `bundle exec rake smoke` green. 9 checks.
|
|
32
|
+
- [x] Suite green on Ruby 3.2.8, 3.3.10 and 3.4.7.
|
|
33
|
+
- [x] Rails matrix green with Rails **actually installed**: 7.0.10, 7.1.6,
|
|
34
|
+
7.2.3.2, 8.0.5.1, 8.1.3.1.
|
|
35
|
+
- [x] `gem build` emits zero warnings.
|
|
36
|
+
- [x] Coverage above the bar. 95.9% line, 78.7% branch.
|
|
37
|
+
- [x] No `TODO`, `FIXME` or stub for anything v0.1 promises.
|
|
38
|
+
- [x] Run against **real, large** Rails applications. Six were checked: lobsters,
|
|
39
|
+
rubygems.org, Solidus, Mastodon, and two private production apps. None
|
|
40
|
+
crashed; none reported an analysis error. `script/ground_truth.rb` found
|
|
41
|
+
**zero false positives across 18 heavily-referenced symbols**.
|
|
42
|
+
|
|
43
|
+
Still to do on real CI hardware:
|
|
44
|
+
|
|
45
|
+
- [ ] Confirm the same matrix is green on GitHub Actions (it has never run
|
|
46
|
+
there: the repository has no remote yet).
|
|
47
|
+
- [ ] Check behaviour on Linux and Windows. Only macOS has been exercised, and
|
|
48
|
+
the case-insensitivity bug found during validation was platform-specific.
|
|
49
|
+
|
|
50
|
+
## 3. Documentation
|
|
51
|
+
|
|
52
|
+
- [ ] Every command in `README.md` and `docs/CLI.md` produces the output shown.
|
|
53
|
+
- [ ] Limitations are stated plainly and prominently.
|
|
54
|
+
- [ ] Comparisons to Packwerk, Enola and test-selection tools are accurate,
|
|
55
|
+
respectful, and make no unverified superiority claim.
|
|
56
|
+
- [ ] `CHANGELOG.md` has a dated `0.1.0` entry.
|
|
57
|
+
- [ ] The JSON contract is documented with its schema version.
|
|
58
|
+
- [ ] Rubydex and Prism are credited, with their licenses acknowledged.
|
|
59
|
+
- [ ] No private paths, usernames, internal hostnames or secrets anywhere in the
|
|
60
|
+
repository, including fixtures and spec output.
|
|
61
|
+
|
|
62
|
+
## 4. Repository setup
|
|
63
|
+
|
|
64
|
+
- [ ] `LICENSE.txt` (MIT) present.
|
|
65
|
+
- [ ] `CODE_OF_CONDUCT.md`, `CONTRIBUTING.md`, `SECURITY.md` present.
|
|
66
|
+
- [ ] Issue templates and a PR template present.
|
|
67
|
+
- [ ] Branch protection on `main`; required status checks.
|
|
68
|
+
- [ ] **GitHub Actions permissions minimised**, `permissions: contents: read` at
|
|
69
|
+
the workflow level, raised only where a job needs more.
|
|
70
|
+
- [ ] No secrets configured that are not yet needed. In particular,
|
|
71
|
+
`release.yml.example` stays disabled until publishing is decided.
|
|
72
|
+
- [ ] Private vulnerability reporting **enabled**, and the placeholder URL in
|
|
73
|
+
`SECURITY.md` replaced with the real advisory link.
|
|
74
|
+
- [ ] Repository description and topics set (`ruby`, `rails`, `static-analysis`,
|
|
75
|
+
`impact-analysis`, `developer-tools`).
|
|
76
|
+
|
|
77
|
+
## 5. Release mechanics
|
|
78
|
+
|
|
79
|
+
- [ ] RubyGems account has **MFA enabled** (the gemspec requires it).
|
|
80
|
+
- [ ] Decided: manual push, or trusted publishing via OIDC. Prefer OIDC over a
|
|
81
|
+
long-lived API key.
|
|
82
|
+
- [ ] A signed tag for the release.
|
|
83
|
+
- [ ] Release notes drafted from the changelog.
|
|
84
|
+
|
|
85
|
+
## 6. Claims to double-check
|
|
86
|
+
|
|
87
|
+
RippleEffect's value is that people can trust what it says. The same standard
|
|
88
|
+
applies to how it is described.
|
|
89
|
+
|
|
90
|
+
- [ ] **No benchmark number is quoted anywhere unless it was measured**, with the
|
|
91
|
+
hardware and project size stated.
|
|
92
|
+
- [ ] No claim that test selection is safe to use for skipping CI.
|
|
93
|
+
- [ ] No probability or percentage anywhere in the risk output or the marketing.
|
|
94
|
+
- [ ] The privacy claims: no network, no telemetry, no boot, no `eval`, are all
|
|
95
|
+
still literally true of the shipped code. Re-verify; do not assume.
|
|
96
|
+
|
|
97
|
+
## 7. Announcement
|
|
98
|
+
|
|
99
|
+
- [ ] README opening lines work as a standalone description.
|
|
100
|
+
- [ ] A short terminal capture of `inspect` and `diff` on a real app.
|
|
101
|
+
- [ ] A post that leads with the problem (Rails hides its dependencies) rather
|
|
102
|
+
than the feature list, and that is honest about the limitations.
|
|
103
|
+
- [ ] Prepared answers for the obvious questions: how it differs from Packwerk and
|
|
104
|
+
Enola, whether it is safe to skip tests with it (no), and how it handles
|
|
105
|
+
dynamic dispatch (it does not, and says so).
|
data/docs/RELEASING.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
> **RippleEffect 0.1.0 has not been released.** Before the first public release,
|
|
4
|
+
> work through [PUBLIC_LAUNCH_CHECKLIST.md](PUBLIC_LAUNCH_CHECKLIST.md), in
|
|
5
|
+
> particular, the name must be verified as available on RubyGems.
|
|
6
|
+
|
|
7
|
+
## Versioning
|
|
8
|
+
|
|
9
|
+
SemVer. The public API and what falls outside it are defined at the top of
|
|
10
|
+
[CHANGELOG.md](../CHANGELOG.md).
|
|
11
|
+
|
|
12
|
+
Two version numbers move independently:
|
|
13
|
+
|
|
14
|
+
- `RippleEffect::VERSION`, the gem.
|
|
15
|
+
- `RippleEffect::SCHEMA_VERSION`, the JSON contract. A breaking change here
|
|
16
|
+
increments both it and the gem's major version.
|
|
17
|
+
- `RippleEffect::CACHE_SCHEMA_VERSION`, the on-disk cache. Bumping it invalidates
|
|
18
|
+
every existing cache, which is the intended effect; it is not part of SemVer.
|
|
19
|
+
|
|
20
|
+
## Before you release
|
|
21
|
+
|
|
22
|
+
Everything below must pass on a clean checkout.
|
|
23
|
+
|
|
24
|
+
```console
|
|
25
|
+
$ bundle install
|
|
26
|
+
$ bundle exec rake # specs + RuboCop
|
|
27
|
+
$ bundle exec rake smoke # build, isolated install, installed CLI
|
|
28
|
+
$ gem build ripple_effect.gemspec # must emit zero warnings
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then check by hand:
|
|
32
|
+
|
|
33
|
+
- [ ] CI is green on every supported Ruby.
|
|
34
|
+
- [ ] `CHANGELOG.md` has a dated entry for this version, and `## [Unreleased]` is
|
|
35
|
+
empty.
|
|
36
|
+
- [ ] `lib/ripple_effect/version.rb` is bumped.
|
|
37
|
+
- [ ] Every command shown in `README.md` and `docs/CLI.md` actually produces the
|
|
38
|
+
output shown. Run them against `spec/fixtures/rails_app`.
|
|
39
|
+
- [ ] Fixtures, docs and specs contain no private paths, usernames or secrets.
|
|
40
|
+
- [ ] `SCHEMA_VERSION` was incremented if the JSON contract changed.
|
|
41
|
+
- [ ] Any benchmark number quoted anywhere was actually measured.
|
|
42
|
+
|
|
43
|
+
## The release
|
|
44
|
+
|
|
45
|
+
```console
|
|
46
|
+
$ git switch main && git pull
|
|
47
|
+
$ $EDITOR lib/ripple_effect/version.rb # bump
|
|
48
|
+
$ $EDITOR CHANGELOG.md # date the entry, empty Unreleased
|
|
49
|
+
$ bundle install # refresh Gemfile.lock
|
|
50
|
+
$ bundle exec rake && bundle exec rake smoke
|
|
51
|
+
|
|
52
|
+
$ git add -A
|
|
53
|
+
$ git commit -m "Release v0.1.0"
|
|
54
|
+
$ git tag -s v0.1.0 -m "RippleEffect v0.1.0"
|
|
55
|
+
$ git push origin main --follow-tags
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then publish:
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
$ gem build ripple_effect.gemspec
|
|
62
|
+
$ gem push ripple_effect-0.1.0.gem
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Finally, cut a GitHub release from the tag, pasting the changelog entry.
|
|
66
|
+
|
|
67
|
+
## RubyGems account requirements
|
|
68
|
+
|
|
69
|
+
- **MFA is required** to own or push this gem. The gemspec sets
|
|
70
|
+
`rubygems_mfa_required`, so RubyGems will reject a push from an account without
|
|
71
|
+
it.
|
|
72
|
+
- Decide before the first release whether pushes are manual or via a trusted
|
|
73
|
+
publishing workflow. `.github/workflows/release.yml.example` sketches the
|
|
74
|
+
automated route and is **not enabled**, do not activate it, or add
|
|
75
|
+
a `RUBYGEMS_API_KEY` secret, until that decision is made. Trusted publishing
|
|
76
|
+
(OIDC) is preferred over a long-lived API key.
|
|
77
|
+
|
|
78
|
+
## After releasing
|
|
79
|
+
|
|
80
|
+
- [ ] `gem install ripple_effect` from a clean machine and run `ripple-effect
|
|
81
|
+
doctor` against a real Rails app.
|
|
82
|
+
- [ ] Confirm the RubyGems page renders the README and links correctly.
|
|
83
|
+
- [ ] Open `## [Unreleased]` in `CHANGELOG.md` again.
|
|
84
|
+
|
|
85
|
+
## Yanking
|
|
86
|
+
|
|
87
|
+
Yank only for a security problem or a broken package. A yank breaks
|
|
88
|
+
anyone who pinned the version.
|
|
89
|
+
|
|
90
|
+
```console
|
|
91
|
+
$ gem yank ripple_effect -v 0.1.0
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Prefer releasing a fixed patch version.
|
data/docs/TESTING.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
|
|
3
|
+
```console
|
|
4
|
+
$ bundle exec rake # specs + RuboCop: the gate
|
|
5
|
+
$ bundle exec rspec # specs only
|
|
6
|
+
$ bundle exec rake smoke # build, isolated install, installed-CLI checks
|
|
7
|
+
$ bundle exec rake benchmark
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Layout
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
spec/
|
|
14
|
+
├── spec_helper.rb
|
|
15
|
+
├── support/
|
|
16
|
+
│ ├── project_helpers.rb # throwaway projects, the shared fixture analyzer
|
|
17
|
+
│ └── git_helpers.rb # throwaway Git repositories
|
|
18
|
+
├── unit/ # one file per class or extractor
|
|
19
|
+
├── integration/ # fixture app, diff engine, JSON contract, CLI, docs
|
|
20
|
+
└── fixtures/
|
|
21
|
+
└── rails_app/ # a static, Rails-shaped application
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### The fixture application
|
|
25
|
+
|
|
26
|
+
`spec/fixtures/rails_app/` is a small but realistic Rails-shaped app. It **never
|
|
27
|
+
boots**, it is analysis input.
|
|
28
|
+
|
|
29
|
+
It contains every relationship the product claims to understand:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
route POST /checkout -> OrdersController#create
|
|
33
|
+
OrdersController#create -> CheckoutService#call
|
|
34
|
+
CheckoutService#call -> BillingService#charge
|
|
35
|
+
CheckoutService#call -> InvoiceJob.perform_later
|
|
36
|
+
Order -> belongs_to :account
|
|
37
|
+
Order -> after_commit :send_receipt, if: :receiptable?
|
|
38
|
+
Order#send_receipt -> OrderMailer.receipt(...).deliver_later
|
|
39
|
+
Subscription#renew! -> RenewSubscriptionJob.perform_later
|
|
40
|
+
Order -> include Auditable
|
|
41
|
+
User -> delegate :display_name, to: :account
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> **Its `*_spec.rb` files are fixtures, not tests.** They exist so the
|
|
45
|
+
> test-relevance extractor has something to index. Both `.rspec` and the Rake task
|
|
46
|
+
> exclude them; do not remove those exclusions.
|
|
47
|
+
|
|
48
|
+
Indexing the fixture is the expensive part of the suite, so it is built once per
|
|
49
|
+
run and shared via `ProjectHelpers.fixture_analyzer`.
|
|
50
|
+
|
|
51
|
+
## Writing specs
|
|
52
|
+
|
|
53
|
+
### Against throwaway files
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
graph_for(
|
|
57
|
+
"app/models/order.rb" => "class Order\n belongs_to :account\nend\n",
|
|
58
|
+
"app/models/account.rb" => "class Account\nend\n"
|
|
59
|
+
) do |graph|
|
|
60
|
+
expect(edges_between(graph, "Order", "Account").map(&:type)).to include(:association)
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`with_project`, `with_analyzer` and `graph_for` all accept either a braced hash or
|
|
65
|
+
brace-less `"path" => "source"` pairs, and clean up after themselves.
|
|
66
|
+
|
|
67
|
+
### Against a real Git repository
|
|
68
|
+
|
|
69
|
+
Diff specs use real, temporary repositories rather than stubs: a stub would let
|
|
70
|
+
us pass against a Git that behaves differently from the user's.
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
with_git_project("app/a.rb" => "class A\n def call; end\nend\n") do |root|
|
|
74
|
+
write_files(root, "app/a.rb" => "class A\n def call\n 1\n end\nend\n")
|
|
75
|
+
|
|
76
|
+
expect(analyzer_for(root).diff(base: "main").changed_nodes.map(&:name)).to eq(["A#call"])
|
|
77
|
+
end
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Helpers: `write_files`, `delete_file`, `git`, `analyzer_for`.
|
|
81
|
+
|
|
82
|
+
### Against the CLI
|
|
83
|
+
|
|
84
|
+
Two layers, on purpose:
|
|
85
|
+
|
|
86
|
+
- `spec/unit/cli_application_spec.rb` drives `Application#run` in-process with
|
|
87
|
+
`StringIO`. Fast, and coverage can see it.
|
|
88
|
+
- `spec/integration/cli_spec.rb` runs the **real executable** in a subprocess, so
|
|
89
|
+
argument parsing, exit codes and the stdout/stderr split are checked as a user
|
|
90
|
+
experiences them.
|
|
91
|
+
|
|
92
|
+
## What must stay covered
|
|
93
|
+
|
|
94
|
+
The plan's bar, and the reason for each:
|
|
95
|
+
|
|
96
|
+
- **Determinism**, identical input, byte-identical output. Without it the JSON
|
|
97
|
+
contract cannot be snapshot-tested.
|
|
98
|
+
- **The JSON contract**, key order, schema version, no symbols, relative paths.
|
|
99
|
+
- **Every CLI command**, including exit codes and which stream output goes to.
|
|
100
|
+
- **Every extractor**, positive, negative, unresolvable, and config-off cases.
|
|
101
|
+
- **Diff mapping**, modified, added, deleted, class-body, renamed, staged,
|
|
102
|
+
unstaged, untracked, invalid ref, and a path containing spaces.
|
|
103
|
+
- **Safety**, that a malicious Git ref cannot reach a shell, that a symlink
|
|
104
|
+
pointing outside the root is refused, that YAML cannot construct objects, and
|
|
105
|
+
that indexing never executes the source.
|
|
106
|
+
- **Documentation consistency**, `spec/integration/documentation_spec.rb` asserts
|
|
107
|
+
that every edge type, node kind and diagnostic code is documented, that the
|
|
108
|
+
config example matches the built-in defaults, and that the README lists every
|
|
109
|
+
command.
|
|
110
|
+
|
|
111
|
+
## Coverage
|
|
112
|
+
|
|
113
|
+
SimpleCov, with branch coverage, reporting to `coverage/`.
|
|
114
|
+
|
|
115
|
+
The release expectation is **≥ 90% line coverage** of our own code. Current:
|
|
116
|
+
**96%+ line**, **79%+ branch**, across 380+ examples.
|
|
117
|
+
|
|
118
|
+
Coverage is a floor, not a goal: a covered line that asserts nothing is worth
|
|
119
|
+
nothing.
|
|
120
|
+
|
|
121
|
+
## The smoke test
|
|
122
|
+
|
|
123
|
+
`bundle exec rake smoke` catches what specs structurally cannot:
|
|
124
|
+
|
|
125
|
+
1. `gem build`, must produce zero warnings.
|
|
126
|
+
2. Install into a throwaway `GEM_HOME`, with every Bundler variable stripped, so
|
|
127
|
+
the *installed* gem is what runs.
|
|
128
|
+
3. `require "ripple_effect"` and check the version.
|
|
129
|
+
4. Run the installed `ripple-effect` binary: `--help`, `version`, `doctor`,
|
|
130
|
+
`inspect`, `graph`.
|
|
131
|
+
5. Check the installed CLI's JSON output parses and carries a schema version.
|
|
132
|
+
|
|
133
|
+
This is how you find a file missing from the gemspec's file list, or a require
|
|
134
|
+
that only resolves from the source tree. **It must pass before any release.**
|
|
135
|
+
|
|
136
|
+
## Ground truth against real applications
|
|
137
|
+
|
|
138
|
+
Fixtures prove the code does what it was written to do. They cannot tell you
|
|
139
|
+
whether the answers are *true* of a real codebase.
|
|
140
|
+
|
|
141
|
+
```console
|
|
142
|
+
$ ruby script/ground_truth.rb ~/code/some-rails-app ~/code/another
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For each application it picks the most-referenced uniquely-named methods and
|
|
146
|
+
compares RippleEffect's reported dependents against every file that textually
|
|
147
|
+
mentions that method name.
|
|
148
|
+
|
|
149
|
+
The text search is a crude oracle on purpose. It effectively has no false
|
|
150
|
+
negatives: if a file uses the method, the name appears in it: so **anything
|
|
151
|
+
RippleEffect reports that grep did not find is a genuine false positive**, which
|
|
152
|
+
is the failure mode this project cares about most. The script exits non-zero if
|
|
153
|
+
it finds any.
|
|
154
|
+
|
|
155
|
+
It is not symmetric: grep also matches comments, same-named methods on unrelated
|
|
156
|
+
objects, and strings, so `unmatched` is a ceiling on what was missed rather than
|
|
157
|
+
a defect count. Conventional test files are counted separately, since a spec is
|
|
158
|
+
relevant because of where it lives, not because it names the method.
|
|
159
|
+
|
|
160
|
+
v0.1 was checked this way against six applications: lobsters, rubygems.org,
|
|
161
|
+
Solidus, Mastodon and two private production apps: covering Rails 7.0 to 8.1,
|
|
162
|
+
classic ERB, API-only, Haml, and an engine monorepo. **18 symbols, zero false
|
|
163
|
+
positives.**
|
|
164
|
+
|
|
165
|
+
## CI
|
|
166
|
+
|
|
167
|
+
`.github/workflows/ci.yml` runs:
|
|
168
|
+
|
|
169
|
+
- **test**, Ruby 3.2, 3.3 and 3.4
|
|
170
|
+
- **rails-matrix**, representative Ruby/Rails pairs (7.0, 7.1, 7.2, 8.0, 8.1)
|
|
171
|
+
via per-version Gemfiles. This job installs the real Rails version and runs
|
|
172
|
+
`spec/integration/rails_dsl_compatibility_spec.rb`, which pins the DSL forms
|
|
173
|
+
each version uses: otherwise the matrix would prove nothing, since the rest
|
|
174
|
+
of the suite never loads Rails.
|
|
175
|
+
- **lint**, RuboCop on the current Ruby
|
|
176
|
+
- **package**, `gem build` plus the installed-gem smoke test
|
|
177
|
+
|
|
178
|
+
Benchmarks run locally, never as CI assertions: wall-clock numbers on shared CI
|
|
179
|
+
runners are noise, and a flaky performance test trains people to ignore failures.
|