Skip to content

Add shakapacker version update command; bump to 9.6.1#2569

Merged
justin808 merged 2 commits intomasterfrom
jg/shakapacker-version-cmd
Mar 9, 2026
Merged

Add shakapacker version update command; bump to 9.6.1#2569
justin808 merged 2 commits intomasterfrom
jg/shakapacker-version-cmd

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Mar 8, 2026

Summary

  • Adds rake shakapacker:update_version[VERSION] to update all shakapacker version references and lock files across the monorepo in one command
  • The task validates version format, updates Gemfiles (preserving = pin prefixes), updates package.json (preserving ^/~ prefixes), runs bundle update shakapacker for all Gemfile.lock files, and runs pnpm install for pnpm-lock.yaml
  • Handles Ruby version switching for apps requiring different Ruby versions, and continues gracefully if a single lock file update fails
  • Updates shakapacker from 9.6.0 to 9.6.1 using the new command (all 13 files: 3 Gemfiles, 3 package.json, 6 Gemfile.lock, 1 pnpm-lock.yaml)

Test plan

  • Verify rake shakapacker:update_version[9.6.1] correctly updates all version references and lock files
  • Verify the command preserves file formatting (no extraneous diffs)
  • Verify rubocop passes with no offenses
  • Verify all pre-commit and pre-push hooks pass
  • CI passes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Updated shakapacker to 9.6.1 across projects and sample apps.
    • Added an automated version-update task to propagate shakapacker upgrades across Gemfiles, package manifests, and lockfiles.
  • Documentation

    • Added guidance for using the update task, testing expectations, and an example CI workflow entry.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 8, 2026

Walkthrough

Adds a new rake task to update shakapacker across the monorepo and bumps shakapacker from 9.6.0 → 9.6.1 in multiple Gemfiles and package.json files; also updates docs with usage and testing guidance.

Changes

Cohort / File(s) Summary
Shakapacker Version Bump (9.6.0 → 9.6.1)
react_on_rails/Gemfile.development_dependencies, react_on_rails_pro/Gemfile.development_dependencies, react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile, react_on_rails/spec/dummy/package.json, react_on_rails_pro/spec/dummy/package.json, react_on_rails_pro/spec/execjs-compatible-dummy/package.json
Updated shakapacker pins from 9.6.09.6.1.
Automation tooling (new)
react_on_rails/rakelib/shakapacker_version.rake
New shakapacker:update_version(version) Rake task and private helpers: validate semver-like version, update Gemfiles and package.jsons (preserving prefixes), update Gemfile.lock via per-dir bundle update with Ruby-version handling, and run pnpm install at monorepo root. Includes logging and error handling.
Docs / CI guidance
AGENTS.md
Added "Updating Shakapacker" section describing the rake task, CI example rake shakapacker:update_version[9.6.1], and expanded local testing guidance across Ruby and JS ecosystems.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant Rake as Rake Task
  participant FS as Repo Files
  participant Bundler as Bundler
  participant PNPM as pnpm

  Dev->>Rake: rake shakapacker:update_version[9.6.1]
  Rake->>FS: scan for Gemfiles, package.json, lockfiles
  Rake->>FS: replace shakapacker pins in matched files
  Rake->>Bundler: run per-dir bundle update (handles ruby version managers)
  Bundler-->>Rake: per-dir success / error
  Rake->>PNPM: run pnpm install at monorepo root
  PNPM-->>Rake: success / error
  Rake->>Dev: summary logs and guidance
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through Gemfiles, quick and spry,
Bumped nine-six-oh to nine-six-one — a tiny try.
A Rake task hums, it finds and fixes locks,
Bundler and pnpm join my happy hops,
Off I bound, carrots clutched — update done! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: introducing a new rake task for shakapacker version updates and bumping the version to 9.6.1 across the monorepo.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jg/shakapacker-version-cmd

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot added dependencies Pull requests that update a dependency file full-ci P2 Backlog priority labels Mar 8, 2026
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 8, 2026

Review: Add shakapacker version update command; bump to 9.6.1

The version bump changes themselves look correct and consistent. The new rake task is a useful maintenance tool, but a few implementation issues are worth addressing.

1. Top-level method definitions pollute Object (main concern)

update_gemfiles, update_package_jsons, and relative_path are defined with top-level def, making them private instance methods on Object accessible from anywhere in the Ruby process. No other rake file in this repo defines top-level helpers — they rely solely on methods from ReactOnRails::TaskHelpers. These should be scoped: move the logic inline into the task, add them to a private module, or extend TaskHelpers.

2. Unused require

require "json" is never used. The implementation switched to regex instead of JSON parsing; this line should be removed.

3. No version format validation

Any string is accepted as a version. A malformed input like rake shakapacker:update_version[v9.6.1] silently writes broken strings into all files. A simple guard would help: raise ... unless version.match?(/\A\d+\.\d+\.\d+/)

4. npm range prefixes silently skipped (worth documenting)

The package.json regex only matches bare version strings. "shakapacker": "^9.6.0" would be skipped without warning. Fine for this repo's pinned usage, but worth noting in the task description.

Minor: Hyphen in [a-zA-Z0-9.\-] is conventionally placed at the end ([a-zA-Z0-9.-]) to avoid range-syntax ambiguity.

Note on lock files: The PR merges before 9.6.1 is published to RubyGems/npm. Any CI job that runs bundle install or pnpm install from scratch will fail until the package is actually published.

@@ -0,0 +1,69 @@
# frozen_string_literal: true

require "json"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This require "json" is unused — the implementation uses regex instead of JSON parsing. Remove it.

end
end

def update_gemfiles(version)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Defining update_gemfiles, update_package_jsons, and relative_path at the top level (outside the namespace) makes them private instance methods on Object, polluting the global method namespace for the entire Ruby process.

The pattern used by every other rake file in this repo is to call methods from ReactOnRails::TaskHelpers (included in the namespace block). The helper logic here should either be inlined into the task body, or the methods should be moved into TaskHelpers / a private module.

Suggested change
def update_gemfiles(version)
def update_gemfiles(version)

Note: the suggestion above keeps the line as-is — the real fix is to move all three method definitions inside a module or into TaskHelpers rather than at the top level.

desc "Update shakapacker version across all Gemfiles and package.json files. " \
"Usage: rake shakapacker:update_version[9.6.1]"
task :update_version, [:version] do |_t, args|
version = args[:version]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No validation of the version format is performed. A caller could accidentally pass v9.6.1 (with a v prefix) or any other malformed string and the task would silently write it into every file.

Suggested change
version = args[:version]
version = args[:version]
raise "Version argument required. Usage: rake shakapacker:update_version[9.6.1]" unless version
raise "Invalid version format '#{version}'. Expected semver like '9.6.1'" unless version.match?(/\A\d+\.\d+\.\d+/)

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 8, 2026

Greptile Summary

This PR introduces a new rake shakapacker:update_version[VERSION] task to synchronize the shakapacker version across all Gemfiles and package.json files in the monorepo in a single command, and uses it to bump shakapacker from 9.6.0 → 9.6.1 across 6 files. The regex-based approach correctly preserves original file formatting.

Key observations:

  • The new rake task works correctly for its intended purpose and handles both unqualified ("9.6.0") and pinned ("= 9.6.0") Gemfile version formats.
  • require "json" on line 3 is imported but never used — the implementation relies on regex substitution rather than JSON parsing.
  • Lock files are intentionally not updated pending publication of shakapacker 9.6.1 to RubyGems/npm, which is clearly documented in the PR description.

All 6 version-bump changes are clean single-line diffs with no functional issues.

Confidence Score: 4/5

  • Safe to merge; the version bump is straightforward and the new rake task works correctly with only a minor unused import.
  • All 6 version-bump changes are clean single-line diffs. The new rake task is functionally correct for its intended purpose of synchronizing versions across the monorepo. The single deduction is for the unused require "json" on line 3 of the rake file, which is a trivial cleanup issue.
  • react_on_rails/rakelib/shakapacker_version.rake — contains an unused require that should be removed.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["rake shakapacker:update_version VERSION"] --> B{version provided?}
    B -- No --> C["raise error"]
    B -- Yes --> D["update_gemfiles(version)"]
    D --> E["Dir.glob Gemfile* \nexclude .lock and gen-examples"]
    E --> F["regex gsub gem shakapacker version"]
    F --> G{changed?}
    G -- Yes --> H["File.write updated content"]
    G -- No --> I["skip"]
    H --> J["update_package_jsons(version)"]
    I --> J
    J --> K["Dir.glob package.json\nexclude node_modules and gen-examples"]
    K --> L["regex gsub shakapacker version"]
    L --> M{changed?}
    M -- Yes --> N["File.write updated content"]
    M -- No --> O["skip"]
    N --> P["Done: remind to run bundle update and pnpm install"]
    O --> P
Loading

Last reviewed commit: 82f47a8

@@ -0,0 +1,69 @@
# frozen_string_literal: true

require "json"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The require "json" on this line is imported but never used. The implementation correctly relies on regex substitution to avoid JSON reformatting artifacts, so this dependency can be safely removed.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is ON, but it could not run because Privacy Mode (Legacy) is turned on. To enable Bugbot Autofix, switch your privacy mode in the Cursor dashboard.

@@ -0,0 +1,69 @@
# frozen_string_literal: true

require "json"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused require "json" import in rake file

Low Severity

require "json" is imported but never used anywhere in the file. The implementation deliberately uses regex-based replacement (as noted in comments) instead of JSON parsing to preserve formatting. The JSON module is never referenced. This appears to be a leftover from an earlier implementation approach that was switched to regex.

Fix in Cursor Fix in Web

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82f47a8abe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"sass-loader": "^12.3.0",
"sass-resources-loader": "^2.1.0",
"shakapacker": "9.6.0",
"shakapacker": "9.6.1",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Regenerate pnpm lockfile after shakapacker bump

This version bump updates workspace package.json files to 9.6.1 but does not update pnpm-lock.yaml (which still pins these importers to 9.6.0), so CI jobs that run pnpm install --frozen-lockfile (for example in .github/workflows/lint-js-and-ruby.yml and other frozen-lockfile workflows) will fail before tests run.

Useful? React with 👍 / 👎.

eval_gemfile File.expand_path("../Gemfile.shared_dev_dependencies", __dir__)

gem "shakapacker", "9.6.0"
gem "shakapacker", "9.6.1"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Update Gemfile.lock when changing shakapacker Gemfile pin

The Gemfile pin is changed to 9.6.1 while the corresponding lockfiles still resolve shakapacker (9.6.0), and Ruby CI runs with BUNDLE_FROZEN=true for the latest matrix (see .github/workflows/gem-tests.yml), so bundle install in react_on_rails will fail due to frozen lockfile mismatch.

Useful? React with 👍 / 👎.

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

🧹 Nitpick comments (1)
react_on_rails/rakelib/shakapacker_version.rake (1)

3-3: Unused import: require "json" is not used.

The file uses regex-based string replacement rather than JSON parsing. This import can be removed.

🧹 Proposed fix
 # frozen_string_literal: true

-require "json"
-
 require_relative "task_helpers"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/rakelib/shakapacker_version.rake` at line 3, Remove the unused
JSON import by deleting the top-level require "json" statement; locate the
require "json" token in the rake file (it is currently the only require in
shakapacker_version.rake) and remove it so the file uses its existing
regex/string-replacement logic without importing the json library.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@react_on_rails/rakelib/shakapacker_version.rake`:
- Around line 54-58: The current package.json regex in the shakapacker updater
silently fails for npm prefixes like ^ or ~; update the pattern used when
building updated (the regex passed to content.gsub and the replacement using
Regexp.last_match) to capture and preserve an optional npm prefix (e.g., ^ or ~,
and optionally = if desired) before the numeric version, and include that
captured prefix in the replacement so the new version string keeps the original
prefix instead of skipping files that used it.

In `@react_on_rails/spec/dummy/package.json`:
- Line 56: The package.json manifest was bumped to "shakapacker": "9.6.1" but
pnpm-lock.yaml still pins 9.6.0, causing CI failures with pnpm install
--frozen-lockfile; to fix, run pnpm install (or pnpm install --lockfile-only)
locally to regenerate pnpm-lock.yaml so it matches the new shakapacker 9.6.1
entry, verify the lockfile changes, and commit the updated pnpm-lock.yaml
alongside the package.json change (alternatively revert the manifest bump if you
prefer to wait).

---

Nitpick comments:
In `@react_on_rails/rakelib/shakapacker_version.rake`:
- Line 3: Remove the unused JSON import by deleting the top-level require "json"
statement; locate the require "json" token in the rake file (it is currently the
only require in shakapacker_version.rake) and remove it so the file uses its
existing regex/string-replacement logic without importing the json library.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8bed09f-0b47-4bc3-90d5-c176668e621f

📥 Commits

Reviewing files that changed from the base of the PR and between 61b1f49 and 82f47a8.

📒 Files selected for processing (7)
  • react_on_rails/Gemfile.development_dependencies
  • react_on_rails/rakelib/shakapacker_version.rake
  • react_on_rails/spec/dummy/package.json
  • react_on_rails_pro/Gemfile.development_dependencies
  • react_on_rails_pro/spec/dummy/package.json
  • react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile
  • react_on_rails_pro/spec/execjs-compatible-dummy/package.json

Comment thread react_on_rails/rakelib/shakapacker_version.rake Outdated
Comment thread react_on_rails/spec/dummy/package.json
cmd = case version_manager
when "rvm" then "rvm #{version} do bundle update shakapacker"
when "rbenv" then "RBENV_VERSION=#{version} bundle update shakapacker"
when "asdf" then "asdf shell ruby #{version} && bundle update shakapacker"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

asdf shell ruby #{version} sets the Ruby version in the current shell session, but when the command is executed as a subprocess via sh, it runs in a child shell that exits immediately — the environment change never takes effect for the subsequent bundle update shakapacker call in the same string.

The reliable approach for asdf is to use either asdf exec or the env var directly:

Suggested change
when "asdf" then "asdf shell ruby #{version} && bundle update shakapacker"
when "asdf" then "ASDF_RUBY_VERSION=#{version} bundle update shakapacker"

Note the same issue exists in task_helpers.rb's bundle_install_with_ruby_version.

# gem "shakapacker", "9.6.0"
# gem "shakapacker", "= 9.6.0"
updated = content.gsub(
/gem "shakapacker",\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The regex only matches double-quoted gem "shakapacker" declarations. Gemfiles that use single quotes (gem 'shakapacker', '9.6.0') will be silently skipped.

Suggested change
/gem "shakapacker",\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/
/gem ['"]shakapacker['"]/,\s*['"](?:=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)['"]/

Or more simply, extend the character class to match both quote styles:

/gem ["']shakapacker["'],\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/

(Full fix would also handle single-quoted version strings, but the Gemfiles in this repo appear to use double quotes consistently, so this may be acceptable as a known limitation — worth documenting with a comment.)

end
end

def bundle_update_with_ruby_version(dir, version)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This duplicates the version-manager case logic from task_helpers.rb's bundle_install_with_ruby_version, but with two differences:

  1. It adds mise support (which task_helpers.rb is missing).
  2. It raises immediately on an unknown manager, whereas task_helpers.rb prints a user-friendly warning before raising.

Consider extracting the shared "build the switch command for manager X" logic into a single method in TaskHelpers (e.g., ruby_version_switch_command(version, cmd)) that both bundle_install_with_ruby_version and bundle_update_with_ruby_version can call. This would also let you add mise support to bundle_install_in in one place.

.reject { |f| f.include?("gen-examples") }
.select { |f| File.read(f).include?("shakapacker") }

gemfile_locks.each do |lockfile|
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The rescue here is attached to the do..end block (implicit begin), which is valid Ruby but can be surprising: it catches errors from all code in the block, including File.dirname and shakapacker_relative_path, not just bundle_update_shakapacker_in.

Also note that if bundle_update_shakapacker_in raises, rel will have already been set, so the rescue message is correct — but it's still worth an explicit begin/rescue/end around just the call you intend to be fallible:

gemfile_locks.each do |lockfile|
  dir = File.dirname(lockfile)
  rel = shakapacker_relative_path(dir)
  puts "  bundle update shakapacker in #{rel}"
  begin
    bundle_update_shakapacker_in(dir)
  rescue StandardError => e
    puts "    WARNING: Failed to update #{rel}: #{e.message}"
    puts "    You may need to update this lock file manually."
  end
end

task :update_version, [:version] do |_t, args|
version = args[:version]
raise "Version argument required. Usage: rake shakapacker:update_version[9.6.1]" unless version
unless version.match?(/\A\d+\.\d+\.\d+([.\-a-zA-Z0-9]*)?\z/)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: the outer capture group with ? is redundant since * already allows zero matches. This is harmless but slightly confusing:

/\A\d+\.\d+\.\d+[.\-a-zA-Z0-9]*\z/

Also, the . inside the character class is a literal dot (which is correct), but - should be placed first or last to avoid being interpreted as a range in some contexts — though \- works fine here.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 9, 2026

Review: Add shakapacker version update command + bump to 9.6.1

The version bump changes look correct and comprehensive — all 13 files updated consistently. The new rake task is a good addition for keeping version references in sync. A few issues worth addressing:

Bugs / Behavioral Issues

  1. asdf command won't work in a subprocess (line 110): 'asdf shell ruby VERSION' sets the version for the current shell session, but 'sh' spawns a child process — the environment change is lost before 'bundle update shakapacker' runs. Use 'ASDF_RUBY_VERSION=VERSION' env var instead. See inline comment. The same bug exists in task_helpers.rb's bundle_install_with_ruby_version — worth fixing there too.

  2. Single-quoted Gemfile declarations silently skipped (line 37): The regex gem "shakapacker" won't match gem 'shakapacker', '9.6.0'. Not a problem for files in this repo today, but worth a comment or a broader pattern.

Code Quality

  1. Duplicated version-manager logic (lines 105-115): bundle_update_with_ruby_version duplicates the case version_manager pattern from task_helpers.rb's bundle_install_with_ruby_version, but with inconsistencies: it adds 'mise' support that task_helpers.rb lacks, and it raises immediately on an unknown manager rather than printing a friendly error. Worth extracting a shared helper in TaskHelpers so both methods stay in sync.

  2. Implicit rescue scope in each block (lines 78-86): Attaching rescue to a do..end block is valid Ruby but catches exceptions from all code in the block, not just bundle_update_shakapacker_in. An explicit begin/rescue/end around the intended call is clearer. See inline comment.

  3. Redundant regex group (line 13): The ([...]*)? pattern has a redundant ? — * already allows zero matches.

Overall

The PR is a solid improvement — the automated update task is the right abstraction for a monorepo with 13+ version references. The version bump itself is clean. The issues above are mostly minor quality items; the asdf fix is the only one with real behavioral impact.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 9, 2026

size-limit report 📦

Path Size
react-on-rails/client bundled (gzip) 62.6 KB (0%)
react-on-rails/client bundled (gzip) (time) 62.6 KB (0%)
react-on-rails/client bundled (brotli) 53.62 KB (-0.05% 🔽)
react-on-rails/client bundled (brotli) (time) 53.65 KB (+0.05% 🔺)
react-on-rails-pro/client bundled (gzip) 63.6 KB (0%)
react-on-rails-pro/client bundled (gzip) (time) 63.6 KB (0%)
react-on-rails-pro/client bundled (brotli) 54.62 KB (0%)
react-on-rails-pro/client bundled (brotli) (time) 54.62 KB (0%)
registerServerComponent/client bundled (gzip) 127.37 KB (0%)
registerServerComponent/client bundled (gzip) (time) 127.37 KB (0%)
registerServerComponent/client bundled (brotli) 61.61 KB (0%)
registerServerComponent/client bundled (brotli) (time) 61.61 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 121.94 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) (time) 121.94 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 56.65 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) (time) 56.65 KB (0%)

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

🧹 Nitpick comments (1)
react_on_rails/rakelib/shakapacker_version.rake (1)

19-21: Separate manifest rewrites from lockfile refresh.

This always jumps straight from the text replacements into lockfile resolution. Making update_shakapacker_lock_files opt-in, or moving it to a second task, would keep the command usable for manifest-only updates and let maintainers run the resolver step later.

🔧 One way to split the phases
-  desc "Update shakapacker version in all Gemfiles, package.json, and lock files. " \
-       "Usage: rake shakapacker:update_version[9.6.1]"
-  task :update_version, [:version] do |_t, args|
+  desc "Update shakapacker version references. " \
+       "Usage: rake shakapacker:update_version[9.6.1,true]"
+  task :update_version, %i[version update_locks] do |_t, args|
     version = args[:version]
+    update_locks = args[:update_locks] == "true"
     raise "Version argument required. Usage: rake shakapacker:update_version[9.6.1]" unless version
     unless version.match?(/\A\d+\.\d+\.\d+([.\-a-zA-Z0-9]*)?\z/)
       raise "Invalid version format '#{version}'. Expected semver like '9.6.1' or '9.6.0.beta.0'"
     end

     puts "Updating shakapacker to #{version} across the monorepo..."

     update_shakapacker_gemfiles(version)
     update_shakapacker_package_jsons(version)
-    update_shakapacker_lock_files
+    update_shakapacker_lock_files if update_locks
   end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/rakelib/shakapacker_version.rake` around lines 19 - 21, The
current rake task unconditionally calls update_shakapacker_lock_files after
doing text replacements, which forces lockfile resolution; change this so
lockfile refresh is opt-in or moved to a separate task: remove the direct call
to update_shakapacker_lock_files from the manifest-update task and either (a)
create a new rake task (e.g., shakapacker:refresh_lockfiles) that invokes
update_shakapacker_lock_files, or (b) guard the call with an environment flag
(e.g., run only when ENV['REFRESH_LOCKFILES']=='true') so
update_shakapacker_gemfiles and update_shakapacker_package_jsons can run
independently of update_shakapacker_lock_files.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@react_on_rails/rakelib/shakapacker_version.rake`:
- Around line 13-14: The version validation regex in the unless block (the
version.match? check) is too permissive and allows trailing or repeated
separators like "9.6.1-" or "9.6.1...."; replace the existing pattern with a
stricter one that requires an initial MAJOR.MINOR.PATCH and only allows
additional prerelease/build segments that begin with a dot or dash followed by
at least one alphanumeric token (no empty tokens, no trailing separators).
Update the regex used in the unless condition (the version.match? call) to
enforce the pattern so only valid semver-like strings such as "9.6.1",
"9.6.0.beta.0", or "9.6.1-rc1" pass.
- Around line 74-82: The task iterates over Gemfile* variants but only targets
Gemfile.lock files; update the loop and the bundle_update_shakapacker_in helper
so it accepts the originating Gemfile basename (e.g.,
"Gemfile.development_dependencies") and uses that to set BUNDLE_GEMFILE when
invoking Bundler; specifically, when iterating in the block that computes rel
via shakapacker_relative_path and calls bundle_update_shakapacker_in(dir), also
determine the matching Gemfile basename for that lockfile and pass it into
bundle_update_shakapacker_in(dir, gemfile_basename), and modify
bundle_update_shakapacker_in to export ENV["BUNDLE_GEMFILE"]=gemfile_basename
(or the full path) before running bundle update so Bundler regenerates the
correct lockfile for non-default manifests.

---

Nitpick comments:
In `@react_on_rails/rakelib/shakapacker_version.rake`:
- Around line 19-21: The current rake task unconditionally calls
update_shakapacker_lock_files after doing text replacements, which forces
lockfile resolution; change this so lockfile refresh is opt-in or moved to a
separate task: remove the direct call to update_shakapacker_lock_files from the
manifest-update task and either (a) create a new rake task (e.g.,
shakapacker:refresh_lockfiles) that invokes update_shakapacker_lock_files, or
(b) guard the call with an environment flag (e.g., run only when
ENV['REFRESH_LOCKFILES']=='true') so update_shakapacker_gemfiles and
update_shakapacker_package_jsons can run independently of
update_shakapacker_lock_files.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 90e29845-2e5d-426b-aa27-5019351d364b

📥 Commits

Reviewing files that changed from the base of the PR and between 82f47a8 and dadc652.

⛔ Files ignored due to path filters (6)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • react_on_rails/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails/spec/dummy/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/spec/dummy/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • react_on_rails/Gemfile.development_dependencies
  • react_on_rails/rakelib/shakapacker_version.rake
  • react_on_rails/spec/dummy/package.json
  • react_on_rails_pro/Gemfile.development_dependencies
  • react_on_rails_pro/spec/dummy/package.json
  • react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile
  • react_on_rails_pro/spec/execjs-compatible-dummy/package.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • react_on_rails/spec/dummy/package.json
  • react_on_rails_pro/spec/dummy/package.json
  • react_on_rails_pro/spec/execjs-compatible-dummy/package.json
  • react_on_rails_pro/Gemfile.development_dependencies

Comment on lines +13 to +14
unless version.match?(/\A\d+\.\d+\.\d+([.\-a-zA-Z0-9]*)?\z/)
raise "Invalid version format '#{version}'. Expected semver like '9.6.1' or '9.6.0.beta.0'"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Tighten the version validator.

/\A\d+\.\d+\.\d+([.\-a-zA-Z0-9]*)?\z/ also accepts malformed inputs like 9.6.1- and 9.6.1...., so a typo can rewrite multiple manifests before anything fails.

🔧 Proposed fix
-    unless version.match?(/\A\d+\.\d+\.\d+([.\-a-zA-Z0-9]*)?\z/)
+    unless version.match?(/\A\d+\.\d+\.\d+(?:[-.][0-9A-Za-z]+)*\z/)
       raise "Invalid version format '#{version}'. Expected semver like '9.6.1' or '9.6.0.beta.0'"
     end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
unless version.match?(/\A\d+\.\d+\.\d+([.\-a-zA-Z0-9]*)?\z/)
raise "Invalid version format '#{version}'. Expected semver like '9.6.1' or '9.6.0.beta.0'"
unless version.match?(/\A\d+\.\d+\.\d+(?:[-.][0-9A-Za-z]+)*\z/)
raise "Invalid version format '#{version}'. Expected semver like '9.6.1' or '9.6.0.beta.0'"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/rakelib/shakapacker_version.rake` around lines 13 - 14, The
version validation regex in the unless block (the version.match? check) is too
permissive and allows trailing or repeated separators like "9.6.1-" or
"9.6.1...."; replace the existing pattern with a stricter one that requires an
initial MAJOR.MINOR.PATCH and only allows additional prerelease/build segments
that begin with a dot or dash followed by at least one alphanumeric token (no
empty tokens, no trailing separators). Update the regex used in the unless
condition (the version.match? call) to enforce the pattern so only valid
semver-like strings such as "9.6.1", "9.6.0.beta.0", or "9.6.1-rc1" pass.

Comment on lines +74 to +82
gemfile_locks = Dir.glob(File.join(monorepo_root, "**", "Gemfile.lock"))
.reject { |f| f.include?("gen-examples") }
.select { |f| File.read(f).include?("shakapacker") }

gemfile_locks.each do |lockfile|
dir = File.dirname(lockfile)
rel = shakapacker_relative_path(dir)
puts " bundle update shakapacker in #{rel}"
bundle_update_shakapacker_in(dir)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
from pathlib import Path

for lockfile in sorted(Path('.').rglob('Gemfile*.lock')):
    if lockfile.name == 'Gemfile.lock':
        continue
    if any(part in {'.git', 'node_modules'} for part in lockfile.parts):
        continue

    text = lockfile.read_text(errors='ignore')
    if 'shakapacker' not in text:
        continue

    gemfile = lockfile.with_suffix('')  # strip .lock
    print(f"missed lockfile: {lockfile}")
    print(f"  matching gemfile: {gemfile} (exists={gemfile.exists()})")
PY

Repository: shakacode/react_on_rails

Length of output: 50


🏁 Script executed:

fd -e development_dependencies

Repository: shakacode/react_on_rails

Length of output: 167


🏁 Script executed:

find . -name "*development_dependencies*" -type f | grep -v ".git" | head -20

Repository: shakacode/react_on_rails

Length of output: 171


🏁 Script executed:

find . -name "Gemfile.development_dependencies.lock" -type f | grep -v ".git"

Repository: shakacode/react_on_rails

Length of output: 50


🏁 Script executed:

grep -r "shakapacker" react_on_rails/Gemfile.development_dependencies react_on_rails_pro/Gemfile.development_dependencies 2>/dev/null || echo "shakapacker not found"

Repository: shakacode/react_on_rails

Length of output: 221


🏁 Script executed:

cat react_on_rails/Gemfile.development_dependencies react_on_rails_pro/Gemfile.development_dependencies

Repository: shakacode/react_on_rails

Length of output: 3713


🏁 Script executed:

cat -n react_on_rails/rakelib/shakapacker_version.rake

Repository: shakacode/react_on_rails

Length of output: 5200


🏁 Script executed:

grep -n "bundle_update_shakapacker_in" react_on_rails/rakelib/shakapacker_version.rake

Repository: shakacode/react_on_rails

Length of output: 153


🏁 Script executed:

cat -n react_on_rails/rakelib/task_helpers.rb

Repository: shakacode/react_on_rails

Length of output: 5432


🏁 Script executed:

grep -A5 "unbundled_sh_in_dir\|sh_in_dir" react_on_rails/rakelib/task_helpers.rb | head -30

Repository: shakacode/react_on_rails

Length of output: 1057


Handle non-default lockfiles to maintain consistency with updated Gemfiles.

This task updates all Gemfile* variants including Gemfile.development_dependencies (lines 26–48), but only bundles Gemfile.lock files (line 74). If Gemfile.development_dependencies is bundled elsewhere, its lockfile will not be regenerated here, leaving dependencies inconsistent. The bundle_update_shakapacker_in helper needs to accept the originating Gemfile basename (e.g., Gemfile.development_dependencies) and pass it via BUNDLE_GEMFILE environment variable so Bundler processes the correct manifest.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/rakelib/shakapacker_version.rake` around lines 74 - 82, The
task iterates over Gemfile* variants but only targets Gemfile.lock files; update
the loop and the bundle_update_shakapacker_in helper so it accepts the
originating Gemfile basename (e.g., "Gemfile.development_dependencies") and uses
that to set BUNDLE_GEMFILE when invoking Bundler; specifically, when iterating
in the block that computes rel via shakapacker_relative_path and calls
bundle_update_shakapacker_in(dir), also determine the matching Gemfile basename
for that lockfile and pass it into bundle_update_shakapacker_in(dir,
gemfile_basename), and modify bundle_update_shakapacker_in to export
ENV["BUNDLE_GEMFILE"]=gemfile_basename (or the full path) before running bundle
update so Bundler regenerates the correct lockfile for non-default manifests.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 9, 2026

Review: Add shakapacker version update command; bump to 9.6.1

The version bump itself (9.6.0 to 9.6.1) across all lock files, Gemfiles, and package.json files looks clean and consistent - all 13 files updated correctly.

The new rake shakapacker:update_version[VERSION] task is a useful addition. A few issues to address below.

update_shakapacker_lock_files
end

private
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

private has no effect here. Inside a Rake namespace block, def methods are defined on main (the top-level object), not inside a class or module body, so the private call does not restrict visibility. The methods remain publicly accessible globally. The existing shakapacker_examples.rake omits this marker entirely, which is the correct approach — the private call should be removed to avoid creating a false impression of encapsulation.

# gem "shakapacker", "9.6.0"
# gem "shakapacker", "= 9.6.0"
updated = content.gsub(
/gem "shakapacker",\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This regex only matches double-quoted gem declarations. Single-quoted entries like gem 'shakapacker', '9.6.0' would be silently skipped, leaving that file stale with no warning. Consider expanding the pattern to handle both quote styles:

Suggested change
/gem "shakapacker",\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/
/gem ["']shakapacker["'],\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/

Or more robustly, use a character class for the surrounding quotes:

/gem (["'])shakapacker\1,\s*(["'])(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)\2/

Comment on lines +105 to +115
def bundle_update_with_ruby_version(dir, version)
version_manager = ENV.fetch("RUBY_VERSION_MANAGER", "rvm")
cmd = case version_manager
when "rvm" then "rvm #{version} do bundle update shakapacker"
when "rbenv" then "RBENV_VERSION=#{version} bundle update shakapacker"
when "asdf" then "asdf shell ruby #{version} && bundle update shakapacker"
when "mise" then "mise exec ruby@#{version} -- bundle update shakapacker"
else raise "Unsupported RUBY_VERSION_MANAGER: #{version_manager}"
end
unbundled_sh_in_dir(dir, cmd)
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This method duplicates nearly all of bundle_install_with_ruby_version in task_helpers.rb, differing only in the bundler subcommand. It also introduces a silent inconsistency: this version supports mise but the original in task_helpers.rb does not, so users relying on mise will find that bundle_install_in fails while bundle_update_shakapacker_in succeeds.

Consider extracting a shared helper into task_helpers.rb that accepts the command:

def run_bundler_with_ruby_version(dir, version, bundler_cmd)
  version_manager = ENV.fetch("RUBY_VERSION_MANAGER", "rvm")
  cmd = case version_manager
        when "rvm"   then "rvm #{version} do #{bundler_cmd}"
        when "rbenv" then "RBENV_VERSION=#{version} #{bundler_cmd}"
        when "asdf"  then "asdf shell ruby #{version} && #{bundler_cmd}"
        when "mise"  then "mise exec ruby@#{version} -- #{bundler_cmd}"
        else raise "Unsupported RUBY_VERSION_MANAGER: #{version_manager}"
        end
  unbundled_sh_in_dir(dir, cmd)
end

Then both callers become one-liners, and mise support is available everywhere.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@AGENTS.md`:
- Around line 65-67: The documentation overstates the rake task's scope; update
the phrasing around the shakapacker:update_version rake task (referenced in
react_on_rails/rakelib/shakapacker_version.rake and the task name
shakapacker:update_version) to reflect that it updates "all relevant shakapacker
references and associated lockfiles" rather than every Gemfile.lock — note that
it skips gen-examples and only modifies lockfiles that already contain
shakapacker; adjust the AGENTS.md text to use that narrower wording and keep the
rest of the usage/flags guidance unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f1ee2d3f-29ac-4eeb-a765-5189a494bf3c

📥 Commits

Reviewing files that changed from the base of the PR and between dadc652 and d1b10eb.

📒 Files selected for processing (1)
  • AGENTS.md

Comment thread AGENTS.md
Comment on lines +65 to +67
Use `rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo. This single command updates all Gemfiles, package.json files, Gemfile.lock files, and pnpm-lock.yaml. Do **not** manually edit individual version references — always use the rake task to keep everything in sync.

The task handles Ruby version switching for apps that require a different Ruby version (set `RUBY_VERSION_MANAGER` to `rvm`, `rbenv`, `asdf`, or `mise` if needed; defaults to `rvm`). It continues gracefully if a single lock file update fails (e.g., due to a missing Ruby version).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Narrow the documented scope of lockfile updates.

react_on_rails/rakelib/shakapacker_version.rake:71-92 does not update all Gemfile.lock files: it skips gen-examples and only touches lockfiles that already contain shakapacker. Reword this to "all relevant shakapacker references and associated lockfiles" so the docs match the task behavior.

✏️ Suggested wording
-Use `rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo. This single command updates all Gemfiles, package.json files, Gemfile.lock files, and pnpm-lock.yaml. Do **not** manually edit individual version references — always use the rake task to keep everything in sync.
+Use `rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo. This single command updates shakapacker version references in Gemfiles and package.json files, refreshes the relevant Gemfile.lock files, and regenerates `pnpm-lock.yaml`. Do **not** manually edit individual version references — always use the rake task to keep everything in sync.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Use `rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo. This single command updates all Gemfiles, package.json files, Gemfile.lock files, and pnpm-lock.yaml. Do **not** manually edit individual version references — always use the rake task to keep everything in sync.
The task handles Ruby version switching for apps that require a different Ruby version (set `RUBY_VERSION_MANAGER` to `rvm`, `rbenv`, `asdf`, or `mise` if needed; defaults to `rvm`). It continues gracefully if a single lock file update fails (e.g., due to a missing Ruby version).
Use `rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo. This single command updates shakapacker version references in Gemfiles and package.json files, refreshes the relevant Gemfile.lock files, and regenerates `pnpm-lock.yaml`. Do **not** manually edit individual version references — always use the rake task to keep everything in sync.
The task handles Ruby version switching for apps that require a different Ruby version (set `RUBY_VERSION_MANAGER` to `rvm`, `rbenv`, `asdf`, or `mise` if needed; defaults to `rvm`). It continues gracefully if a single lock file update fails (e.g., due to a missing Ruby version).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 65 - 67, The documentation overstates the rake task's
scope; update the phrasing around the shakapacker:update_version rake task
(referenced in react_on_rails/rakelib/shakapacker_version.rake and the task name
shakapacker:update_version) to reflect that it updates "all relevant shakapacker
references and associated lockfiles" rather than every Gemfile.lock — note that
it skips gen-examples and only modifies lockfiles that already contain
shakapacker; adjust the AGENTS.md text to use that narrower wording and keep the
rest of the usage/flags guidance unchanged.

Add `rake shakapacker:update_version[VERSION]` which updates all
shakapacker references in Gemfiles, package.json files, and lock files
across the monorepo in one command.

The task:
- Validates version format (semver)
- Updates Gemfiles preserving "= " pin prefixes
- Updates package.json preserving ^ and ~ prefixes
- Runs bundle update shakapacker for all Gemfile.lock files
- Handles Ruby version switching for apps requiring different Ruby
- Runs pnpm install to update pnpm-lock.yaml
- Continues gracefully if a single lock file update fails

Also bumps shakapacker from 9.6.0 to 9.6.1 using the new command.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add the new command to the Commands section and a short subsection
explaining its usage, so agents and contributors know to use the
rake task rather than manually editing version references.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@justin808 justin808 force-pushed the jg/shakapacker-version-cmd branch from d1b10eb to 7472910 Compare March 9, 2026 01:46
# gem "shakapacker", "9.6.0"
# gem "shakapacker", "= 9.6.0"
updated = content.gsub(
/gem "shakapacker",\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This regex only matches double-quoted gem declarations. Gemfiles using single quotes (gem 'shakapacker', '9.6.0') will be silently skipped. Consider broadening the pattern to match either quote style:

Suggested change
/gem "shakapacker",\s*"(=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)"/
/gem ["']shakapacker["'],\s*["'](=\s*)?[\d.]+(?:[a-zA-Z0-9.\-]*)["']/

Or, simpler to capture and replace correctly, use a capture group approach that handles both quote styles.

Comment on lines +105 to +114
def bundle_update_with_ruby_version(dir, version)
version_manager = ENV.fetch("RUBY_VERSION_MANAGER", "rvm")
cmd = case version_manager
when "rvm" then "rvm #{version} do bundle update shakapacker"
when "rbenv" then "RBENV_VERSION=#{version} bundle update shakapacker"
when "asdf" then "asdf shell ruby #{version} && bundle update shakapacker"
when "mise" then "mise exec ruby@#{version} -- bundle update shakapacker"
else raise "Unsupported RUBY_VERSION_MANAGER: #{version_manager}"
end
unbundled_sh_in_dir(dir, cmd)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This method duplicates bundle_install_with_ruby_version from task_helpers.rb with one meaningful difference: it adds mise support that task_helpers.rb lacks. This divergence means mise users get inconsistent behavior — it works here but not with bundle_install_in.

Consider refactoring task_helpers.rb to accept the bundle subcommand as a parameter and reuse it here, e.g.:

def bundle_run_with_ruby_version(dir, version, subcommand)
  version_manager = ENV.fetch("RUBY_VERSION_MANAGER", "rvm")
  cmd = case version_manager
        when "rvm"   then "rvm #{version} do bundle #{subcommand}"
        when "rbenv" then "RBENV_VERSION=#{version} bundle #{subcommand}"
        when "asdf"  then "asdf shell ruby #{version} && bundle #{subcommand}"
        when "mise"  then "mise exec ruby@#{version} -- bundle #{subcommand}"
        else raise "Unsupported RUBY_VERSION_MANAGER: #{version_manager}"
        end
  unbundled_sh_in_dir(dir, cmd)
end

This way both bundle install and bundle update shakapacker use the same logic, including mise.

end

def shakapacker_relative_path(path)
Pathname.new(path).relative_path_from(Pathname.new(monorepo_root)).to_s
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pathname is used here without an explicit require 'pathname'. This works in most Rails/Rake contexts because it's loaded transitively, but it's fragile. Add require 'pathname' at the top of the file alongside require_relative "task_helpers".

Comment thread AGENTS.md
# CI/workflow linting
actionlint # GitHub Actions lint
yamllint .github/ # YAML lint (do NOT run RuboCop on .yml files)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hardcoding 9.6.1 here will make this example stale after the next version bump. Prefer a placeholder:

Suggested change
rake shakapacker:update_version[VERSION] # Update shakapacker across the monorepo

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 9, 2026

Overall this is a well-structured automation PR. The rake task is a clean improvement over manually editing 13+ files, and the version bump itself looks correct. See inline comments for specific issues.

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

♻️ Duplicate comments (2)
react_on_rails/rakelib/shakapacker_version.rake (2)

13-14: ⚠️ Potential issue | 🟡 Minor

Tighten the version validator before rewriting manifests.

Line 13 still accepts malformed inputs like 9.6.1- and 9.6.1...., so a typo can rewrite multiple files before Bundler or pnpm fails later.

🔧 Suggested fix
-    unless version.match?(/\A\d+\.\d+\.\d+([.\-a-zA-Z0-9]*)?\z/)
+    unless version.match?(/\A\d+\.\d+\.\d+(?:[-.][0-9A-Za-z]+)*\z/)
       raise "Invalid version format '#{version}'. Expected semver like '9.6.1' or '9.6.0.beta.0'"
     end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/rakelib/shakapacker_version.rake` around lines 13 - 14, The
current version validation using version.match? allows trailing or repeated
separators (e.g. "9.6.1-" or "9.6.1...."); update the regex used by
version.match? in the rake task to a stricter pattern that only permits the core
semver (MAJOR.MINOR.PATCH) optionally followed by prerelease/build identifiers
where each identifier is an alphanumeric group separated by a single dot or
hyphen (no trailing separators and no empty groups), so replace the existing
version.match? check with a regex that enforces "digits.digits.digits" and, if
present, only ".|-" followed by one or more alphanumerics (repeated as needed);
keep the same raise "Invalid version format '#{version}'..." behavior when the
new validation fails.

74-82: ⚠️ Potential issue | 🟠 Major

Non-default Gemfiles still won’t get the right lockfile refresh.

Line 74 only enumerates Gemfile.lock, and Line 101/Line 108-111 run bundle update shakapacker without binding Bundler to the originating Gemfile. That leaves manifests like Gemfile.development_dependencies at risk of being updated while their corresponding lockfiles stay stale.

🔧 Suggested direction
-    gemfile_locks = Dir.glob(File.join(monorepo_root, "**", "Gemfile.lock"))
-                       .reject { |f| f.include?("gen-examples") }
-                       .select { |f| File.read(f).include?("shakapacker") }
-
-    gemfile_locks.each do |lockfile|
-      dir = File.dirname(lockfile)
+    gemfiles = Dir.glob(File.join(monorepo_root, "**", "Gemfile*"))
+                  .reject { |f| f.end_with?(".lock") }
+                  .reject { |f| f.include?("gen-examples") }
+                  .select { |f| File.read(f).include?('gem "shakapacker"') }
+
+    gemfiles.each do |gemfile|
+      dir = File.dirname(gemfile)
+      gemfile_basename = File.basename(gemfile)
       rel = shakapacker_relative_path(dir)
       puts "  bundle update shakapacker in #{rel}"
-      bundle_update_shakapacker_in(dir)
+      bundle_update_shakapacker_in(dir, gemfile_basename)
     rescue StandardError => e
       puts "    WARNING: Failed to update #{rel}: #{e.message}"
       puts "    You may need to update this lock file manually."
     end
-  def bundle_update_shakapacker_in(dir)
+  def bundle_update_shakapacker_in(dir, gemfile_basename)
     required_version = detect_bundler_ruby_version(dir)
 
     if required_version && required_version != RUBY_VERSION
       puts "    Switching Ruby: #{RUBY_VERSION} -> #{required_version}"
-      bundle_update_with_ruby_version(dir, required_version)
+      bundle_update_with_ruby_version(dir, required_version, gemfile_basename)
     else
-      unbundled_sh_in_dir(dir, "bundle update shakapacker")
+      unbundled_sh_in_dir(dir, "BUNDLE_GEMFILE=#{gemfile_basename} bundle update shakapacker")
     end
   end
#!/bin/bash
# Verify whether the repo has non-default Gemfiles containing shakapacker
# and whether they have their own lockfiles that the current Gemfile.lock glob misses.
fd -HI -t f '^Gemfile(\..+)?$' | while read -r gemfile; do
  case "$gemfile" in
    *.lock|*gen-examples*) continue ;;
  esac

  if rg -n 'gem "shakapacker"' "$gemfile" >/dev/null; then
    lockfile="${gemfile}.lock"
    if [ -f "$lockfile" ]; then
      printf '%s -> %s\n' "$gemfile" "$lockfile"
    else
      printf '%s -> <no sibling lockfile>\n' "$gemfile"
    fi
  fi
done

Also applies to: 94-115

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@AGENTS.md`:
- Around line 59-65: Update the documented rake invocation to run under Bundler:
replace occurrences of "rake shakapacker:update_version[...]" (including the
example "rake shakapacker:update_version[9.6.1]") with "bundle exec rake
shakapacker:update_version[VERSION]" (or "bundle exec rake
shakapacker:update_version[9.6.1]" for the example) so the task is always run
via Bundler.

---

Duplicate comments:
In `@react_on_rails/rakelib/shakapacker_version.rake`:
- Around line 13-14: The current version validation using version.match? allows
trailing or repeated separators (e.g. "9.6.1-" or "9.6.1...."); update the regex
used by version.match? in the rake task to a stricter pattern that only permits
the core semver (MAJOR.MINOR.PATCH) optionally followed by prerelease/build
identifiers where each identifier is an alphanumeric group separated by a single
dot or hyphen (no trailing separators and no empty groups), so replace the
existing version.match? check with a regex that enforces "digits.digits.digits"
and, if present, only ".|-" followed by one or more alphanumerics (repeated as
needed); keep the same raise "Invalid version format '#{version}'..." behavior
when the new validation fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b1e431ed-dc75-45b0-9b29-00bbc14015f8

📥 Commits

Reviewing files that changed from the base of the PR and between d1b10eb and 7472910.

⛔ Files ignored due to path filters (6)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • react_on_rails/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails/spec/dummy/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/spec/dummy/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • AGENTS.md
  • react_on_rails/Gemfile.development_dependencies
  • react_on_rails/rakelib/shakapacker_version.rake
  • react_on_rails/spec/dummy/package.json
  • react_on_rails_pro/Gemfile.development_dependencies
  • react_on_rails_pro/spec/dummy/package.json
  • react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile
  • react_on_rails_pro/spec/execjs-compatible-dummy/package.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile
  • react_on_rails_pro/Gemfile.development_dependencies
  • react_on_rails_pro/spec/execjs-compatible-dummy/package.json
  • react_on_rails/spec/dummy/package.json

Comment thread AGENTS.md
Comment on lines +59 to +65
# Dependency version updates
rake shakapacker:update_version[9.6.1] # Update shakapacker across the monorepo
```

### Updating Shakapacker

Use `rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo. This single command updates all Gemfiles, package.json files, Gemfile.lock files, and pnpm-lock.yaml. Do **not** manually edit individual version references — always use the rake task to keep everything in sync.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Document this task with bundle exec rake.

Line 60 and Line 65 currently show a plain rake invocation even though this repo’s policy is to run Ruby commands through Bundler. Please document the new task as bundle exec rake shakapacker:update_version[...] so agents don’t run it against the wrong gem set.

✏️ Suggested wording
-# Dependency version updates
-rake shakapacker:update_version[9.6.1]  # Update shakapacker across the monorepo
+# Dependency version updates
+bundle exec rake shakapacker:update_version[9.6.1]  # Update shakapacker across the monorepo
-Use `rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo.
+Use `bundle exec rake shakapacker:update_version[VERSION]` to update shakapacker across the entire monorepo.

Based on learnings: Use bundle exec for Ruby commands.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 59 - 65, Update the documented rake invocation to run
under Bundler: replace occurrences of "rake shakapacker:update_version[...]"
(including the example "rake shakapacker:update_version[9.6.1]") with "bundle
exec rake shakapacker:update_version[VERSION]" (or "bundle exec rake
shakapacker:update_version[9.6.1]" for the example) so the task is always run
via Bundler.

@justin808 justin808 merged commit 7e73c00 into master Mar 9, 2026
51 checks passed
@justin808 justin808 deleted the jg/shakapacker-version-cmd branch March 9, 2026 04:38
justin808 added a commit that referenced this pull request Mar 9, 2026
## Summary

- Add changelog entries for 6 user-visible PRs merged since v16.4.0.rc.6
that were missing from `[Unreleased]`
- Update existing #2561 entry to include #2568 contributor credit

### New entries added

| Section | PR | Description |
|---|---|---|
| Added | #2539 | Environment-variable-driven ports in Procfile
templates |
| Fixed | #2417 | Rspack generator config path fix |
| Fixed | #2419 | Precompile hook load-based execution fix |
| Fixed | #2577 | `create-react-on-rails-app` validation improvements |
| Pro Fixed | #2416 | StreamResponse status fallback fix |
| Pro Fixed | #2566 | Empty-string license plan mismatch fix |

### Skipped PRs (not user-visible)

Docs (#2406, #2414, #2479, #2494, #2518, #2537, #2544), CI/internal
(#2533, #2547, #2555, #2557, #2558, #2564), dependabot (#2387, #2541),
dev dependencies (#2559, #2569, #2573).

## Test plan

- [ ] Verify changelog formatting matches existing entries
- [ ] Verify all user-visible PRs since v16.4.0.rc.6 are covered

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only changelog updates with no runtime or build behavior
changes.
> 
> **Overview**
> Updates `CHANGELOG.md`’s **[Unreleased]** section to include
previously missing user-facing entries: Procfile templates now support
env-driven ports, several generator/`bin/dev` precompile-hook and
rspack-path fixes are documented, and `create-react-on-rails-app`
validation improvements are noted.
> 
> Also adds two Pro fix entries (StreamResponse status fallback and
license plan empty-string validation) and updates the existing `bin/dev`
precompile-hook entry to credit an additional PR/contributor.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e75d2b5. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file full-ci P2 Backlog priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant