Fix resolve_hook_script_path to work without Rails.root#2568
Fix resolve_hook_script_path to work without Rails.root#2568
Conversation
resolve_hook_script_path required Rails.root to resolve hook script paths, returning nil in bin/dev context where Rails isn't loaded. This caused hook_configured? to return false even when the hook was properly configured, leading to redundant pack generation after the hook already ran. Add project_root helper that falls back to BUNDLE_GEMFILE dirname (set by Bundler during require "bundler/setup") or Dir.pwd when Rails.root is unavailable. Companion to shakacode/shakapacker#963 which fixes Shakapacker::Env to work without Rails. Together these two fixes fully resolve #2438 without the YAML-parsing workaround in #2561. Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds Pathname support and a project_root resolver (prefers Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ReviewThe fix is correct and well-scoped. Minor nits (inline):
More significant gap — test coverage: One edge case to be aware of: Overall the approach is solid and the dependency on the companion shakapacker PR is clearly documented. |
Greptile SummaryThis PR fixes Key changes:
Issues found:
Confidence Score: 3/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["resolve_hook_script_path(hook_value)"] --> B{hook_value blank?}
B -- yes --> C[return nil]
B -- no --> D["project_root.join(hook_value.strip)"]
D --> E["project_root()"]
E --> F{Rails defined\n& Rails.root truthy?}
F -- yes --> G["Pathname.new(Rails.root) ⚠️\n(redundant wrap — Rails.root\nalready returns a Pathname)"]
F -- no --> H{BUNDLE_GEMFILE\nenv var set & non-blank?}
H -- yes --> I["Pathname.new(BUNDLE_GEMFILE).expand_path"]
I --> J{File exists?}
J -- yes --> K[return gemfile_path.dirname]
J -- no --> L["Pathname.new(Dir.pwd)"]
H -- no --> L
G --> M[potential_path]
K --> M
L --> M
M --> N{potential_path.file?}
N -- yes --> O[return potential_path]
N -- no --> C
Last reviewed commit: f9f0115 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
react_on_rails/lib/react_on_rails/packer_utils.rb (1)
237-246: Add regression specs for the new non-Rails fallbacks.This is the core fix, but the provided
packer_utils_speccoverage only exercises theRails.root.join(...)branch. Please lock down both theBUNDLE_GEMFILEandDir.pwdpaths so this behavior does not silently regress.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@react_on_rails/lib/react_on_rails/packer_utils.rb` around lines 237 - 246, Add regression specs for ReactOnRails::PackerUtils.project_root that cover the two non-Rails fallbacks: (1) when ENV["BUNDLE_GEMFILE"] is set to a valid Gemfile path, assert project_root returns the Gemfile's directory by creating a temporary Gemfile, setting ENV["BUNDLE_GEMFILE"] to its path, undefining or stubbing Rails/root, and calling project_root; and (2) when no Rails.root and no BUNDLE_GEMFILE, assert project_root returns Pathname.new(Dir.pwd) by clearing ENV["BUNDLE_GEMFILE"], ensuring Rails is not present or has no root, calling project_root, and comparing to Pathname.new(Dir.pwd). Remember to restore ENV and any Rails constant/state after each example to avoid test leakage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@react_on_rails/lib/react_on_rails/packer_utils.rb`:
- Around line 237-246: Add regression specs for
ReactOnRails::PackerUtils.project_root that cover the two non-Rails fallbacks:
(1) when ENV["BUNDLE_GEMFILE"] is set to a valid Gemfile path, assert
project_root returns the Gemfile's directory by creating a temporary Gemfile,
setting ENV["BUNDLE_GEMFILE"] to its path, undefining or stubbing Rails/root,
and calling project_root; and (2) when no Rails.root and no BUNDLE_GEMFILE,
assert project_root returns Pathname.new(Dir.pwd) by clearing
ENV["BUNDLE_GEMFILE"], ensuring Rails is not present or has no root, calling
project_root, and comparing to Pathname.new(Dir.pwd). Remember to restore ENV
and any Rails constant/state after each example to avoid test leakage.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2a4ddadf-f3cd-4b41-b741-17a4638325ad
📒 Files selected for processing (1)
react_on_rails/lib/react_on_rails/packer_utils.rb
Rails.root already returns a Pathname, so wrapping it in Pathname.new() caused instance_double(Pathname) in specs to fail on unstubbed to_path. Added unit tests for all three project_root branches: Rails.root, BUNDLE_GEMFILE dirname, and Dir.pwd fallback. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Review SummaryThe fix is conceptually correct and well-motivated — using Critical: Test stubs do not match the implementation All three new tests under "when Rails is not defined" stub
The simplest fix is to change the implementation to use Missing higher-level test coverage The new specs test the
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@react_on_rails/spec/react_on_rails/packer_utils_spec.rb`:
- Around line 357-377: The tests are stubbing ENV.[] but the code calls
ENV.fetch("BUNDLE_GEMFILE", nil), so update the specs around the project_root
examples to stub ENV.fetch instead of ENV.[]; use allow(ENV).to
receive(:fetch).and_call_original and then override .with("BUNDLE_GEMFILE",
nil).and_return(__FILE__) for the valid-file case, .and_return(nil) for the "not
set" case, and .and_return("/non/existent/Gemfile") for the non-existent-file
case so the project_root expectations exercise the intended branches.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e6096592-08bf-4ec8-b835-f4145f514cb8
📒 Files selected for processing (2)
react_on_rails/lib/react_on_rails/packer_utils.rbreact_on_rails/spec/react_on_rails/packer_utils_spec.rb
The implementation uses ENV.fetch("BUNDLE_GEMFILE", nil) but tests
stubbed ENV.[]. In MRI Ruby these are separate methods — the stub
didn't intercept fetch, causing the "valid file" test to fail.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
PR Review: Fix resolve_hook_script_path to work without Rails.rootOverall this is a well-motivated and correctly-scoped fix. The fallback chain (Rails.root → BUNDLE_GEMFILE → Dir.pwd) is a sound approach. A few things worth addressing: 1. Missing test: Rails.root returns nil/falsy The project_root guard handles the case where Rails.root is nil (e.g., during engine initialization before Rails is fully booted). However, there is no spec for this — the test suite only covers Rails being fully defined with a valid root, or Rails being absent entirely. A spec where Rails.root returns nil would prevent regressions. 2. resolve_hook_script_path behavior change is undocumented The old comment (Hook value might be a script path relative to Rails root) has been removed without replacement. A short note explaining the project_root fallback chain would help future readers understand why Rails is no longer required. 3. project_root visibility project_root is a module-level self. method and becomes part of the public API. If it is only intended as an internal helper, consider private_class_method :project_root to prevent unintended external use. Positive notes
|
stub_const("ENV", ENV.to_h.merge(...)) replaces the entire ENV object,
so all access methods ([], fetch, key?) work consistently. This avoids
coupling tests to the specific ENV method the implementation uses.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@react_on_rails/spec/react_on_rails/packer_utils_spec.rb`:
- Around line 357-363: The test for the BUNDLE_GEMFILE branch can accidentally
pass if Dir.pwd equals Pathname.new(__FILE__).expand_path.dirname; update the
example so it forces a different current working directory before calling
described_class.project_root (e.g., stub Dir.pwd or Dir.getwd to return a path
different from expected_dir) while still stubbing ENV.fetch("BUNDLE_GEMFILE",
nil) to __FILE__, ensuring project_root must use the BUNDLE_GEMFILE dirname
branch; reference the BUNDLE_GEMFILE stub and the described_class.project_root
call when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4c03d671-4500-43e3-9f4d-ce65931d2bed
📒 Files selected for processing (1)
react_on_rails/spec/react_on_rails/packer_utils_spec.rb
ReviewThe approach is sound — removing the hard Minor issues:
Otherwise the implementation is clean, the commit history tells a clear story, and the test structure for |
Add entries for user-visible changes since v16.4.0.rc.6: - #2539: env-var-driven ports in Procfile templates - #2417: rspack generator config path fix - #2419: precompile hook load-based execution fix - #2577: create-react-on-rails-app validation improvements - #2416: StreamResponse status fallback fix (Pro) - #2566: empty-string license plan mismatch fix (Pro) - Updated #2561 entry to include #2568 contributor credit Co-Authored-By: Claude Opus 4.6 <[email protected]>
## Summary - Add changelog entries for 6 user-visible PRs merged since v16.4.0.rc.6 that were missing from `[Unreleased]` - Update existing #2561 entry to include #2568 contributor credit ### New entries added | Section | PR | Description | |---|---|---| | Added | #2539 | Environment-variable-driven ports in Procfile templates | | Fixed | #2417 | Rspack generator config path fix | | Fixed | #2419 | Precompile hook load-based execution fix | | Fixed | #2577 | `create-react-on-rails-app` validation improvements | | Pro Fixed | #2416 | StreamResponse status fallback fix | | Pro Fixed | #2566 | Empty-string license plan mismatch fix | ### Skipped PRs (not user-visible) Docs (#2406, #2414, #2479, #2494, #2518, #2537, #2544), CI/internal (#2533, #2547, #2555, #2557, #2558, #2564), dependabot (#2387, #2541), dev dependencies (#2559, #2569, #2573). ## Test plan - [ ] Verify changelog formatting matches existing entries - [ ] Verify all user-visible PRs since v16.4.0.rc.6 are covered 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Documentation-only changelog updates with no runtime or build behavior changes. > > **Overview** > Updates `CHANGELOG.md`’s **[Unreleased]** section to include previously missing user-facing entries: Procfile templates now support env-driven ports, several generator/`bin/dev` precompile-hook and rspack-path fixes are documented, and `create-react-on-rails-app` validation improvements are noted. > > Also adds two Pro fix entries (StreamResponse status fallback and license plan empty-string validation) and updates the existing `bin/dev` precompile-hook entry to credit an additional PR/contributor. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e75d2b5. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.6 <[email protected]>
…2580) ## Summary - Reverts #2561 (squash commit 769d120), which was merged after #2568 already landed on master - #2568 + [shakacode/shakapacker#963](shakacode/shakapacker#963) fix the root cause of #2438 — #2561's YAML-parsing fallback is redundant - CHANGELOG entry updated to reference #2568 only ## What's removed All of #2561's additions on top of #2568: - `extract_precompile_hook_from_yaml` / `extract_precompile_hook_from_shakapacker_config` split - `extract_script_from_command` interpreter-prefix stripping - `extract_hash_for_environment` / `current_shakapacker_environment` helpers - `SHAKAPACKER_CONFIG_PATH` constant, `require "erb"`, `require "yaml"` - `rubocop:disable Metrics/ModuleLength` - `GENERATE_PACKS_PATTERN` expansion for `generate_packs_if_needed` - 72 lines of #2561-specific specs ## What remains (from #2568 + shakapacker#963) - `project_root` helper (Rails.root → BUNDLE_GEMFILE → Dir.pwd fallback) - `resolve_hook_script_path` using `project_root` - `require "pathname"` - 3 project_root specs - Shakapacker `Env#current` guard (separate repo, already merged) ## Why #2568 was designed to supersede #2561 — its PR description says so explicitly. Both were merged, resulting in unnecessary complexity (YAML config re-parsing, ERB evaluation, environment fallback chain) that duplicates what Shakapacker already handles after #963. ## Test plan - `bundle exec rspec react_on_rails/spec/react_on_rails/packer_utils_spec.rb` - `bundle exec rubocop react_on_rails/lib/react_on_rails/packer_utils.rb react_on_rails/spec/react_on_rails/packer_utils_spec.rb` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved bin/dev startup reliability with enhanced hook script path resolution during early startup when Rails.root is unavailable. * Removed YAML configuration dependency, streamlining hook detection. * Added validation checks for hook script existence to prevent runtime errors. * Simplified hook script pattern matching for better clarity. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
project_roothelper that resolves the project root without requiringRails.rootBUNDLE_GEMFILEdirname (reliable — always set afterrequire "bundler/setup") thenDir.pwdresolve_hook_script_pathnow usesproject_rootinstead of hard-requiringRails.rootRelated to #2438 — addresses the hook detection root cause (hook not running from
bin/devcontext), though the exact symptom reported in that issue (pack generation failure) could not be reproduced.Problem
resolve_hook_script_pathreturned nil wheneverRails.rootwasn't available (e.g., frombin/devwhich intentionally skips loading Rails for startup speed). This causedhook_configured?to return false even when the precompile hook was correctly configured inshakapacker.yml, leading to redundant pack generation after the hook already ran.Companion PR
This works together with shakacode/shakapacker#963, which fixes
Shakapacker::Env#currentto resolve the environment fromRAILS_ENV/RACK_ENVenv vars when Rails isn't loaded. Together, these two fixes address thebin/devhook detection issue.With both fixes applied,
bin/devoutput shows the correct flow:Supersedes #2561
PR #2561 worked around the Shakapacker
Env#currentbug by re-implementing YAML config parsing. With the Shakapacker fix in place, that workaround is no longer needed — this PR provides only the minimalresolve_hook_script_pathfix that was still necessary.Test plan
hook_configured?returnstruefrom non-Rails context (test app with both fixes)bin/devruns hook and skips redundant pack generationBUNDLE_GEMFILEcorrectly resolves project root even whenDir.pwddiffers🤖 Generated with Claude Code
Summary by CodeRabbit
Improvements
Tests