You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tighten helper binstub parity and PATH lookup (#1128)
## Summary
Adds focused parity coverage for the helper binstub contract introduced
in #1123.
The PR keeps the checked-in Ruby helper wrappers, the dummy app wrapper,
and the `createBinStub` TypeScript template aligned so future helper
drift fails CI quickly.
## Changes
- Export `createBinStub` from `package/configExporter/cli.ts` for test
use.
- Add `test/configExporter/createBinStub.test.js`, which generates
`shakapacker-config` and `diff-bundler-config` and byte-compares them
with `lib/install/bin/*`.
- Assert generated helper binstubs are executable.
- Keep `mkdirSync` and `chmodSync` in the top-level `fs` import instead
of using inline `require("fs")`.
- Improve `spec/shakapacker/binstub_sync_spec.rb` failure guidance so
contributors are told to update all synchronized copies.
## Review follow-up
Addressed the current actionable review threads:
- Switched to flat `test.each(["shakapacker-config",
"diff-bundler-config"])`.
- Removed the dead `if (tmp)` cleanup guard.
- Added a note explaining why `diff-bundler-config` is covered even
though production init only generates `shakapacker-config`.
- Added executable-permission coverage for generated binstubs.
- Expanded the Ruby sync failure message to name all synchronized
copies.
- Moved `mkdirSync` and `chmodSync` into the module-level `fs` import.
- Fixed leading and trailing empty `PATH` segment handling so helper
binstubs honor the current directory during Node lookup, and added RSpec
coverage for both helper commands.
Discussion/advice:
- The generated-user-binstub comment concern is intentionally left as
discussion-only for this PR. This parity test is meant to prove the
generated template matches the checked-in install files byte-for-byte;
changing generated comments separately would weaken that contract.
- Empty `PATH` segment handling turned out to be a real edge case: Ruby
`File.join("", "node")` checks `/node`, not the current directory, and
Ruby `String#split` drops trailing empty fields unless called with a
negative limit. The helper now preserves trailing entries and maps empty
segments to `Dir.pwd` before joining, preserving normal PATH semantics
even though the binstub later `chdir`s to the app root.
## CI note
This branch is rebased onto current `origin/main`.
The earlier `Test Both Bundlers` failure was Bundler frozen-mode
lockfile drift in `spec/dummy/Gemfile.lock`: the lockfile still recorded
`shakapacker (10.1.0.rc.1)` while the current gemspec resolves to
`10.1.0`. That lockfile fix is now already included in current
`origin/main`, and this branch has been rebased on top of it, so the PR
diff no longer carries a lockfile change.
The previous `claude-review` failure was due to the external Claude
weekly limit, not the repository diff.
## Test plan
- [x] `bundle exec rspec spec/shakapacker/helper_binstubs_spec.rb:211
--format documentation` - 4 empty-`PATH` examples pass for leading and
trailing entries across both helper commands
- [x] `bundle exec rspec spec/shakapacker/binstub_sync_spec.rb
spec/shakapacker/helper_binstubs_spec.rb` - 21 examples, 0 failures
- [x] `yarn jest test/configExporter/createBinStub.test.js` - 2 tests
passed
- [x] `yarn eslint package/configExporter/cli.ts
test/configExporter/createBinStub.test.js`
- [x] `bundle exec rubocop spec/shakapacker/helper_binstubs_spec.rb
spec/shakapacker/binstub_sync_spec.rb` - no offenses
- [x] `git diff --check origin/main...HEAD`
Refs #1123.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Changes are confined to install/helper binstub templates and test
tooling; behavior fix is narrow (PATH parsing) with new regression
coverage.
>
> **Overview**
> Tightens **helper binstub** parity and fixes **Node lookup** when
`PATH` contains empty segments (leading/trailing `:`).
>
> **PATH lookup:** `shakapacker_find_executable` now splits `PATH` with
a negative limit so trailing empty entries are kept, and treats an empty
segment as **`Dir.pwd`** instead of joining to `/node`. The same Ruby
logic is updated in `lib/install/bin/*`,
`spec/dummy/bin/shakapacker-config`, and the **`createBinStub`**
template in `package/configExporter/cli.ts`.
>
> **Parity & CI:** **`createBinStub`** is exported (test-only) and uses
top-level `fs` imports; **`test/configExporter/createBinStub.test.js`**
byte-compares generated `shakapacker-config` / `diff-bundler-config`
stubs to `lib/install/bin/*` and checks execute bits.
**`binstub_sync_spec`** failure text lists all four sync targets.
**`helper_binstubs_spec`** adds RSpec for leading/trailing empty `PATH`
entries, refactors `real_node_path`, and wraps some cases in
**`Bundler.with_unbundled_env`**.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
88a44c9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments