Unify release scripts and add strict version validation#1881
Unify release scripts and add strict version validation#1881AbanoubGhadban merged 30 commits intomasterfrom
Conversation
- Unified release task for all packages (core + pro) with synchronized versioning - Supports semver bump types (patch/minor/major) and explicit versions - Publishes all packages: react-on-rails, react-on-rails-pro NPM packages, react_on_rails gem, react_on_rails_pro gem, and node-renderer package - Verdaccio mode now publishes all NPM packages for complete local testing - Removed release-it dependency in favor of direct yarn publish - react_on_rails_pro.gemspec now dynamically references ReactOnRails::VERSION - Uses gem bump for both core and pro version updates (no manual file writing) - Deprecated separate pro release script, redirects to unified task - Preserves dry-run, verdaccio testing, and skip-push options Examples: rake release[patch] # Bump patch version rake release[16.2.0] # Set explicit version rake release[patch,true] # Dry run rake release[16.2.0,false,verdaccio] # Test with Verdaccio 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Detects required Ruby version using 'bundle platform --ruby' - Automatically switches to required version before bundle install - Uses Open3.capture3 for safe command execution with proper error handling - Supports pre-release versions (rc, preview, dev, alpha, beta) - Requires exact version match (as enforced by Bundler) - Supports rvm, rbenv, and asdf version managers - Configurable via RUBY_VERSION_MANAGER environment variable - Falls back gracefully if version detection fails This prevents bundle install failures due to Ruby version mismatches during the release process, especially when releasing pro packages that require different Ruby versions than the system default. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Changed approach: run version switch and bundle install in single command - RVM: Use 'rvm VERSION do bundle install' to run in version context - rbenv: Use RBENV_VERSION environment variable - asdf: Chain commands with && to maintain shell context - Removed separate switch_ruby_version method (doesn't persist across subshells) - Simplified bundle_install_in to detect version and call appropriate method This ensures Ruby version switching actually takes effect for bundle install. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
This reverts commit f55c485.
- Implement bundle_install_in() to detect and auto-switch Ruby versions - Use 'bundle platform --ruby' to detect required Ruby version from Gemfile - Support rvm, rbenv, and asdf version managers (via RUBY_VERSION_MANAGER env var) - Run detection in unbundled environment to avoid conflicts - Automatically switch Ruby version when needed during bundle install - Skip version switching when no Ruby version is specified in Gemfile - Handle pre-release versions (rc, alpha, beta) This enables the release script to work across directories with different Ruby version requirements (e.g., pro dummy app requires Ruby 3.3.7).
Use word boundary (\b) in regex to ensure we only match VERSION constant, not PROTOCOL_VERSION. This prevents accidentally updating the protocol version when bumping the package version.
…se files Documentation updates: - Update root releasing.md with all 5 packages and 4 parameters - Add comprehensive requirements section (NPM, RubyGems, GitHub Packages auth) - Add Ruby version management documentation - Add Testing with Verdaccio section - Update version synchronization to include all files - Clarify public vs private package publishing - Update pro CONTRIBUTING.md to reference root release task - Replace pro releasing.md with redirect to root documentation - Delete deprecated pro rakelib/release.rake - Delete deprecated pro script/release All release documentation now correctly reflects unified versioning and the single release script at repository root.
When using skip_push parameter, we should also skip git pull since the branch might not have upstream tracking (e.g., during testing).
This reverts commit 18ff99c.
This commit implements fail-fast validation for package.json configuration to prevent runtime errors and ensure proper package/gem compatibility. Changes: - Add new validation method that raises errors instead of logging warnings - Validate package.json file exists before checking versions - Detect conflicting package installations (both base and Pro) - Enforce exact version matching (no semver wildcards) - Validate Pro gem/package compatibility - Remove deprecated log_if_gem_and_node_package_versions_differ method Implementation details: - Created validate_version_and_package_compatibility! method with 4 validations: 1. validate_package_json_exists! - Ensures package.json is present 2. validate_package_gem_compatibility! - Checks Pro/base package conflicts 3. validate_exact_version! - Enforces exact versions (no ^, ~, >, <, *) 4. validate_version_match! - Ensures gem and package versions match - Added package detection methods (react_on_rails_package?, react_on_rails_pro_package?) - Applied DRY principle with shared package_installed? helper - Integrated validation into Rails engine initializer (config.after_initialize) - Added comprehensive test coverage (53 tests, all passing) - Included helpful error messages with package.json location Fixes #1876 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
WalkthroughUnifies release into a single, unified-version rake task for five packages; enforces strict boot-time gem↔npm compatibility via a new validator that raises on misconfiguration; adds package-manager-aware install/remove helpers and Ruby-version-aware bundle install; removes pro-specific release automation; updates docs, fixtures, and tests. Changes
Sequence Diagram(s)sequenceDiagram
participant Rails as Rails Init
participant Engine as ReactOnRails::Engine
participant VC as VersionChecker
participant App as Application Boot
Rails->>Engine: config.after_initialize
Engine->>VC: VersionChecker.build.validate_version_and_package_compatibility!
rect #F3F7FF
VC->>VC: validate_package_json_exists!
alt package.json missing
VC-->>App: raise ReactOnRails::Error (install guidance)
else
VC->>VC: validate_package_gem_compatibility!
alt conflict detected
VC-->>App: raise ReactOnRails::Error (conflict remediation)
else
VC->>VC: validate_exact_version!
alt semver wildcard found
VC-->>App: raise ReactOnRails::Error (use exact version)
else
VC->>VC: validate_version_match!
alt gem/npm mismatch
VC-->>App: raise ReactOnRails::Error (sync versions)
else
VC-->>Engine: validation passed
end
end
end
end
end
sequenceDiagram
participant Dev as Developer
participant Rake as Rake Release Task
participant Helper as TaskHelpers
participant RubyMgr as Ruby Manager
participant Registry as NPM/GH/Gem Registries
Dev->>Rake: rake release[version,dry_run,registry,skip_push]
Rake->>Helper: bundle_install_in(dir)
Helper->>Helper: detect_bundler_ruby_version(dir)
alt ruby mismatch
Helper->>RubyMgr: bundle_install_with_ruby_version(...)
else
Helper->>Rake: run bundle install normally
end
Rake->>Rake: update unified version across gems & npm packages
Rake->>Registry: publish npm packages (npmjs / GH / Verdaccio)
alt publishing public
Rake->>Registry: publish RubyGems
end
Rake-->>Dev: release summary / dry-run output
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used📓 Path-based instructions (1)**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (2)📚 Learning: 2025-10-23T17:22:01.064ZApplied to files:
📚 Learning: 2025-02-18T13:08:01.477ZApplied to files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
🔇 Additional comments (4)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
rakelib/task_helpers.rb (1)
97-101: Optional: tolerate Ruby patchlevel suffixesBundler may output
ruby 3.2.1p20. Current regex captures3.2.1, which works for equality againstRUBY_VERSION; if you want to preserve prerelease and ignore optionalp\d+, consider:- match = output.strip.match(/ruby\s+([\d.]+(?:-[a-zA-Z0-9.]+)?)/) + match = output.strip.match(/ruby\s+([\d.]+)(?:p\d+)?(?:-([a-zA-Z0-9.]+))?/) + version = match && [match[1], match[2]].compact.join("-") + versiondocs/contributor-info/releasing.md (1)
3-211: Comprehensive documentation of the unified release process.The documentation clearly explains the 5-package unified release workflow, including:
- Command usage with practical examples
- Public vs private package distinctions
- Authentication requirements for multiple registries
- Verdaccio testing workflow
This aligns well with the PR objectives of simplifying the release process.
As per coding guidelines, consider adding language specifiers to the fenced code blocks at lines 153 and 169 to address the markdownlint warnings:
For line 153 (
.npmrccontent):- ``` + ```ini //npm.pkg.github.com/:_authToken=<TOKEN>For line 169 (
.gem/credentialscontent):- ``` + ```yaml :github: Bearer <GITHUB_TOKEN>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
react_on_rails_pro/spec/dummy/Gemfile.lockis excluded by!**/*.lockreact_on_rails_pro/yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (15)
docs/contributor-info/releasing.md(3 hunks)lib/react_on_rails/engine.rb(1 hunks)lib/react_on_rails/version_checker.rb(4 hunks)rakelib/release.rake(9 hunks)rakelib/task_helpers.rb(2 hunks)react_on_rails_pro/CONTRIBUTING.md(1 hunks)react_on_rails_pro/docs/contributors-info/releasing.md(1 hunks)react_on_rails_pro/package.json(0 hunks)react_on_rails_pro/rakelib/release.rake(0 hunks)react_on_rails_pro/react_on_rails_pro.gemspec(2 hunks)react_on_rails_pro/script/release(0 hunks)spec/react_on_rails/fixtures/both_packages.json(1 hunks)spec/react_on_rails/fixtures/pro_package.json(1 hunks)spec/react_on_rails/fixtures/pro_semver_caret_package.json(1 hunks)spec/react_on_rails/version_checker_spec.rb(4 hunks)
💤 Files with no reviewable changes (3)
- react_on_rails_pro/package.json
- react_on_rails_pro/script/release
- react_on_rails_pro/rakelib/release.rake
🧰 Additional context used
📓 Path-based instructions (2)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
lib/react_on_rails/engine.rbrakelib/release.rakerakelib/task_helpers.rbreact_on_rails_pro/react_on_rails_pro.gemspecspec/react_on_rails/version_checker_spec.rblib/react_on_rails/version_checker.rb
**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Prettier is the sole authority for formatting all non-Ruby files; never manually format them
Files:
spec/react_on_rails/fixtures/both_packages.jsonspec/react_on_rails/fixtures/pro_package.jsondocs/contributor-info/releasing.mdreact_on_rails_pro/CONTRIBUTING.mdreact_on_rails_pro/docs/contributors-info/releasing.mdspec/react_on_rails/fixtures/pro_semver_caret_package.json
🧠 Learnings (3)
📚 Learning: 2025-10-23T17:22:01.064Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.064Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.
Applied to files:
lib/react_on_rails/engine.rbreact_on_rails_pro/react_on_rails_pro.gemspecspec/react_on_rails/version_checker_spec.rblib/react_on_rails/version_checker.rb
📚 Learning: 2025-02-12T16:38:06.537Z
Learnt from: Romex91
PR: shakacode/react_on_rails#1697
File: package-scripts.yml:28-28
Timestamp: 2025-02-12T16:38:06.537Z
Learning: The file `node_package/lib/ReactOnRails.full.js` is autogenerated during the build process and should not be present in the repository.
Applied to files:
spec/react_on_rails/fixtures/pro_package.jsonreact_on_rails_pro/react_on_rails_pro.gemspec
📚 Learning: 2025-09-15T21:24:48.207Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1781
File: node_package/src/ClientSideRenderer.ts:82-95
Timestamp: 2025-09-15T21:24:48.207Z
Learning: In React on Rails, the force_load feature includes both explicit `data-force-load="true"` usage and the ability to hydrate components during the page loading state (`document.readyState === 'loading'`). Both capabilities require a Pro license, so the condition `!railsContext.rorPro && (isComponentForceLoaded || document.readyState === 'loading')` correctly gates both scenarios.
Applied to files:
react_on_rails_pro/react_on_rails_pro.gemspec
🧬 Code graph analysis (3)
lib/react_on_rails/engine.rb (1)
lib/react_on_rails/version_checker.rb (3)
build(12-14)build(173-175)validate_version_and_package_compatibility!(28-33)
spec/react_on_rails/version_checker_spec.rb (2)
spec/react_on_rails/support/version_test_helpers.rb (1)
stub_gem_version(3-5)lib/react_on_rails/version_checker.rb (8)
validate_version_and_package_compatibility!(28-33)build(12-14)build(173-175)raw(185-207)react_on_rails_package?(209-211)react_on_rails_pro_package?(213-215)package_name(217-221)semver_wildcard?(223-228)
lib/react_on_rails/version_checker.rb (1)
lib/react_on_rails/utils.rb (1)
react_on_rails_pro?(215-223)
🪛 GitHub Actions: Lint JS and Ruby
rakelib/task_helpers.rb
[error] 91-91: RuboCop: Style/NumericPredicate - Use exit_status.zero? instead of exit_status == 0. (autocorrectable). Command failed: bundle exec rubocop
🪛 markdownlint-cli2 (0.18.1)
docs/contributor-info/releasing.md
153-153: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
169-169: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
react_on_rails_pro/CONTRIBUTING.md
304-304: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
309-309: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: claude-review
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: markdown-link-check
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22)
- GitHub Check: lint-js-and-ruby
🔇 Additional comments (18)
react_on_rails_pro/react_on_rails_pro.gemspec (1)
41-41: Implement exact version pinning for unified versioning.Replacing the hardcoded version constraint with
ReactOnRails::VERSIONenforces an exact version match between the core package and Pro gem, eliminating version mismatch risks. This is a key requirement for the unified release workflow described in the PR objectives.spec/react_on_rails/fixtures/pro_semver_caret_package.json (1)
1-10: Fixture correctly exercises caret-range violationLooks good for asserting the “no semver ranges” rule against react-on-rails-pro.
Please confirm VersionChecker only enforces exact versions for our packages (react-on-rails, react-on-rails-pro) and not all deps/devDeps. If broader, add/adjust tests accordingly.
spec/react_on_rails/fixtures/pro_package.json (1)
1-10: Happy-path fixture LGTMExact pin for react-on-rails-pro with permissive versions elsewhere makes sense for pass-case.
react_on_rails_pro/CONTRIBUTING.md (1)
316-328: Release commands align with rake signatureCommands match task args: version, dry_run, registry, skip_push. No action needed.
rakelib/release.rake (4)
131-153: Version propagation to all package.json files looks correctRoot, workspace packages, and pro node-renderer updated; pro depends on core with exact version. Good.
198-208: Workspace publish flow LGTMPublishing core and pro via Yarn workspaces with
--new-versionaligns with unified versioning.
82-90: Review comment is based on incorrect assumptions about the repository structure.The verification output shows only 2 gemspec files exist (root and react_on_rails_pro directory). The
findcommands with-mindepth 2and-mindepth 3are correctly scoped—they don't match either existing file and won't delete anything. The code is working as intended; there is no safety risk.Likely an incorrect or invalid review comment.
253-277: Review suggestion assumes unified versioning, but codebase uses split pro versioningThe suggested verification script would fail in the current state. The pro package maintains independent versions (4.0.0) while main uses 16.1.1, with partial misalignment between pro Ruby gem and NPM packages.
Before implementing the sync check suggested, clarify whether:
- Pro should track main versions (unify to 16.1.1), or
- Pro maintains intentional independent versioning (current state needs alignment fixes within pro track itself)
The current dry-run message lists pro version.rb as updateable but uses single version variables, suggesting potential release logic gaps for dual-versioning scenarios.
lib/react_on_rails/version_checker.rb (5)
20-33: LGTM! Well-structured validation orchestration.The new validation flow clearly separates concerns into four distinct checks, each with targeted error messages. The fail-fast approach aligns with the project's goal of early error detection.
37-55: Clear and actionable error message for missing package.json.The error message provides excellent guidance with expected location, explanation, and fix commands. Using
gem_versionin the fix ensures version consistency.
57-113: Comprehensive package/gem compatibility validation with clear remediation steps.The three misconfig scenarios (both packages, pro gem + base package, pro package without gem) are handled with detailed, actionable error messages. The use of
package_json_locationhelper maintains DRY principles.
185-207: LGTM! Pro package correctly takes precedence.The precedence logic (checking
react-on-rails-probeforereact-on-rails) aligns with the unified versioning strategy and prevents ambiguity when both packages are present.
209-221: Clean public API for package detection.The new helper methods (
react_on_rails_package?,react_on_rails_pro_package?,package_name) provide a clear interface for determining which package is installed, improving readability throughout the validation logic.lib/react_on_rails/engine.rb (1)
7-15: LGTM! Well-placed fail-fast validation.The
after_initializetiming ensures Rails is fully loaded before validation runs, while still failing fast enough to prevent runtime issues. The info-level logging provides good visibility without being verbose.spec/react_on_rails/fixtures/both_packages.json (1)
1-11: LGTM! Fixture correctly simulates conflicting package installation.This fixture appropriately tests the scenario where both
react-on-railsandreact-on-rails-proare installed, which should trigger the validation error invalidate_package_gem_compatibility!.react_on_rails_pro/docs/contributors-info/releasing.md (1)
1-40: LGTM! Clear redirection to unified release documentation.The documentation appropriately redirects users to the centralized release process while providing quick-reference commands. The prominent outdated notice prevents confusion.
spec/react_on_rails/version_checker_spec.rb (2)
16-207: LGTM! Comprehensive test coverage for validation scenarios.The test suite thoroughly covers all validation paths:
- Package/gem compatibility checks (both packages, mismatches)
- Version validation (exact, wildcard, local paths)
- Missing package.json handling
- Pro gem and package combinations
All tests use proper mocking and clear expectations.
394-496: Excellent coverage of package detection logic.The Pro package detection tests verify:
- Base-only, Pro-only, and both-packages scenarios
- Precedence rules (Pro takes priority)
- Semver wildcard detection
- Default behavior when no packages found
Adds validation to ensure the React on Rails Pro gem version matches
the node renderer package version for best compatibility.
**Changes:**
- **Ruby side** (`lib/react_on_rails_pro/utils.rb`):
- Add `railsEnv` to `common_form_data` method to send Rails environment
to the node renderer
- **Node renderer** (`packages/node-renderer/src/worker/checkProtocolVersionHandler.ts`):
- Add gem version validation logic with environment-aware behavior
- Create `normalizeVersion()` function to handle version format differences:
- Ruby gem format: `4.0.0.rc.1` → NPM format: `4.0.0-rc.1`
- Case-insensitive comparison (e.g., `4.0.0-RC.1` == `4.0.0-rc.1`)
- Whitespace trimming
- **Development**: Throw 412 error when versions don't match
- **Production**: Log warning but allow request to proceed
- **Tests** (`packages/node-renderer/tests/worker.test.ts`):
- Update 11 existing tests to include `railsEnv` field
- Add 6 new comprehensive tests for gem version validation:
- Matching versions test
- Development environment mismatch rejection
- Production environment mismatch allowance
- Version normalization tests (dot format, case-insensitive, whitespace)
**Edge cases handled:**
- ✅ Prerelease format differences (4.0.0.rc.1 vs 4.0.0-rc.1)
- ✅ Case sensitivity (4.0.0-RC.1 vs 4.0.0-rc.1)
- ✅ Whitespace trimming
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Pull Request Review: Unify release scripts and add strict version validationSummaryThis is an excellent PR that significantly improves the React on Rails release process and runtime validation. The changes are well-structured, thoroughly tested, and address real pain points in version management. 🎯 Strengths1. Unified Release Process ✅
2. Strict Version Validation ✅
3. Test Coverage ✅
4. Code Quality ✅
🔍 Code Quality ObservationsVersion Checker (lib/react_on_rails/version_checker.rb)Excellent:
Minor suggestions:
Release Script (rakelib/release.rake)Excellent:
Observations:
🔒 Security ✅
⚡ Performance ✅
🐛 Potential IssuesCritical: None ✅ Minor:
📚 Documentation Quality ✅Outstanding:
🧪 Testing RecommendationsConsider adding:
🎨 Best Practices ✅Follows CLAUDE.md requirements and Rails/Ruby conventions perfectly. 🚀 Migration ImpactPotentially breaking for misconfigured setups, but:
Recommendation: Consider temporary ENV flag (REACT_ON_RAILS_SKIP_VERSION_CHECK) for smoother migration. 📊 Overall Assessment
✅ Recommendation: APPROVE with minor suggestionsThis PR is a significant quality improvement. The implementation is clean, well-tested, and thoroughly documented. Optional improvements:
Before merge:
Great work! This will make releases much more reliable and user configurations much safer. Review generated by Claude Code |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
react_on_rails_pro/lib/react_on_rails_pro/utils.rb (1)
175-182: Avoid sending nulls; omit nil-valued fieldsWhen RSC support is disabled, dependencyBundleTimestamps is nil. Prefer omitting nil entries to keep the payload clean and future‑proof.
Apply this minimal change:
{ "gemVersion" => ReactOnRailsPro::VERSION, "protocolVersion" => ReactOnRailsPro::PROTOCOL_VERSION, "password" => ReactOnRailsPro.configuration.renderer_password, - "dependencyBundleTimestamps" => dependencies, - "railsEnv" => Rails.env.to_s - } + "dependencyBundleTimestamps" => dependencies, + "railsEnv" => Rails.env.to_s + }.compactreact_on_rails_pro/packages/node-renderer/tests/worker.test.ts (1)
332-470: Great coverage; consider two small additions
- Add a test for missing railsEnv to confirm behavior defaults (dev should 412, prod should allow with warning).
- Add a test for prerelease without dot (e.g., 4.0.0.rc1) to lock down normalization.
Would you like me to draft these two Jest cases?
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (3)
7-10: Don’t default NODE_ENV to 'production'Defaulting to 'production' can silently allow version mismatches when railsEnv is absent. Let it be undefined and rely on explicit railsEnv or the actual environment.
-const NODE_ENV = process.env.NODE_ENV || 'production'; +const NODE_ENV = process.env.NODE_ENV;
11-29: Broaden prerelease normalization (optional)Your normalization misses cases like 4.0.0.rc1. A small regex tweak keeps scope tight while covering this common variant.
- // Replace the first dot after major.minor.patch with a hyphen to handle Ruby gem format - // Examples: "4.0.0.rc.1" -> "4.0.0-rc.1", "4.0.0.alpha.1" -> "4.0.0-alpha.1" - normalized = normalized.replace(/^(\d+\.\d+\.\d+)\.([a-z]+)/, '$1-$2'); + // Handle Ruby gem prerelease forms: + // "4.0.0.rc.1" -> "4.0.0-rc.1", "4.0.0.alpha.1" -> "4.0.0-alpha.1", "4.0.0.rc1" -> "4.0.0-rc.1" + normalized = normalized + .replace(/^(\d+\.\d+\.\d+)\.([a-z]+)\.(\d+)$/, '$1-$2.$3') + .replace(/^(\d+\.\d+\.\d+)\.([a-z]+)(\d+)$/, '$1-$2.$3');Consider adding a unit test for "rc1".
54-81: Env-aware mismatch handling looks correct; minor DX polishConsider appending the evaluated environment (railsEnv/NODE_ENV) to the message to aid debugging when behavior differs between dev and prod.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
react_on_rails_pro/spec/dummy/Gemfile.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
react_on_rails_pro/lib/react_on_rails_pro/utils.rb(1 hunks)react_on_rails_pro/lib/react_on_rails_pro/version.rb(1 hunks)react_on_rails_pro/package.json(1 hunks)react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts(2 hunks)react_on_rails_pro/packages/node-renderer/tests/worker.test.ts(10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- react_on_rails_pro/package.json
🧰 Additional context used
📓 Path-based instructions (3)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,config.ru,**/*.{rb,rake,gemspec,ru}}: All Ruby code must pass RuboCop with zero offenses before commit/push
RuboCop is the sole authority for Ruby file formatting; never manually format Ruby files
Files:
react_on_rails_pro/lib/react_on_rails_pro/version.rbreact_on_rails_pro/lib/react_on_rails_pro/utils.rb
**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Prettier is the sole authority for formatting all non-Ruby files; never manually format them
Files:
react_on_rails_pro/packages/node-renderer/tests/worker.test.tsreact_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for JS/TS code (lint via rake lint or yarn lint)
Files:
react_on_rails_pro/packages/node-renderer/tests/worker.test.tsreact_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
🧬 Code graph analysis (1)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (1)
react_on_rails_pro/packages/node-renderer/src/worker/types.ts (1)
FastifyRequest(11-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: claude-review
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: markdown-link-check
- GitHub Check: lint-js-and-ruby
🔇 Additional comments (3)
react_on_rails_pro/lib/react_on_rails_pro/version.rb (1)
4-4: Version update verified across all packages.All six version locations are correctly synchronized to 16.1.1, confirming successful implementation of the unified versioning strategy. PROTOCOL_VERSION remains appropriately unchanged at 2.0.0.
react_on_rails_pro/lib/react_on_rails_pro/utils.rb (1)
179-181: railsEnv addition looks goodIncluding Rails.env in the payload matches the new protocol and tests. No issues.
react_on_rails_pro/packages/node-renderer/tests/worker.test.ts (1)
29-31: railsEnv plumbed through tests coherentlyThe tests now include railsEnv where protocol/gem checks apply. This aligns with handler logic.
Also applies to: 47-55, 75-85, 118-122, 145-149, 172-176, 200-203, 291-299, 315-323
Optimize version validation by caching comparison results to avoid repeated normalization on every rendering request. **Changes:** - Add `versionCache` Map to store version comparison results - Cache is checked before performing normalization (key: gemVersion) - Normalization only runs on cache miss - Production logging is now conditional on cache miss (logs only once) **Performance benefits:** - Eliminates repeated string operations (trim, toLowerCase, regex) on every request - Prevents log spam in production (warning logged only once per unique version) - Minimal memory overhead (few cached version strings) **Cache behavior:** - Cache key: gemVersion string - Cache value: boolean (true if versions match, false if mismatch) - If key exists, comparison result is used directly - Production warning only logs when version is first encountered (justCached flag) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Pull Request Review: Unified Release Scripts and Strict Version ValidationOverall AssessmentThis is an excellent and comprehensive PR that significantly improves the React on Rails release process and runtime validation. The changes are well-architected, thoroughly tested, and will prevent many common configuration issues. Recommendation: ✅ Approve with minor suggestions Part 1: Unified Release Script - EXCELLENT ⭐Strengths
Code Quality Highlights
Suggestions
Part 2: Strict Version Validation - EXCELLENT ⭐Strengths
Suggestions
Part 3: Node Renderer Version Validation - VERY GOOD ⭐Strengths
Suggestions
Part 4: Ruby Version Auto-Switching - VERY GOOD ⭐Strengths
Suggestions
Summary ScoresSecurity: ✅ No Issues Final RecommendationsMust Address
Should Consider
Nice to Have
SummaryThis PR represents a significant improvement to React on Rails: ✅ Eliminates version mismatches at multiple levels Code quality is high, architecture is sound, implementation is thorough. Great work! 🎉 Review by Claude Code per CLAUDE.md guidelines |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx,css,scss,json,yml,yaml,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Prettier is the sole authority for formatting all non-Ruby files; never manually format them
Files:
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for JS/TS code (lint via rake lint or yarn lint)
Files:
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts
🧬 Code graph analysis (1)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (2)
react_on_rails_pro/spec/dummy/client/node-renderer.js (1)
process(5-5)react_on_rails_pro/packages/node-renderer/src/worker/types.ts (1)
FastifyRequest(11-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build-dummy-app-webpack-test-bundles
- GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22)
- GitHub Check: claude-review
- GitHub Check: markdown-link-check
- GitHub Check: build-dummy-app-webpack-test-bundles (3.2, 20)
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: lint-js-and-ruby
- GitHub Check: build-dummy-app-webpack-test-bundles
🔇 Additional comments (5)
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts (5)
7-8: LGTM!The log import is correctly added to support the production warning behavior introduced later in the file.
9-14: LGTM!The version cache is a good optimization that prevents repeated normalization and avoids log spam for duplicate version checks. In typical deployments, the cache will only contain 1-2 entries, so unbounded growth is not a practical concern.
16-34: LGTM!The normalization function correctly handles the Ruby gem prerelease format conversion (e.g.,
4.0.0.rc.1→4.0.0-rc.1). The regex is well-targeted for the documented use case, and the lowercase/trim operations ensure robust comparison.
36-40: LGTM!The RequestBody interface provides clear type safety for the destructured request body fields.
59-75: LGTM with the production detection caveat!The gem version validation logic is well-implemented:
- The caching strategy correctly avoids repeated normalization and prevents log spam by using the
justCachedflag to log warnings only once per unique gem version.- Error messages are clear and actionable, guiding users to update either the gem or the node renderer package.
- The environment-aware behavior (warning in production vs. 412 error in development) provides a good balance between strict validation during development and operational flexibility in production.
Assuming the production detection logic at line 76 is corrected, this implementation achieves the PR objective of strict version validation with appropriate environment-sensitive handling.
Also applies to: 77-100
Summary
This PR implements three major improvements to React on Rails version management:
These changes work together to ensure consistent versioning across all packages (both during releases and at runtime).
Part 1: Unified Release Script
Problem
Previously, React on Rails had two separate release scripts with different workflows:
react-on-railsgem +react-on-railsNPM +react-on-rails-proNPMreact_on_rails_progem +node-rendererNPMThis created maintenance overhead and potential for version mismatches.
Solution: Synchronized Versioning
All packages now share the same version number, managed by a single release script at the root.
Packages unified:
react-on-rails(gem + NPM)react-on-rails-pro(gem + NPM)node-renderer(NPM)Version files updated atomically (6 locations):
/lib/react_on_rails/version.rb/packages/react-on-rails/package.json/packages/react-on-rails-pro/package.json/react_on_rails_pro/lib/react_on_rails_pro/version.rb/react_on_rails_pro/package.json(node-renderer)/package.json(root workspace)Key Features
patch,minor,majoror specify exact version^or~)Usage Examples
Files Removed (Deprecated)
react_on_rails_pro/rakelib/release.rake- Replaced by unified scriptreact_on_rails_pro/script/release- No longer neededreact_on_rails_pro/package.json- Not needed at Pro rootDocumentation Updated
docs/contributor-info/releasing.md- Complete rewrite with new processreact_on_rails_pro/CONTRIBUTING.md- Updated to reference root scriptreact_on_rails_pro/docs/contributors-info/releasing.md- Updated release docsPart 2: Strict Version Validation
Problem
Users could misconfigure package.json (wrong versions, conflicting packages, semver wildcards) and only discover issues at runtime. Warnings were easily missed in logs.
Solution: Fail-Fast Validation
Application now validates configuration at boot and raises clear errors for misconfigurations.
Implementation
validate_version_and_package_compatibility!config.after_initialize^,~,>,<,*)Validation Scenarios
1. Missing package.json
2. Both packages installed
3. Pro gem with base package
4. Pro package without Pro gem
5. Non-exact version (semver wildcard)
6. Version mismatch
Code Quality Improvements
package_installed?(package_name)helperreact_on_rails_package?,react_on_rails_pro_package?log_if_gem_and_node_package_versions_differmethodTest Coverage
Part 3: Node Renderer Gem Version Validation
Problem
When using React on Rails Pro with a remote node renderer, version mismatches between the Ruby gem (
react_on_rails_pro) and the node renderer package (@shakacode-tools/react-on-rails-pro-node-renderer) could cause subtle runtime issues. These mismatches were difficult to diagnose.Solution: Runtime Version Validation
The node renderer now validates that the gem version matches the node renderer package version on every request, with environment-aware behavior.
Implementation
Ruby Side Changes (
lib/react_on_rails_pro/utils.rb):railsEnvtocommon_form_datamethodNode Renderer Changes (
packages/node-renderer/src/worker/checkProtocolVersionHandler.ts):normalizeVersion()function to handle version format differencesVersion Normalization
The
normalizeVersion()function handles these edge cases:4.0.0.rc.14.0.0-rc.14.0.0-RC.14.0.0-rc.14.0.04.0.04.0.0.alpha.14.0.0-alpha.14.0.0.beta.24.0.0-beta.2Behavior
Development Environment:
Production Environment:
Environment Detection
The node renderer determines if it's in production using either:
railsEnv === 'production'(sent from Ruby)NODE_ENV === 'production'(node environment variable)If either is production, the permissive behavior applies.
Test Coverage
Updated Tests (
packages/node-renderer/tests/worker.test.ts):railsEnvfield in requestsNew Tests Added (6 comprehensive tests):
4.0.0.rc.1==4.0.0-rc.1)4.0.0-RC.1==4.0.0-rc.1)Test Results:
Files Changed
Release Script Changes
rakelib/release.rake- Unified release logic for all packagesrakelib/task_helpers.rb- Enhanced with Ruby version detectiondocs/contributor-info/releasing.md- Complete documentation rewritereact_on_rails_pro/CONTRIBUTING.md- Updated contributor guidereact_on_rails_pro/docs/contributors-info/releasing.md- Updated release docsreact_on_rails_pro/react_on_rails_pro.gemspec- Dependency updatesVersion Validation Changes
lib/react_on_rails/engine.rb- Added validation initializerlib/react_on_rails/version_checker.rb- Core validation logic (205 lines changed)spec/react_on_rails/version_checker_spec.rb- Comprehensive test coverage (327 lines changed)spec/react_on_rails/fixtures/- New test fixtures (3 files)Node Renderer Validation Changes
lib/react_on_rails_pro/utils.rb- AddedrailsEnvto request datapackages/node-renderer/src/worker/checkProtocolVersionHandler.ts- Added gem version validation with normalizationpackages/node-renderer/tests/worker.test.ts- Updated existing tests + 6 new testsRemoved Files
react_on_rails_pro/rakelib/release.rake- Deprecatedreact_on_rails_pro/script/release- No longer neededreact_on_rails_pro/package.json- Not needed at Pro rootBenefits
Unified Release Script
Strict Version Validation
Node Renderer Validation
Testing
Release Script Testing
Validation Testing
Node Renderer Testing
Migration Notes
For Contributors
rake releasecommand instead of Pro-specific scriptsFor Users
^,~, etc.)Fixes #1876
🤖 Generated with Claude Code
Co-Authored-By: Claude [email protected]
This change is
Summary by CodeRabbit
New Features
Chores
Documentation
Tests