Skip to content

Unify release scripts and add strict version validation#1881

Merged
AbanoubGhadban merged 30 commits intomasterfrom
strict-version-validation
Oct 27, 2025
Merged

Unify release scripts and add strict version validation#1881
AbanoubGhadban merged 30 commits intomasterfrom
strict-version-validation

Conversation

@AbanoubGhadban
Copy link
Copy Markdown
Collaborator

@AbanoubGhadban AbanoubGhadban commented Oct 26, 2025

Summary

This PR implements three major improvements to React on Rails version management:

  1. Unified release script - Consolidates separate release workflows into a single, atomic release process
  2. Strict version validation - Adds fail-fast validation to prevent runtime configuration errors
  3. Node renderer gem version validation - Ensures gem and node renderer versions match at runtime

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:

  • Root script: Released react-on-rails gem + react-on-rails NPM + react-on-rails-pro NPM
  • Pro script: Released react_on_rails_pro gem + node-renderer NPM

This 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):

  1. /lib/react_on_rails/version.rb
  2. /packages/react-on-rails/package.json
  3. /packages/react-on-rails-pro/package.json
  4. /react_on_rails_pro/lib/react_on_rails_pro/version.rb
  5. /react_on_rails_pro/package.json (node-renderer)
  6. /package.json (root workspace)

Key Features

  • Automatic Ruby version detection and switching - Detects required Ruby version from gemspecs and switches automatically
  • Semver bump support - Use patch, minor, major or specify exact version
  • Exact version dependencies - Updates all dependency declarations with exact versions (no ^ or ~)
  • Dry run mode - Test all changes without actually publishing
  • Verdaccio support - Test NPM packages locally before publishing
  • Skip push option - Test git operations without pushing
  • Uncommitted changes validation - Prevents accidental releases with uncommitted work
  • Atomic updates - All version files updated together

Usage Examples

# Semver bump
rake release[patch]                           # Bump patch version
rake release[minor]                           # Bump minor version
rake release[major]                           # Bump major version

# Explicit version
rake release[17.0.0]                          # Set to specific version

# With options
rake release[patch,true]                      # Dry run
rake release[17.0.0,false,verdaccio]          # Test with Verdaccio
rake release[17.0.0,false,npm,skip_push]      # Skip git push

Files Removed (Deprecated)

  • react_on_rails_pro/rakelib/release.rake - Replaced by unified script
  • react_on_rails_pro/script/release - No longer needed
  • react_on_rails_pro/package.json - Not needed at Pro root

Documentation Updated

  • docs/contributor-info/releasing.md - Complete rewrite with new process
  • react_on_rails_pro/CONTRIBUTING.md - Updated to reference root script
  • react_on_rails_pro/docs/contributors-info/releasing.md - Updated release docs

Part 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

  • New validation method: validate_version_and_package_compatibility!
  • Integrated into Rails engine: Runs on config.after_initialize
  • Four validation checks:
    1. package.json exists - Ensures the file is present
    2. Package compatibility - Detects conflicting installations (both base and Pro)
    3. Exact versions - Enforces exact version matching (no ^, ~, >, <, *)
    4. Version match - Ensures gem and npm package versions match exactly

Validation Scenarios

1. Missing package.json

**ERROR** ReactOnRails: package.json file not found.
Expected location: /path/to/package.json

2. Both packages installed

**ERROR** ReactOnRails: Both 'react-on-rails' and 'react-on-rails-pro' packages are installed.
Fix: Remove 'react-on-rails' - the Pro package includes all base functionality.

3. Pro gem with base package

**ERROR** ReactOnRails: You have the Pro gem installed but are using the base 'react-on-rails' package.
Fix: Install react-on-rails-pro package instead.

4. Pro package without Pro gem

**ERROR** ReactOnRails: You have the 'react-on-rails-pro' package installed but the Pro gem is not installed.
Fix: Install the Pro gem or use the base package.

5. Non-exact version (semver wildcard)

**ERROR** ReactOnRails: The 'react-on-rails' package version is not an exact version.
Detected: ^16.1.1
Do not use ^, ~, >, <, *, or other semver ranges.

6. Version mismatch

**ERROR** ReactOnRails: The 'react-on-rails' package version does not match the gem version.
Package: 16.1.2
Gem: 16.1.1

Code Quality Improvements

  • Applied DRY principle: Created shared package_installed?(package_name) helper
  • Added package detection methods: react_on_rails_package?, react_on_rails_pro_package?
  • Removed deprecated log_if_gem_and_node_package_versions_differ method
  • Clear, actionable error messages with package.json location

Test Coverage

  • Added 9 new test cases for validation scenarios
  • Created 3 new fixture files for Pro package testing
  • Total: 53 tests, all passing
  • Zero RuboCop offenses

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):

  • Added railsEnv to common_form_data method
  • Rails environment is now sent with every request to the node renderer

Node Renderer Changes (packages/node-renderer/src/worker/checkProtocolVersionHandler.ts):

  • Added gem version validation alongside existing protocol version checks
  • Created normalizeVersion() function to handle version format differences
  • Environment-aware error handling

Version Normalization

The normalizeVersion() function handles these edge cases:

Ruby Gem Format NPM Format Result
4.0.0.rc.1 4.0.0-rc.1 ✅ Match
4.0.0-RC.1 4.0.0-rc.1 ✅ Match (case-insensitive)
4.0.0 4.0.0 ✅ Match (whitespace trimmed)
4.0.0.alpha.1 4.0.0-alpha.1 ✅ Match
4.0.0.beta.2 4.0.0-beta.2 ✅ Match

Behavior

Development Environment:

Status: 412 Precondition Failed

Version mismatch error: React on Rails Pro gem version (4.0.0) does not
match node renderer version (4.0.1). Using exact matching versions is
recommended for best compatibility.

Gem version: 4.0.0
Node renderer version: 4.0.1

Update either the gem or the node renderer package to match versions.

Production Environment:

Status: 200 OK (request allowed)

[WARN] React on Rails Pro gem version (4.0.0) does not match node renderer
version (4.0.1). Using exact matching versions is recommended for best
compatibility.

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):

  • Updated 11 existing tests to include railsEnv field in requests

New Tests Added (6 comprehensive tests):

  1. ✅ Allows request when gem version matches package version
  2. ✅ Rejects request in development when versions don't match (412 error)
  3. ✅ Allows request in production when versions don't match (with warning)
  4. ✅ Normalizes gem version with dot before prerelease (4.0.0.rc.1 == 4.0.0-rc.1)
  5. ✅ Normalizes gem version case-insensitively (4.0.0-RC.1 == 4.0.0-rc.1)
  6. ✅ Handles whitespace in gem version

Test Results:

  • Test Suites: 1 passed, 1 total
  • Tests: 17 passed, 17 total (11 updated + 6 new)
  • Time: 2.364 s

Files Changed

Release Script Changes

  • rakelib/release.rake - Unified release logic for all packages
  • rakelib/task_helpers.rb - Enhanced with Ruby version detection
  • docs/contributor-info/releasing.md - Complete documentation rewrite
  • react_on_rails_pro/CONTRIBUTING.md - Updated contributor guide
  • react_on_rails_pro/docs/contributors-info/releasing.md - Updated release docs
  • react_on_rails_pro/react_on_rails_pro.gemspec - Dependency updates

Version Validation Changes

  • lib/react_on_rails/engine.rb - Added validation initializer
  • lib/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 - Added railsEnv to request data
  • packages/node-renderer/src/worker/checkProtocolVersionHandler.ts - Added gem version validation with normalization
  • packages/node-renderer/tests/worker.test.ts - Updated existing tests + 6 new tests

Removed Files

  • react_on_rails_pro/rakelib/release.rake - Deprecated
  • react_on_rails_pro/script/release - No longer needed
  • react_on_rails_pro/package.json - Not needed at Pro root

Benefits

Unified Release Script

  • One command to release everything - No more switching between scripts
  • Prevents version mismatches - All packages updated atomically
  • Automatic Ruby version switching - No manual version management
  • Clearer mental model - One version number to track
  • Consistent dependency pinning - Exact versions everywhere
  • Reduced maintenance overhead - Single script to maintain

Strict Version Validation

  • Fail-fast - Errors caught at boot time, not runtime
  • Clear error messages - Users know exactly what's wrong and how to fix it
  • Prevents misconfigurations - No more version mismatches or conflicting packages
  • Better developer experience - Immediate feedback on configuration issues
  • Complements release script - Ensures versions installed match what was released

Node Renderer Validation

  • Runtime version enforcement - Catches version mismatches at request time
  • Environment-aware - Strict in development, permissive in production
  • Handles edge cases - Normalizes Ruby gem vs NPM version format differences
  • Clear error messages - Users know exactly which versions are mismatched
  • Complements boot-time validation - Provides additional layer of safety for remote renderers
  • Better debugging - Version mismatches identified immediately with clear warnings

Testing

Release Script Testing

# Dry run test
rake release[17.0.0,true]

# Verdaccio test
rake release[17.0.0,false,verdaccio]

# Test without pushing
rake release[17.0.0,false,npm,skip_push]

Validation Testing

# Run validation tests
bundle exec rspec spec/react_on_rails/version_checker_spec.rb

# Check linting
bundle exec rubocop lib/react_on_rails/version_checker.rb spec/react_on_rails/version_checker_spec.rb

Node Renderer Testing

# Run node renderer tests
cd react_on_rails_pro
yarn jest packages/node-renderer/tests/worker.test.ts

# Run all tests
yarn nps test

Migration Notes

For Contributors

  • Use the root rake release command instead of Pro-specific scripts
  • The script will automatically detect and switch Ruby versions as needed
  • All version files are now updated atomically

For Users

  • Applications will now fail to boot with clear error messages if package.json is misconfigured
  • Ensure exact versions in package.json (no ^, ~, etc.)
  • If using Pro, ensure both Pro gem and Pro npm package are installed
  • For remote node renderer users: Version mismatches will be caught at request time
    • Development: Requests will fail with 412 error
    • Production: Requests will succeed with warning logs

Fixes #1876

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]


This change is Reviewable

Summary by CodeRabbit

  • New Features

    • Stronger startup/version compatibility checks with clearer, actionable errors and environment-aware leniency for renderer/gem mismatches.
    • Package-manager detection with safe, manager-specific install/remove commands.
    • Remote node-renderer validates gem version per-request (strict in dev, permissive in prod) with normalization and caching.
  • Chores

    • Unified single-version release across packages with multi-registry publishing and local Verdaccio testing support; removed old per-package release scripts.
  • Documentation

    • Consolidated and rewritten release and contributor guidance.
  • Tests

    • New fixtures and expanded tests covering version checks, package-manager detection, and env-aware validation.

AbanoubGhadban and others added 16 commits October 26, 2025 14:02
- 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]>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 26, 2025

Walkthrough

Unifies 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

Cohort / File(s) Summary
Release Docs
docs/contributor-info/releasing.md, react_on_rails_pro/CONTRIBUTING.md, react_on_rails_pro/docs/contributors-info/releasing.md
Rewrote release documentation to describe a unified 5-package release, new rake signature rake release[version,dry_run,registry,skip_push], multi-registry publishing (npmjs.org / GitHub Packages / Verdaccio), auth/token steps, and expanded testing/troubleshooting guidance.
Unified Release Task & Removal
Root: rakelib/release.rake
Removed pro release: react_on_rails_pro/rakelib/release.rake (deleted), react_on_rails_pro/script/release (deleted), react_on_rails_pro/package.json
Replaced per-repo release with a root unified release task (arg renamed to version), unified version propagation across gems and npm packages, semver-bump or explicit-version handling, dry-run/skip_push/Verdaccio modes; removed pro-specific release automation and release-it config; updated messaging and artifact lists.
Version Validation & Engine Init
lib/react_on_rails/version_checker.rb, lib/react_on_rails/engine.rb, spec/react_on_rails/version_checker_spec.rb, spec/react_on_rails/fixtures/*
Replaced soft warnings with validate_version_and_package_compatibility! (raises on errors); added checks for package.json presence, package/gem compatibility, semver wildcard rejection, and exact-version equality; moved invocation to config.after_initialize; added fixtures and expanded tests.
Task Helpers & Ruby Switching
rakelib/task_helpers.rb
Added detect_bundler_ruby_version and bundle_install_with_ruby_version to detect required Ruby from Bundler and run bundle install via rvm/rbenv/asdf when needed; added require "English" and adjusted method visibility.
Pro Gem & Versioning
react_on_rails_pro/react_on_rails_pro.gemspec, react_on_rails_pro/lib/react_on_rails_pro/version.rb
Bumped Pro VERSION to 16.1.1; pro gem runtime dependency on react_on_rails now references ReactOnRails::VERSION dynamically (removed hard-coded ">= 16.0.0").
Node Renderer Runtime Check
react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts, react_on_rails_pro/packages/node-renderer/tests/worker.test.ts
Added gemVersion and railsEnv payload handling, prerelease normalization, comparison caching, and environment-aware behavior (development: reject mismatch; production: warn once); tests include railsEnv.
Package Manager Detection & Commands
lib/react_on_rails/utils.rb, spec/react_on_rails/utils_spec.rb
Added package-manager detection (:yarn/:pnpm/:bun/:npm) via package.json or lockfiles and helper methods to generate install/remove commands with validation and Shellwords escaping; added tests covering detection and command generation.
Test Fixtures
spec/react_on_rails/fixtures/both_packages.json, spec/react_on_rails/fixtures/pro_package.json, spec/react_on_rails/fixtures/pro_semver_caret_package.json
New fixtures modeling react-on-rails / react-on-rails-pro combinations (exact and caret semver) used by VersionChecker tests.
Misc — Pro utils
react_on_rails_pro/lib/react_on_rails_pro/utils.rb
Added railsEnv to common_form_data payload.
Changelogs
CHANGELOG.md, react_on_rails_pro/CHANGELOG.md
Documented breaking changes (strict boot-time validation, node renderer validation) and security note for command-injection protections.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Files/areas needing extra attention:
    • lib/react_on_rails/version_checker.rb — error messaging, semver detection, boot-time raising behavior and test coverage.
    • rakelib/release.rake — unified version propagation, registry branching, dry-run and skip_push semantics, and side-effect ordering.
    • rakelib/task_helpers.rb — external command construction, Ruby manager support, and failure handling.
    • lib/react_on_rails/utils.rb — package manager detection heuristics and shell-escaped command generation.
    • react_on_rails_pro/packages/node-renderer/src/worker/checkProtocolVersionHandler.ts — normalization/caching and environment gating.

Possibly related PRs

Suggested reviewers

  • justin808
  • Judahmeek
  • ihabadham

Poem

🐇 I hopped through diffs with a tiny drum,

One version to rule them — all packages come.
Validators guard the boot-time gate,
Ruby swaps smooth, installs cooperate.
A carrot for releases — unified and fun.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Unify release scripts and add strict version validation" directly and accurately summarizes the two primary changes in this PR. The changeset implements a unified release script that consolidates separate root and Pro release workflows into a single rake task (rakelib/release.rake rewritten, Pro-specific tasks removed), and adds strict boot-time version validation through the new validate_version_and_package_compatibility! method. The title is clear, specific, and captures the main developer intent without vagueness or noise.
Linked Issues Check ✅ Passed The PR satisfies all primary coding requirements from issue #1876. The unified versioning strategy is implemented with all packages synchronized to version 16.1.1 across six version files (engine, core/pro gems, core/pro NPM packages). The single root rake task (rakelib/release.rake) atomically updates all version locations, supports exact dependency pinning, semver bump types (patch/minor/major), and preserves dry-run, Verdaccio, skip-push, and uncommitted-changes validation. Strict version validation is enforced via boot-time checks including package.json existence, package conflict detection, prohibition of semver ranges, and exact gem-npm version matching. Node renderer gem-version validation is implemented with environment-aware behavior (412 in development, warning in production) and railsEnv propagation.
Out of Scope Changes Check ✅ Passed All changes directly support the stated PR objectives. The unified release implementation includes rakelib/release.rake rewrite, rakelib/task_helpers.rb enhancements for Ruby version detection, removal of Pro-specific release files, and lib/react_on_rails/utils.rb utilities for package manager command generation. Strict validation is implemented via lib/react_on_rails/engine.rb initializer and lib/react_on_rails/version_checker.rb with comprehensive test coverage and fixtures. Node renderer validation is added to checkProtocolVersionHandler.ts with supporting utils.rb changes and tests. Documentation, version bumps, gemspec updates, and changelog entries are all consistent with the unified versioning and validation objectives. No extraneous changes detected.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch strict-version-validation

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d16d32e and 85cbb19.

📒 Files selected for processing (2)
  • CHANGELOG.md (2 hunks)
  • react_on_rails_pro/CHANGELOG.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{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:

  • CHANGELOG.md
  • react_on_rails_pro/CHANGELOG.md
🧠 Learnings (2)
📚 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:

  • CHANGELOG.md
📚 Learning: 2025-02-18T13:08:01.477Z
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1644
File: lib/react_on_rails/helper.rb:190-197
Timestamp: 2025-02-18T13:08:01.477Z
Learning: RSC support validation in React on Rails Pro is handled through a chain of validations:
1. Pro version check in `run_stream_inside_fiber`
2. RSC support check during pack generation via `ReactOnRailsPro.configuration.enable_rsc_support`
3. RSC support validation during component registration
This makes additional validation in the helper methods unnecessary.

Applied to files:

  • react_on_rails_pro/CHANGELOG.md
⏰ 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)
  • GitHub Check: dummy-app-integration-tests (3.4, 22)
  • GitHub Check: dummy-app-integration-tests (3.2, 20)
  • GitHub Check: claude-review
  • GitHub Check: build-dummy-app-webpack-test-bundles
  • GitHub Check: rspec-package-tests (3.2, minimum)
  • GitHub Check: rspec-package-tests (3.4, latest)
  • GitHub Check: rspec-package-tests (3.2, latest)
  • GitHub Check: rspec-package-tests (3.4, minimum)
  • GitHub Check: build-dummy-app-webpack-test-bundles
  • GitHub Check: markdown-link-check
  • GitHub Check: build
  • GitHub Check: lint-js-and-ruby
🔇 Additional comments (4)
react_on_rails_pro/CHANGELOG.md (1)

33-33: Well-documented feature addition.

Line 33 clearly describes the node renderer gem version validation feature with environment-aware behavior, version normalization details, and proper attribution. The entry follows keepachangelog format and provides context for both development and production deployments.

CHANGELOG.md (3)

30-30: Clear and concise improvement entry.

The "Improved Error Messages" entry succinctly describes the enhancement with package-manager-specific commands, includes the PR reference, and maintains consistency with existing Added entries.


111-114: Comprehensive breaking changes documentation with migration guidance.

Both breaking change entries are thorough and actionable:

  • Line 111 clearly states the boot-time failure behavior, explains the exact-version requirement, and provides a concrete migration example.
  • Line 113 documents Pro-specific node renderer validation with environment-aware behavior (412 in development, warning in production) and clear migration step.

Both entries include appropriate PR references and align with the PR objectives for version validation enforcement.


115-117: Security section properly introduced and documented.

The new "Security" section is well-placed in the Breaking Changes area and the "Command Injection Protection" entry clearly describes the hardening without unnecessary detail. The entry includes the PR reference and is consistent with the security improvements described in the PR objectives.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
rakelib/task_helpers.rb (1)

97-101: Optional: tolerate Ruby patchlevel suffixes

Bundler may output ruby 3.2.1p20. Current regex captures 3.2.1, which works for equality against RUBY_VERSION; if you want to preserve prerelease and ignore optional p\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("-")
+      version
docs/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 (.npmrc content):

-  ```
+  ```ini
   //npm.pkg.github.com/:_authToken=<TOKEN>

For line 169 (.gem/credentials content):

-  ```
+  ```yaml
   :github: Bearer <GITHUB_TOKEN>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d527ddf and bf5681a.

⛔ Files ignored due to path filters (2)
  • react_on_rails_pro/spec/dummy/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/yarn.lock is 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.rb
  • rakelib/release.rake
  • rakelib/task_helpers.rb
  • react_on_rails_pro/react_on_rails_pro.gemspec
  • spec/react_on_rails/version_checker_spec.rb
  • lib/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.json
  • spec/react_on_rails/fixtures/pro_package.json
  • docs/contributor-info/releasing.md
  • react_on_rails_pro/CONTRIBUTING.md
  • react_on_rails_pro/docs/contributors-info/releasing.md
  • spec/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.rb
  • react_on_rails_pro/react_on_rails_pro.gemspec
  • spec/react_on_rails/version_checker_spec.rb
  • lib/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.json
  • react_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::VERSION enforces 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 violation

Looks 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 LGTM

Exact 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 signature

Commands 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 correct

Root, workspace packages, and pro node-renderer updated; pro depends on core with exact version. Good.


198-208: Workspace publish flow LGTM

Publishing core and pro via Yarn workspaces with --new-version aligns 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 find commands with -mindepth 2 and -mindepth 3 are 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 versioning

The 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_version in 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_location helper maintains DRY principles.


185-207: LGTM! Pro package correctly takes precedence.

The precedence logic (checking react-on-rails-pro before react-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_initialize timing 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-rails and react-on-rails-pro are installed, which should trigger the validation error in validate_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

Comment thread rakelib/task_helpers.rb
Comment thread rakelib/task_helpers.rb Outdated
Comment thread react_on_rails_pro/CONTRIBUTING.md Outdated
Comment thread react_on_rails_pro/react_on_rails_pro.gemspec
AbanoubGhadban and others added 2 commits October 26, 2025 19:55
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]>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Oct 26, 2025

Pull Request Review: Unify release scripts and add strict version validation

Summary

This 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.

🎯 Strengths

1. Unified Release Process ✅

  • Clear improvement: Consolidating two separate release scripts into one atomic process eliminates version drift
  • Smart implementation: Handles 5 packages with unified versioning
  • Developer-friendly: Semver bump support (patch/minor/major)
  • Well-documented: Extensive inline help and examples

2. Strict Version Validation ✅

  • Fail-fast approach: Catches misconfigurations at boot time
  • Excellent error messages: Clear, actionable messages with exact fix instructions
  • Comprehensive scenarios: 6 distinct validation cases with specific guidance
  • Good separation of concerns: Each validation in its own method

3. Test Coverage ✅

  • Thorough testing: 53 tests covering all validation scenarios
  • Good use of fixtures: New fixture files for Pro package testing
  • Proper mocking: Well-structured test doubles
  • Edge cases covered: Both packages, Pro-only, base-only, version mismatches

4. Code Quality ✅

  • DRY principle: Shared package_installed? helper
  • Clear method naming: react_on_rails_package?, react_on_rails_pro_package?
  • Good memoization: Prevents repeated file reads
  • Zero RuboCop offenses: Follows project style

🔍 Code Quality Observations

Version Checker (lib/react_on_rails/version_checker.rb)

Excellent:

  • Well-separated validation methods
  • Error messages include context
  • Pro package detection with precedence logic

Minor suggestions:

  1. Early return pattern (line 95): Double-negative logic could be clearer
  2. Edge case: Consider error handling for malformed JSON (line 262)

Release Script (rakelib/release.rake)

Excellent:

  • Clear progression: validate → bump → update → publish
  • Dry run and Verdaccio support
  • Atomic version updates across 6 locations

Observations:

  1. Consider documenting recovery steps for partial publish failures
  2. Pro version regex with word boundary is exactly right

🔒 Security ✅

  • Credentials handled correctly
  • Uncommitted changes check prevents accidents
  • Registry validation prevents typos

⚡ Performance ✅

  • File I/O properly memoized
  • Boot-time impact minimal (one-time validation)

🐛 Potential Issues

Critical: None ✅

Minor:

  1. JSON parsing error handling could be added
  2. Package precedence logic flow could be documented better

📚 Documentation Quality ✅

Outstanding:

  • Comprehensive PR description
  • Release docs completely rewritten
  • Clear inline comments
  • Error messages with troubleshooting

🧪 Testing Recommendations

Consider adding:

  1. Integration test in Rails boot context
  2. Malformed JSON test
  3. File permission test

🎨 Best Practices ✅

Follows CLAUDE.md requirements and Rails/Ruby conventions perfectly.

🚀 Migration Impact

Potentially breaking for misconfigured setups, but:

  • Error messages are clear and actionable ✅
  • Better to fail at boot than at runtime ✅

Recommendation: Consider temporary ENV flag (REACT_ON_RAILS_SKIP_VERSION_CHECK) for smoother migration.

📊 Overall Assessment

  • Code Quality: 9.5/10
  • Test Coverage: 10/10
  • Documentation: 10/10
  • Security: 10/10
  • Best Practices: 10/10

✅ Recommendation: APPROVE with minor suggestions

This PR is a significant quality improvement. The implementation is clean, well-tested, and thoroughly documented.

Optional improvements:

  1. Add JSON parsing error handling
  2. Consider ENV-based escape hatch for validation
  3. Add integration test for Rails boot validation
  4. Clarify Pro version gsub comment

Before merge:

  • ✅ All tests passing (53 specs)
  • ✅ Zero RuboCop offenses
  • ✅ Documentation complete
  • ✅ No security concerns
  • ⚠️ Consider migration impact

Great work! This will make releases much more reliable and user configurations much safer.


Review generated by Claude Code

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 fields

When 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
+      }.compact
react_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 polish

Consider 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

📥 Commits

Reviewing files that changed from the base of the PR and between bf5681a and e04c313.

⛔ Files ignored due to path filters (1)
  • react_on_rails_pro/spec/dummy/Gemfile.lock is 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.rb
  • react_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.ts
  • 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/tests/worker.test.ts
  • 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 (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 good

Including 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 coherently

The 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]>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Oct 26, 2025

Pull Request Review: Unified Release Scripts and Strict Version Validation

Overall Assessment

This 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

  1. Atomic Version Updates - All 6 version files updated together prevents inconsistencies
  2. Smart Ruby Version Handling - Auto-detection and switching is a game-changer
  3. Comprehensive Options - Dry-run, Verdaccio testing, skip-push provide flexibility
  4. Clear Documentation - Thorough desc with helpful examples
  5. Semver Support - Keywords and explicit versions

Code Quality Highlights

  • rakelib/release.rake:126 - Smart use of word boundary to avoid matching PROTOCOL_VERSION
  • rakelib/release.rake:146 - Package name comparison works well

Suggestions

  1. Consider error handling wrapper around gem bump call (line 103)
  2. Consider pre-flight check to ensure expected files exist

Part 2: Strict Version Validation - EXCELLENT ⭐

Strengths

  1. Fail-Fast Philosophy - Boot-time vs runtime error detection
  2. Clear Error Messages - Include problem, location, and fix commands
  3. Comprehensive Checks - All validation scenarios covered
  4. DRY Code - package_installed helper eliminates duplication

Suggestions

  1. Add tests for malformed JSON edge cases
  2. Consider config option to disable in production (though overhead is negligible)

Part 3: Node Renderer Version Validation - VERY GOOD ⭐

Strengths

  1. Environment-Aware - Strict in dev, permissive in prod
  2. Smart Normalization - Handles Ruby gem vs NPM format differences
  3. Caching - Prevents repeated logging
  4. Comprehensive Testing - 17 tests including edge cases

Suggestions

  1. Document that either railsEnv or NODE_ENV being production triggers permissive mode
  2. Test single-segment prereleases like 4.0.0.rc1
  3. Consider REACT_ON_RAILS_STRICT_VERSION_CHECK env var for staging

Part 4: Ruby Version Auto-Switching - VERY GOOD ⭐

Strengths

  1. Version Manager Support - rvm, rbenv, asdf
  2. Error Handling - Clear failure messages
  3. Smart Detection - bundle platform --ruby approach
  4. Same-Shell Context - Version switch persists

Suggestions

  1. Consider caching detected versions
  2. Document manual testing procedure

Summary Scores

Security: ✅ No Issues
Performance: ✅ Good
Testing: ✅ Excellent (53 version checker tests, 17 node renderer tests, zero RuboCop offenses)
Documentation: ⭐ Outstanding
Code Style: ✅ Perfect


Final Recommendations

Must Address

  • None - production-ready as-is

Should Consider

  1. Error handling around gem bump
  2. Document environment detection behavior
  3. Test single-segment prereleases

Nice to Have

  1. Cache Ruby version detection
  2. Integration tests for release workflow
  3. Update CLAUDE.md with new process

Summary

This PR represents a significant improvement to React on Rails:

✅ Eliminates version mismatches at multiple levels
✅ Reduces maintenance burden
✅ Improves developer experience
✅ Well-tested with comprehensive coverage
✅ Excellent documentation

Code quality is high, architecture is sound, implementation is thorough.

Great work! 🎉


Review by Claude Code per CLAUDE.md guidelines

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e04c313 and 730798c.

📒 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.14.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 justCached flag 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unify release scripts and automate version management across all packages

2 participants