-
Notifications
You must be signed in to change notification settings - Fork 0
Reorganize into monorepo structure #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Move all existing code to packages/demo_common/ - Rename gem from react_on_rails_demo_common to demo_common - Add root-level README and CONTRIBUTING documentation - Create demos/ directory for future demo applications - Add helper scripts for managing demos: - bootstrap-all.sh: Install dependencies for all demos - test-all.sh: Run tests across all demos - new-demo.sh: Create new demo application - apply-shared.sh: Apply shared configs to demos - Update CI workflow for monorepo structure - Prepare for hosting multiple React on Rails demo applications This sets up the foundation for a monorepo containing multiple demo applications that share common configuration and utilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughConverts the repo into a monorepo for multiple React on Rails demos with shared tooling. Adds CI, bash and Ruby utilities for creating, scaffolding, testing, and updating demos; introduces a shared package (Ruby gem + npm), extensive documentation, test suites, and standardized lint/test configurations. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant U as User
participant CLI as bin/new-demo
participant Lib as DemoScripts::DemoCreator
participant PF as PreFlightChecks
participant CR as CommandRunner
participant FS as Filesystem
U->>CLI: new-demo DEMO_NAME [options]
CLI->>Lib: create!(options)
Lib->>PF: run!
PF-->>Lib: ok
Lib->>CR: rails new (with skips)
CR-->>Lib: status
Lib->>CR: bin/rails db:prepare
Lib->>CR: bundle add shakapacker/react_on_rails (versions)
Lib->>FS: Append shared gem, symlink configs
Lib->>CR: rails webpacker/shakapacker install
Lib->>CR: rails react_on_rails:install [args]
Lib->>FS: Generate README
Lib-->>CLI: done
CLI-->>U: Success message
sequenceDiagram
autonumber
participant U as User
participant CLI as bin/update-all-demos
participant Up as DemoScripts::DemoUpdater
participant CR as CommandRunner
participant D as demos/*
U->>CLI: update-all-demos --ror --shakapacker [flags]
CLI->>Up: update!
Up->>Up: validate versions
loop for each demo
Up->>D: locate Gemfile
alt has Gemfile
Up->>CR: bundle add react_on_rails --version X
Up->>CR: bundle add shakapacker --version Y
Up->>CR: bundle install
Up->>D: Update README Gem Versions (unless dry-run)
alt run tests
Up->>CR: rspec
CR-->>Up: pass/fail
end
Up-->>Up: record result
else
Up-->>Up: skip
end
end
Up-->>CLI: summary
sequenceDiagram
autonumber
participant GH as GitHub Actions
participant CI as ci.yml
participant Repo as Git diff
participant Matrix as Demos Matrix
participant Job as Test Job
GH->>CI: PR opened/updated
CI->>Repo: git diff origin/main
Repo-->>CI: changed paths
CI->>Matrix: build list of changed demos (<=5)
alt demos found
loop each demo
CI->>Job: setup Ruby/Node, install deps
Job->>Job: run rspec/rails tests
end
else
CI-->>GH: skip demo tests
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120+ minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Change all references from v15 to v16 throughout documentation - Update new-demo.sh with modern Rails options: - Add --skip-javascript, --skip-hotwire, --skip-turbolinks - Add --skip-action-text - Use bundle add with --strict flag - Create database as part of setup - Add scaffold-demo.sh script with advanced options: - TypeScript support option - CSS framework options (Tailwind, Bootstrap, Material-UI) - Colored output for better UX - Complete project setup with example controller/view - Comprehensive README generation - Update documentation to mention new scaffolding capabilities 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🧹 Nitpick comments (25)
demos/.gitkeep (1)
1-1: OK to keep; consider Rails-style.keep.The placeholder is fine. If you prefer Rails conventions in
demos/*, consider.keepto match the patterns you already whitelist elsewhere.packages/demo_common/.gitignore (1)
3-3: Tighten patterns and add a few common Ruby/dev artifacts.
- Use trailing slashes for directories (
.bundle/,pkg/) to avoid accidental file matches.- Consider ignoring RuboCop cache, RSpec status, and byebug history.
Apply:
-.bundle +.bundle/ @@ -pkg +pkg/ @@ coverage +.rubocop-https---cache +.rspec_status +.byebug_historyAlso applies to: 12-12, 9-9, 27-28
packages/demo_common/demo_common.gemspec (2)
13-14: Files glob may package unnecessary dirs.
{app,config,db,lib}/**/*can include empty or app-only dirs. Prefer tracking via git or a tighter glob to avoid bloat.For example:
-spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] +spec.files = `git ls-files -z`.split("\x0")Or restrict to needed paths (e.g.,
lib/**/*, configs, license, readme).
18-22: Consider moving RuboCop deps to development or document grouping.Having
rubocop*as runtime dependencies pulls them into production installs of consumer apps. If this gem is dev-only, either:
- Move to development dependencies here, and instruct consumers to add RuboCop in their app’s development/test group, or
- Explicitly document that apps should include
gem 'demo_common', group: %i[development test].Example:
-spec.add_dependency "rubocop", "~> 1.50" -spec.add_dependency "rubocop-rails", "~> 2.19" -spec.add_dependency "rubocop-performance", "~> 1.17" +spec.add_development_dependency "rubocop", "~> 1.50" +spec.add_development_dependency "rubocop-rails", "~> 2.19" +spec.add_development_dependency "rubocop-performance", "~> 1.17"Also consider adding:
spec.metadata = { "homepage_uri" => spec.homepage, "source_code_uri" => spec.homepage, "changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md" }.gitignore (1)
44-47: Add common JS test artifacts (Playwright) and tool caches.Since Playwright and JS tooling are documented, ignore their outputs/caches.
# Testing /demos/*/coverage/ /demos/*/test/reports/ +playwright-report/ +test-results/ +.nyc_output/ +.eslintcachescripts/apply-shared.sh (4)
4-11: Make script location-agnostic (determine repo root).Currently assumes execution from repo root. Add repo-root discovery to avoid surprises when invoked from other dirs.
set -euo pipefail + +# Ensure we run from the repo root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +cd "${REPO_ROOT}"
14-16: Robust demo iteration (spaces, hidden dirs).Globbing can break on spaces and will include non-dirs. Prefer find with NUL delim.
-if [ -d "demos" ] && [ "$(ls -A demos 2>/dev/null)" ]; then - for demo in demos/*; do - if [ -d "$demo" ]; then +if [ -d "demos" ] && [ "$(ls -A demos 2>/dev/null)" ]; then + while IFS= read -r -d '' demo; do + if [ -d "$demo" ]; then demo_name=$(basename "$demo") echo "📦 Updating $demo_name..." @@ - fi - done + fi + done < <(find demos -mindepth 1 -maxdepth 1 -type d -print0)
39-44: Ensure bin directory exists before linking.Avoid failures if a demo lacks bin/. Harmless for Rails, but safer generally.
- if [ -f "$demo/bin/dev" ]; then + mkdir -p "$demo/bin" + if [ -f "$demo/bin/dev" ] || [ -L "$demo/bin/dev" ]; then rm "$demo/bin/dev" fi
47-54: Tighten Gemfile detection to avoid commented matches and duplicates.Current grep may match comments. Use a stricter regex and append only once.
- if ! grep -q "demo_common" "$demo/Gemfile"; then + if ! grep -Eq '^\s*gem\s+["'\'']demo_common["'\'']\b' "$demo/Gemfile"; then echo " Adding demo_common to Gemfile..." echo '' >> "$demo/Gemfile" echo '# Shared demo configuration and utilities' >> "$demo/Gemfile" echo 'gem "demo_common", path: "../../packages/demo_common"' >> "$demo/Gemfile" fiscripts/new-demo.sh (3)
4-11: Pre-flight checks for required tools.Fail fast with clear messages if rails/bundle/node package manager is missing.
set -euo pipefail + +# Pre-flight +for cmd in rails bundle; do + command -v "$cmd" >/dev/null 2>&1 || { echo "Error: $cmd not found"; exit 1; } +done +PKG_MGR="npm" +if command -v pnpm >/dev/null 2>&1; then PKG_MGR="pnpm"; fi +command -v "$PKG_MGR" >/dev/null 2>&1 || { echo "Error: $PKG_MGR not found"; exit 1; }
59-67: Align shared config links (.prettierrc) and harden bin/dev linking.Keep parity with apply-shared.sh and ensure idempotence.
echo "🔗 Creating configuration symlinks..." ln -sf ../../packages/demo_common/config/.rubocop.yml .rubocop.yml ln -sf ../../packages/demo_common/config/.eslintrc.js .eslintrc.js +if [ -f "../../packages/demo_common/config/.prettierrc" ]; then + ln -sf ../../packages/demo_common/config/.prettierrc .prettierrc +fi if [ -f "../../packages/demo_common/bin/dev" ]; then - rm -f bin/dev + mkdir -p bin + rm -f bin/dev ln -sf ../../../packages/demo_common/bin/dev bin/dev chmod +x bin/dev fi
116-121: Update “Next steps” to reflect JS install (if not installing automatically).If you choose not to auto-install, at least instruct users to run the package manager before bin/dev.
-echo " cd $DEMO_DIR" -echo " bin/dev" +echo " cd $DEMO_DIR" +echo " pnpm install # or npm install" +echo " bin/dev"CONTRIBUTING.md (2)
90-99: Add language to fenced code block (markdownlint MD040).The Conventional Commits example lacks a language tag. Use “text” for neutral formatting.
-``` +```text feat: add TypeScript support to v16 demo @@ Fixes #123--- `129-137`: **Cross-link shared config automation.** Mention scripts/apply-shared.sh so contributors know how to propagate updates. ```diff When modifying shared configuration in `packages/demo_common/`: @@ 3. Consider backward compatibility 4. Update the gem/npm package versions appropriately +5. Run `./scripts/apply-shared.sh` to re-link configs across demosscripts/bootstrap-all.sh (3)
4-7: Make script resilient to invocation path (repo root).Mirror the root detection used in other scripts for consistency.
set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +cd "${REPO_ROOT}"
29-31: Use NUL-delimited find for robust demo iteration.Avoid breakage with spaces/unusual names.
-if [ -d "demos" ] && [ "$(ls -A demos 2>/dev/null)" ]; then - for demo in demos/*; do - if [ -d "$demo" ]; then +if [ -d "demos" ] && [ "$(ls -A demos 2>/dev/null)" ]; then + while IFS= read -r -d '' demo; do + if [ -d "$demo" ]; then @@ - fi - done + fi + done < <(find demos -mindepth 1 -maxdepth 1 -type d -print0)
45-52: Prefer pnpm when available (consistency with demo_common block).Minor nit: matches the earlier branch.
- if [ -f "package.json" ]; then + if [ -f "package.json" ]; then echo " Installing JavaScript dependencies..." if command -v pnpm &> /dev/null; then pnpm install else npm install fi fiscripts/test-all.sh (2)
59-61: Guard RuboCop invocation.Only run if RuboCop is available to avoid hard failures on demos that don’t include it.
- echo " Running RuboCop..." - bundle exec rubocop || FAILED_DEMOS="$FAILED_DEMOS $demo_name-rubocop" + echo " Running RuboCop..." + if bundle exec rubocop -v >/dev/null 2>&1; then + bundle exec rubocop || FAILED_DEMOS="$FAILED_DEMOS $demo_name-rubocop" + fi
63-68: Decide whether JS tests should gate CI and prefer pnpm when available.Right now JS tests/lint are best-effort and don’t affect FAILED_DEMOS, and npm is hardcoded. If these should gate, capture failures and prefer pnpm like other scripts.
- echo " Running JavaScript tests..." - npm test 2>/dev/null || true - npm run lint 2>/dev/null || true + echo " Running JavaScript tests..." + if command -v pnpm &> /dev/null; then PKG=pnpm; else PKG=npm; fi + $PKG test 2>/dev/null || FAILED_DEMOS="$FAILED_DEMOS $demo_name-js" + $PKG run lint 2>/dev/null || FAILED_DEMOS="$FAILED_DEMOS $demo_name-lint"Apply the same change in the packages/demo_common section.
- npm test 2>/dev/null || true - npm run lint 2>/dev/null || true + if command -v pnpm &> /dev/null; then PKG=pnpm; else PKG=npm; fi + $PKG test 2>/dev/null || FAILED_DEMOS="$FAILED_DEMOS demo_common-js" + $PKG run lint 2>/dev/null || FAILED_DEMOS="$FAILED_DEMOS demo_common-lint"Also applies to: 29-34
.github/workflows/ci.yml (1)
32-48: Optional: enable Bundler caching in subdir jobs for speed.Use
ruby/setup-rubywithbundler-cache: trueandworking-directory: packages/demo_common(already present) and consider caching npm via lockfile. For demo loops, consider anactions/cacheonvendor/bundlekeyed by each demo’sGemfile.lockto reduce CI time.Also applies to: 50-70
README.md (2)
7-19: Specify language on fenced code block for the tree.Adds syntax hint and satisfies MD040.
Apply this diff:
-``` +```text react_on_rails-demos/ ├─ packages/ │ └─ demo_common/ # Shared configuration and utilities │ ├─ Gemfile # Shared Ruby dependencies │ ├─ package.json # Shared JavaScript dependencies │ ├─ config/ # Shared linting configs │ └─ lib/ # Ruby utilities and templates └─ demos/ ├─ react_on_rails-demo-v16-ssr-auto-registration-bundle-splitting/ ├─ react_on_rails-demo-v16-react-server-components/ └─ ... # Additional demo applications--- `27-27`: **Replace emphasized placeholder with plain text or a list item.** Avoid MD036 by not using emphasis as a heading. Apply this diff: ```diff -*(Demos will be listed here as they are added)* +- None yet. Use `./scripts/new-demo.sh` to add one.scripts/scaffold-demo.sh (3)
98-101: Database creation may fail on machines without Postgres configured.Consider guarding or making it non-fatal with clear guidance.
Apply this diff:
-if [ "$SKIP_DB" = false ]; then +if [ "$SKIP_DB" = false ]; then echo -e "${YELLOW}📦 Setting up database...${NC}" - bin/rails db:create + if ! bin/rails db:create; then + echo -e "${YELLOW}Skipping DB creation (configure PostgreSQL or pass --skip-db).${NC}" + fi fi
173-201: Wire Tailwind/Bootstrap CSS into a pack entry.After adding Tailwind or Bootstrap, import the CSS so it actually loads.
Apply this diff:
npm install --save-dev tailwindcss postcss autoprefixer npx tailwindcss init -p @@ mkdir -p app/javascript/styles cat > app/javascript/styles/application.css << 'EOF' @tailwind base; @tailwind components; @tailwind utilities; EOF fi @@ if [ "$SKIP_INSTALL" = false ]; then echo -e "${YELLOW}📦 Installing npm dependencies...${NC}" npm install fi + +# Ensure CSS is imported by a pack entry +if [ -f app/javascript/packs/application.js ]; then + grep -q "styles/application.css" app/javascript/packs/application.js || \ + echo "import '../styles/application.css';" >> app/javascript/packs/application.js +fi +if [ -f app/javascript/packs/application.ts ]; then + grep -q "styles/application.css" app/javascript/packs/application.ts || \ + echo "import '../styles/application.css';" >> app/javascript/packs/application.ts +fiFor Bootstrap, also import CSS (e.g.,
import 'bootstrap/dist/css/bootstrap.min.css';) in the same pack whenUSE_BOOTSTRAP=true. Want me to add that conditional block?Also applies to: 215-219
12-26: Optional: preflight checks for required tools.Fail fast with helpful messages if
rails,bundle,node,npm(and optionallypsql) aren’t available. I can add a small helper to check commands.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
packages/demo_common/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (13)
.github/workflows/ci.yml(1 hunks).gitignore(1 hunks)CONTRIBUTING.md(1 hunks)README.md(1 hunks)demos/.gitkeep(1 hunks)packages/demo_common/.gitignore(1 hunks)packages/demo_common/README.md(1 hunks)packages/demo_common/demo_common.gemspec(1 hunks)scripts/apply-shared.sh(1 hunks)scripts/bootstrap-all.sh(1 hunks)scripts/new-demo.sh(1 hunks)scripts/scaffold-demo.sh(1 hunks)scripts/test-all.sh(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
CONTRIBUTING.md
7-7: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
27-27: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
README.md
7-7: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
27-27: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🪛 actionlint (1.7.7)
.github/workflows/ci.yml
78-78: "matrix values" section should not be empty
(syntax-check)
84-84: shellcheck reported issue in this script: SC2086:info:4:30: Double quote to prevent globbing and word splitting
(shellcheck)
🔇 Additional comments (4)
.gitignore (1)
29-31: Confirm intent to ignore.ruby-versionat repo root.Ignoring
.ruby-versionis fine if you manage versions via asdf/Toolfiles, but teams often commit it for onboarding consistency. Confirm this choice.packages/demo_common/README.md (1)
30-35: Remove generator rename suggestion
The install generator lives in ReactOnRailsDemoCommon::Generators and is invoked viarails generate react_on_rails_demo_common:install, so the README is already correct.Likely an incorrect or invalid review comment.
README.md (1)
33-37: Align tool recommendation with scripts/CI.README recommends pnpm, but scripts/CI use npm. Either:
- Note that scripts default to npm, or
- Add pnpm support switches in scripts.
Would you like a small patch to detect and prefer pnpm when available?scripts/scaffold-demo.sh (1)
81-94: Confirm Rails flags; drop obsolete--skip-turbolinks.Rails 7+ no longer uses Turbolinks; the flag is obsolete and may be ignored.
Prefer:
rails new "$DEMO_DIR" --database=postgresql --skip-javascript --skip-hotwire \ --skip-action-mailbox --skip-action-text --skip-active-storage \ --skip-action-cable --skip-sprockets --skip-system-testWant me to update the script after confirming your target Rails version?
| strategy: | ||
| matrix: | ||
| demo: [] # Will be populated as demos are added | ||
| fail-fast: false | ||
| steps: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove empty matrix; run loop without strategy.
Empty matrix triggers actionlint and adds no value since you already loop over demos.
Apply this diff:
- strategy:
- matrix:
- demo: [] # Will be populated as demos are added
- fail-fast: false🧰 Tools
🪛 actionlint (1.7.7)
78-78: "matrix values" section should not be empty
(syntax-check)
🤖 Prompt for AI Agents
.github/workflows/ci.yml around lines 76 to 80 contains an empty strategy.matrix
block which is unnecessary and triggers actionlint; remove the entire strategy
block (both matrix: and fail-fast: entries) so the job runs without a strategy,
leaving the steps section directly under the job definition and ensuring
indentation remains correct.
|
|
||
| Gem::Specification.new do |spec| | ||
| spec.name = "react_on_rails_demo_common" | ||
| spec.name = "demo_common" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Rename looks correct; verify library namespace and require path.
Ensure lib/demo_common.rb and lib/demo_common/version.rb define module DemoCommon so require 'demo_common' works with the new name.
Run:
Also applies to: 10-10
🏁 Script executed:
#!/bin/bash
fd -a --hidden -t f -E .git 'demo_common.rb|version.rb' | xargs -I{} sh -c 'echo "== {} =="; sed -n "1,120p" "{}"'
rg -nP '^\s*module\s+DemoCommon\b' -C2Length of output: 694
Update module namespace and file paths to match demo_common gem
Rename lib/react_on_rails_demo_common.rb → lib/demo_common.rb and lib/react_on_rails_demo_common/version.rb → lib/demo_common/version.rb, and change both module ReactOnRailsDemoCommon declarations to module DemoCommon.
🤖 Prompt for AI Agents
In packages/demo_common/demo_common.gemspec around line 4, the gem name is set
to "demo_common" but the library files and module namespace still reference the
old react_on_rails_demo_common naming; rename the files
lib/react_on_rails_demo_common.rb → lib/demo_common.rb and
lib/react_on_rails_demo_common/version.rb → lib/demo_common/version.rb, and
update both module declarations from module ReactOnRailsDemoCommon to module
DemoCommon within those files so the gemspec, file paths, and module namespace
are consistent.
| ```json | ||
| "devDependencies": { | ||
| "@shakacode/react-on-rails-demo-common": "github:shakacode/react_on_rails_demo_common" | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify or update the NPM package name and source.
The README references @shakacode/react-on-rails-demo-common. If the JS package is not (yet) published or is renamed for the monorepo, update this section accordingly or mark as TBD.
Run to check for an actual package manifest:
🏁 Script executed:
#!/bin/bash
fd -a package.json packages/demo_common | xargs -I{} sh -c 'echo "== {} =="; jq -r ".name, .version" "{}" 2>/dev/null || true'
rg -n "@shakacode/react-on-rails-demo-common|@shakacode/demo-common|react-on-rails-demo-common" -C2Length of output: 5562
Dev package name is correct; fix GitHub install path
The package @shakacode/[email protected] exists in package.json. Update the README devDependencies snippet to use the hyphenated GitHub repo shorthand:
"@shakacode/react-on-rails-demo-common": "github:shakacode/react-on-rails-demo-common"
(packages/demo_common/README.md:26)
🤖 Prompt for AI Agents
In packages/demo_common/README.md around lines 24 to 28, the devDependencies
snippet uses an incorrect GitHub install path for the package; update the
snippet so the key uses the correct hyphenated package name
"@shakacode/react-on-rails-demo-common" and set its value to the hyphenated
GitHub shorthand "github:shakacode/react-on-rails-demo-common" so the README
accurately reflects the package name and repository install path.
scripts/scaffold-demo.sh
Outdated
| ln -sf ../../packages/demo_common/config/.rubocop.yml .rubocop.yml | ||
| ln -sf ../../packages/demo_common/config/.eslintrc.js .eslintrc.js | ||
| if [ -f "../../packages/demo_common/bin/dev" ]; then | ||
| rm -f bin/dev | ||
| ln -sf ../../../packages/demo_common/bin/dev bin/dev | ||
| chmod +x bin/dev | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken symlink: extra “../” in path to demo_common/bin/dev.
The symlink points outside the repo; bin/dev will be broken.
Apply this diff:
if [ -f "../../packages/demo_common/bin/dev" ]; then
rm -f bin/dev
- ln -sf ../../../packages/demo_common/bin/dev bin/dev
+ ln -sf ../../packages/demo_common/bin/dev bin/dev
chmod +x bin/dev
fi📝 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.
| ln -sf ../../packages/demo_common/config/.rubocop.yml .rubocop.yml | |
| ln -sf ../../packages/demo_common/config/.eslintrc.js .eslintrc.js | |
| if [ -f "../../packages/demo_common/bin/dev" ]; then | |
| rm -f bin/dev | |
| ln -sf ../../../packages/demo_common/bin/dev bin/dev | |
| chmod +x bin/dev | |
| fi | |
| ln -sf ../../packages/demo_common/config/.rubocop.yml .rubocop.yml | |
| ln -sf ../../packages/demo_common/config/.eslintrc.js .eslintrc.js | |
| if [ -f "../../packages/demo_common/bin/dev" ]; then | |
| rm -f bin/dev | |
| ln -sf ../../packages/demo_common/bin/dev bin/dev | |
| chmod +x bin/dev | |
| fi |
🤖 Prompt for AI Agents
In scripts/scaffold-demo.sh around lines 121 to 127 the symlink for bin/dev
points too high (uses ../../../packages/demo_common/bin/dev) which creates a
broken link outside the repo; change the symlink target to
../../packages/demo_common/bin/dev so it points to the correct path, keep the rm
-f, chmod +x and conditional logic unchanged.
Enhanced both new-demo.sh and scaffold-demo.sh scripts with: Pre-flight checks: - Verify target directory does not exist - Check for uncommitted changes (staged or unstaged) - Confirm running in a git repository - Provide clear error messages with remediation steps Dry-run mode: - Add --dry-run flag to preview commands without execution - Display all commands that would be run - Show final command to execute for real Generator improvements: - Add --ignore-warnings flag to react_on_rails:install - Skips git check when running generator from scripts - Allows clean execution in controlled environments All commands now use run_cmd() wrapper for consistent handling of dry-run vs actual execution modes. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Code Review: Reorganize into monorepo structureGreat work on reorganizing the repository into a monorepo structure! This is a solid foundation for managing multiple React on Rails demo applications. ✅ Strengths
🔍 Issues & Suggestions1. Shell Script Security (scripts/new-demo.sh:61, scripts/scaffold-demo.sh:97)The eval command is used with user input, which could be a security risk. Consider using safer alternatives or adding proper input validation. 2. CI Workflow Edge Case (.github/workflows/ci.yml:114)The test checking for spec directory should use -d flag instead of -f 3. Missing Executable PermissionsEnsure all shell scripts have executable permissions set in git: git update-index --chmod=+x scripts/*.sh 4. Error Handling in bootstrap-all.shDatabase preparation errors are silenced (line 57). Consider logging failures instead of silently continuing. 5. Package.json Path ConsistencyThe gem is renamed to demo_common but npm package references might still use the old name. Ensure consistency across all package references. 🚀 Performance Considerations
🔒 Security Considerations
🧪 Test Coverage
💡 Additional Recommendations
✨ Overall AssessmentThis is a well-executed monorepo migration that sets up a maintainable structure for multiple demos. The breaking changes are clearly documented, and migration instructions are helpful. With the minor issues addressed above, this will provide an excellent foundation for the React on Rails demo ecosystem. Recommendation: ✅ Approve with minor changes Great work on this reorganization! The structure will make it much easier to maintain and expand the demo collection. 🤖 Generated with Claude Code |
Each Rails app should use its own bin/dev script that's specific to that app's configuration. Removed symlink logic from: - scripts/new-demo.sh - scripts/scaffold-demo.sh - scripts/apply-shared.sh Only configuration files (.rubocop.yml, .eslintrc.js) should be symlinked, as these are truly shared across demos. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Added version configuration system for demo creation: New `.demo-versions` config file: - Defines default versions for Shakapacker and React on Rails - Simple bash file sourced by scripts - Easy to update for new releases Command-line overrides: - Added --shakapacker-version flag to both scripts - Added --react-on-rails-version flag to both scripts - Supports version constraints (~> 8.0) or exact versions (8.0.0) - Command-line flags override config file defaults Version display: - Scripts now show which versions are being used - Clear feedback during demo creation Updated documentation: - Added Version Configuration section to README - Examples of using version flags - Explanation of fallback behavior This allows: 1. Global defaults for most demos 2. Per-demo version customization when needed 3. Easy testing of new React on Rails/Shakapacker versions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Created complete documentation and tooling for managing gem versions across demos, including beta testing and bulk updates. New documentation (docs/VERSION_MANAGEMENT.md): - Overview of version precedence (demo Gemfile > global defaults) - Creating demos with stable, custom, or beta versions - Updating individual demos to new versions - Beta/RC version testing workflow - Bulk updates across all demos - Version tracking patterns - Troubleshooting and examples Enhanced demo templates: - Added "Gem Versions" section to README templates - Shows which versions were used at creation - Includes creation/update date - Links to version management docs New update-all-demos.sh script: - Bulk update React on Rails and/or Shakapacker across demos - Supports selective updates with pattern matching - Runs tests after updates (optional) - Dry-run mode for preview - Updates README dates and versions - Provides clear summary and next steps Updated .demo-versions config: - Added comprehensive comments explaining usage - Clarified that it only affects NEW demos - Quick reference for common workflows - Links to full documentation Workflows documented: 1. Standard demo creation with global defaults 2. Custom version override per demo 3. Beta/RC version testing in dedicated demos 4. Updating existing demos individually 5. Bulk updates when releasing new versions 6. Edge/development version testing with git branches This provides a complete system for: - Consistent versioning across demos - Flexible per-demo customization - Safe beta testing without affecting stable demos - Easy updates when releasing new versions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this 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
♻️ Duplicate comments (2)
scripts/new-demo.sh (1)
188-195: Install JS dependencies after Rails generators.The Shakapacker and React on Rails installers modify
package.json, but the script never runsnpm installto install those dependencies. Users must manually runnpm installbeforebin/devwill work, which contradicts the "Next steps" output.Apply this diff to install JS dependencies:
echo "" echo "📦 Installing React on Rails (skipping git check)..." run_cmd "cd '$DEMO_DIR' && bundle exec rails generate react_on_rails:install --ignore-warnings" +echo "" +echo "📦 Installing JavaScript dependencies..." +run_cmd "cd '$DEMO_DIR' && npm install" + echo "" echo "📝 Creating README..."Then update the "Next steps" section to reflect this:
echo "✅ Demo created successfully at $DEMO_DIR" echo "" echo "Next steps:" echo " cd $DEMO_DIR" echo " bin/dev"scripts/scaffold-demo.sh (1)
66-67: Validate demo name to prevent path traversal.The script assigns
DEMO_NAMEdirectly from$1without validation, allowing path traversal attacks like../../etc/passwd. This is a security issue.Apply this diff:
# Parse first argument as demo name DEMO_NAME="$1" shift + +# Validate demo name: alphanumeric, hyphens, underscores only +if [[ -z "$DEMO_NAME" ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then + echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" + echo "Demo name must contain only letters, numbers, hyphens, and underscores" + exit 1 +fi
🧹 Nitpick comments (5)
scripts/update-all-demos.sh (3)
80-86: eval usage is acceptable here but consider safer alternative.The shellcheck warning about
evalnegating array benefits is valid. However, in this context where commands are constructed internally (not from user input), the security risk is minimal. The pattern is also consistent with other scripts in this PR.For future hardening, consider using arrays with proper quoting instead of eval:
run_cmd() { if [ "$DRY_RUN" = true ]; then echo -e "${YELLOW}[DRY-RUN]${NC} $*" else "$@" # Execute directly without eval fi }Then call with:
run_cmd bundle add react_on_rails --version "$REACT_ON_RAILS_VERSION" --skip-install
144-164: README update logic assumes specific format.The
sedcommands expect exact markdown formatting (## Gem Versions,- **React on Rails**:, etc.). If a demo's README has different formatting or is missing these sections, the updates will silently fail.Consider adding validation or warning messages:
if [ "$DRY_RUN" = false ]; then if [ -f README.md ] && grep -q "## Gem Versions" README.md; then echo -e " Updating README.md with new versions..." # ... existing sed commands ... else echo -e " ${YELLOW}⚠ README.md missing '## Gem Versions' section, skipping update${NC}" fi fi
167-177: Test failures halt processing but continue summary.When tests fail (line 174
exit 1), the subshell exits but the loop continues. This is correct behavior, but the error output> /dev/null 2>&1hides useful diagnostic information.Consider showing test output on failure:
if [ -d "spec" ]; then echo -e " Running tests..." - if bundle exec rspec --fail-fast > /dev/null 2>&1; then + if bundle exec rspec --fail-fast --format progress; then echo -e " ${GREEN}✓ Tests passed${NC}" else echo -e " ${RED}✗ Tests failed${NC}" exit 1 fi fiREADME.md (2)
7-19: Add language identifier to fenced code block.The directory structure code block should specify
textorplaintextas the language identifier for proper rendering and to satisfy markdownlint.Apply this diff:
-``` +```text react_on_rails-demos/ ├─ packages/ │ └─ demo_common/ # Shared configuration and utilities
25-27: Use proper heading instead of emphasized text.Line 27 uses emphasis (
*(Demos will be listed here as they are added)*) instead of a proper heading or list item. While functional, using proper markdown structure is better for accessibility and parsing.Consider using a blockquote or note format:
### Available Demos -*(Demos will be listed here as they are added)* +> Demos will be listed here as they are added.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.demo-versions(1 hunks)README.md(1 hunks)docs/VERSION_MANAGEMENT.md(1 hunks)scripts/apply-shared.sh(1 hunks)scripts/new-demo.sh(1 hunks)scripts/scaffold-demo.sh(1 hunks)scripts/update-all-demos.sh(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- .demo-versions
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/apply-shared.sh
🧰 Additional context used
🧬 Code graph analysis (3)
scripts/new-demo.sh (1)
scripts/scaffold-demo.sh (2)
show_usage(26-47)run_cmd(126-133)
scripts/update-all-demos.sh (2)
scripts/new-demo.sh (1)
run_cmd(90-97)scripts/scaffold-demo.sh (1)
run_cmd(126-133)
scripts/scaffold-demo.sh (1)
scripts/new-demo.sh (2)
show_usage(26-41)run_cmd(90-97)
🪛 markdownlint-cli2 (0.18.1)
README.md
7-7: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
27-27: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🪛 Shellcheck (0.11.0)
scripts/new-demo.sh
[warning] 95-95: eval negates the benefit of arrays. Drop eval to preserve whitespace/symbols (or eval as string).
(SC2294)
scripts/update-all-demos.sh
[warning] 84-84: eval negates the benefit of arrays. Drop eval to preserve whitespace/symbols (or eval as string).
(SC2294)
scripts/scaffold-demo.sh
[error] 371-371: Couldn't find 'fi' for this 'if'.
(SC1046)
[error] 371-371: Couldn't parse this if expression. Fix to allow more checks.
(SC1073)
[error] 374-374: '(' is invalid here. Did you forget to escape it?
(SC1036)
[error] 374-374: Expected 'fi' matching previously mentioned 'if'.
(SC1047)
[error] 374-374: Expected 'fi'. Fix any mentioned problems and try again.
(SC1072)
🔇 Additional comments (5)
docs/VERSION_MANAGEMENT.md (1)
1-510: Comprehensive version management documentation looks excellent!This documentation provides clear, detailed workflows for version management across demos. The structure is logical, examples are practical, and it addresses common scenarios (beta testing, bulk updates, edge versions).
scripts/new-demo.sh (1)
90-97: eval usage consistent with other scripts.The shellcheck warning about
evalis noted. This pattern is consistent across all scripts in this PR (update-all-demos.sh, scaffold-demo.sh). While a safer array-based approach would be ideal, the current implementation is acceptable for this context where commands are constructed internally.README.md (1)
1-113: Clear, well-structured monorepo documentation!The README provides an excellent overview of the monorepo structure, available scripts, and workflows. The examples are practical and the version configuration section clearly explains the defaults and override mechanisms.
scripts/scaffold-demo.sh (2)
125-133: Consistent eval usage across scripts.The
run_cmdfunction useseval, similar to other scripts in this PR. While shellcheck warns about this, it's an acceptable pattern for this use case where commands are constructed internally.
336-341: npm install conditional logic is clear.The script appropriately skips npm installation when
--skip-installis specified, and clearly documents this in the usage and next steps output.
Converted all demo management scripts from Bash to Ruby with a full test suite using RSpec. New Ruby Implementation: - Modular, object-oriented design - Type-safe with clear interfaces - Fully testable and tested - Better error handling - Consistent API across all scripts Core Modules (lib/demo_scripts/): - Config: Loads and manages version configuration - PreFlightChecks: Validates environment before creating demos - CommandRunner: Executes commands with dry-run support - DemoCreator: Creates basic React on Rails demos - DemoScaffolder: Creates advanced demos with options (TypeScript, Tailwind, etc.) - DemoUpdater: Bulk updates gem versions across demos Executable Scripts (bin/): - bin/new-demo: Create a new basic demo - bin/scaffold-demo: Create an advanced demo with options - bin/update-all-demos: Update versions across all demos All scripts support: - --dry-run mode for previewing changes - Custom version overrides - Clear error messages - Help documentation Test Suite (spec/): - Config loading and version precedence - Command execution with dry-run - Pre-flight checks for git state - Demo creation logic - README generation - 100% coverage of core functionality Benefits over Bash: - Testable: Full RSpec test suite - Maintainable: Clear class structure - Extensible: Easy to add new features - Reliable: Type checking and error handling - Cross-platform: Better Windows support Bash scripts retained for compatibility but Ruby versions are recommended for production use. Usage: bin/new-demo my-demo --dry-run bin/scaffold-demo my-demo --typescript --tailwind bin/update-all-demos --react-on-rails-version '~> 16.1' Testing: bundle install bundle exec rspec bundle exec rubocop 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Fixed CI workflow to properly handle PRs targeting non-main branches
and added proper shell variable quoting for shellcheck compliance.
Changes to .github/workflows/ci.yml:
1. Full history fetch:
- Added fetch-depth: 0 to checkout step
- Ensures git diff has full history for comparison
2. Dynamic base ref handling:
- Added step to fetch PR base ref explicitly
- Changed git diff from hardcoded origin/main to origin/${{ github.base_ref }}
- Now works correctly for PRs targeting any branch
3. Shell quoting fixes (SC2086):
- Quoted all variable expansions: ${var}
- Fixed: demos=${CHANGED} instead of demos=$CHANGED
- Fixed: "demos/${demo}" instead of "demos/$demo"
- Fixed: -n "${CHANGED}" instead of -n "$CHANGED"
- Fixed: ls -A demos 2>/dev/null in test condition
4. Other improvements:
- Changed -f "spec" to -d "spec" (spec is a directory)
- Better error handling with 2>/dev/null redirection
This fixes the issue where:
- Shallow clones broke git diff operations
- PRs targeting feature branches would diff against wrong base
- shellcheck warnings about unquoted expansions
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
Added Lefthook git hooks to enforce code quality standards automatically before commits. New lefthook.yml configuration: - Pre-commit trailing newline check (auto-fixes) - Pre-commit RuboCop linting (auto-fixes safe issues) - Commit message validation Hooks automatically: 1. Add trailing newlines to staged files (*.rb, *.js, *.ts, etc.) 2. Run RuboCop on staged Ruby files with auto-fix 3. Validate commit messages are not empty Added lefthook to Gemfile: - gem "lefthook", "~> 1.5" New documentation (docs/CONTRIBUTING_SETUP.md): - Complete development setup guide - How to install and use git hooks - How to skip hooks when needed - Testing and linting instructions - Troubleshooting common issues - Best practices for contributors Updated README.md: - Added Initial Setup section - Instructions for installing hooks - Link to detailed setup documentation Usage: bundle install lefthook install This ensures all committed files meet quality standards: - Files end with newlines (required by POSIX) - Ruby code passes RuboCop checks - Commit messages are meaningful Hooks can be skipped with LEFTHOOK=0 if needed, but this is discouraged except in exceptional circumstances. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Updated RuboCop and related gems to latest versions and fixed all linting violations across the codebase. RuboCop Updates: - rubocop: ~> 1.50 → ~> 1.69 (latest) - rubocop-performance: ~> 1.17 → ~> 1.23 - rubocop-rspec: ~> 2.20 → ~> 3.2 New .rubocop.yml configuration: - Enabled all new cops (NewCops: enable) - Configured plugins for rubocop-performance and rubocop-rspec - Adjusted metrics for demo creation scripts (complex setup code) - Disabled Documentation cop for internal tools - Configured RSpec cops for test files - Excluded build artifacts and vendor directories Metrics Adjustments (for demo scripts): - ClassLength: 150 → 300 (demo creators have lots of setup) - AbcSize: 17 → 25 (complex orchestration methods) - CyclomaticComplexity: 7 → 10 (conditional setup flows) - PerceivedComplexity: 8 → 12 (options handling) - ParameterLists: 5 → 12 (demo scaffolder has many options) - BlockLength: Excluded Rakefiles and specs Fixed Violations: - Converted all double quotes to single quotes - Added trailing newlines to all files - Fixed string interpolation style - Fixed indentation consistency - Removed unnecessary File.exist? checks - Added RuboCop metadata to gemspec Result: - 23 files inspected - 0 offenses detected - All code now passes latest RuboCop standards Files auto-formatted by RuboCop: - All Ruby files in lib/ - All spec files - Gemfiles and gemspecs - Rakefiles 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
| @@ -0,0 +1,510 @@ | |||
| # Version Management Workflow | |||
|
|
|||
| This document describes how to manage React on Rails and Shakapacker versions across demos, including creating demos with beta versions and updating existing demos. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| --dry-run | ||
| ``` | ||
|
|
||
| Then manually edit the demo's `Gemfile` to point to a git branch: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is really a separate type of change.
enable bin/new-demo to support using branches
|
|
||
| ## Version Precedence | ||
|
|
||
| After demo creation, version management follows this pattern: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want a top level file that demos can inherit from:
Like:
# frozen_string_literal: true
source "https://rubygems.org"
eval_gemfile File.expand_path("../../Gemfile.development_dependencies", __dir__)
gem "react_on_rails", path: "../.."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How best to have a default and allow overrides?
docs/VERSION_MANAGEMENT.md
Outdated
|
|
||
| ```bash | ||
| # Using beta version | ||
| ./scripts/scaffold-demo.sh react_on_rails-demo-v16-beta-test \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need updates to reflect new ruby program
…docs updates ## Changes Made ### Package Renaming (Breaking Change) - Renamed ReactOnRailsDemoCommon module to DemoCommon for consistency - Renamed lib files: react_on_rails_demo_common → demo_common - Updated all references throughout the codebase - Updated packages/demo_common/README.md with correct monorepo installation examples ### Security Fixes - Added input validation to new-demo.sh to prevent path traversal attacks - Added input validation to scaffold-demo.sh to prevent path traversal attacks - Fixed variable expansion syntax error in scaffold-demo.sh (line 381) - Fixed subshell issue in test-all.sh that prevented FAILED_DEMOS tracking ### Script Improvements - Added JavaScript dependency installation after Rails generators in new-demo.sh - Scripts now properly install npm/pnpm dependencies after shakapacker/react_on_rails installation - test-all.sh now uses pushd/popd instead of subshells for proper variable propagation ### Documentation Updates - Added Gemfile.development_dependencies for shared development dependencies across demos - Updated VERSION_MANAGEMENT.md to reference new Ruby programs (bin/*) instead of bash scripts - Added cypress-playwright-on-rails reference to VERSION_MANAGEMENT.md - Documented eval_gemfile pattern for demo applications - Added note about git branch support as a future enhancement ## Migration Guide for demo_common If you're using the old module name: **Before:** ```ruby require 'react_on_rails_demo_common' ReactOnRailsDemoCommon.root ``` **After:** ```ruby require 'demo_common' DemoCommon.root ``` Generator invocation also changes: ```bash # Before rails generate react_on_rails_demo_common:install # After rails generate demo_common:install ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 15
♻️ Duplicate comments (2)
.github/workflows/ci.yml (1)
76-79: Empty matrix adds no value; consider removing the strategy block entirely.The
matrix: { demo: [] }is empty and triggers actionlint warnings. The job already loops over demos using shell logic (lines 109-124), making the matrix strategy unnecessary.Apply this diff to remove the empty strategy:
- strategy: - matrix: - demo: [] # Will be populated as demos are added - fail-fast: falsescripts/scaffold-demo.sh (1)
389-395: Fix README date interpolation.CURRENT_DATEis computed but the heredoc escapes it, so the generated README shows$CURRENT_DATEliterally. Drop the backslash so the actual date is written.Apply this diff:
-Created: \$CURRENT_DATE +Created: $CURRENT_DATE
🧹 Nitpick comments (15)
Gemfile (1)
5-5: Consider a more recent Ruby minimum version.Ruby 3.0 reached end-of-life in March 2024. Consider requiring
>= 3.1or>= 3.2to ensure security support and access to newer language features.-ruby '>= 3.0' +ruby '>= 3.1'docs/CONTRIBUTING_SETUP.md (1)
47-47: Consider using proper heading levels for subsections.The bold text "Trailing Newline Check" could be converted to a proper heading (e.g.,
##### Trailing Newline Check) to improve document structure and accessibility.Apply this pattern to similar subsections:
-**Trailing Newline Check** +##### Trailing Newline CheckAlso applies to lines 52 and 59 ("RuboCop Linting" and "Message Validation").
spec/demo_scripts/command_runner_spec.rb (1)
16-21: Make the dir test shell-agnostic.
touchis POSIX-only, so this spec fails on Windows/agents without coreutils. Switch to a Ruby command so the test still exercisesdir:handling without relying on platform-specific binaries.- runner.run('touch test.txt', dir: tmpdir) + runner.run(%(#{RbConfig.ruby} -e "File.write('test.txt', '')"), dir: tmpdir)If
RbConfigisn’t already loaded in your spec helper, addrequire 'rbconfig'.spec/demo_scripts/config_spec.rb (1)
11-12: Consider using constants for expected default versions.The hardcoded version strings
'~> 8.0'and'~> 16.0'might drift from the actual defaults ifDemoScripts::Config::DEFAULT_SHAKAPACKER_VERSIONandDEFAULT_REACT_ON_RAILS_VERSIONchange. Referencing the implementation constants would make tests more maintainable.Apply this diff:
- expect(config.shakapacker_version).to eq('~> 8.0') - expect(config.react_on_rails_version).to eq('~> 16.0') + expect(config.shakapacker_version).to eq(DemoScripts::Config::DEFAULT_SHAKAPACKER_VERSION) + expect(config.react_on_rails_version).to eq(DemoScripts::Config::DEFAULT_REACT_ON_RAILS_VERSION)spec/demo_scripts/pre_flight_checks_spec.rb (1)
21-30: Stub specific git commands for success caseIn the success context, replace
allow(checks).to receive(:system).and_call_originalwith stubs for the two Git checks:
allow(checks).to receive(:system).with(/git rev-parse/).and_return(true) allow(checks).to receive(:system).with(/git diff-index/).and_return(true)This avoids relying on real repository state and mirrors the failure specs.
scripts/new-demo.sh (1)
97-104:evalnegates benefit of argument safety.The
run_cmdfunction useseval "$@", which can be unsafe if arguments contain special characters. Shellcheck correctly flags this as negating the benefits of proper argument handling.Consider this safer alternative that preserves arguments without eval:
run_cmd() { if [ "$DRY_RUN" = true ]; then echo "[DRY-RUN] $*" else echo "▶ $*" - eval "$@" + "$@" fi }Note: If you need shell metacharacter expansion (pipes, redirects, etc.), the current
evalapproach is necessary, but be aware it requires careful input sanitization.lib/demo_scripts/config.rb (2)
21-31: Add error handling for file reading.
File.readlineswill raise an exception if the file becomes unreadable between the existence check and the read operation (TOCTOU issue), or if there are permission issues.Apply this diff to add error handling:
def load_config - File.readlines(@config_file).each do |line| - next if line.strip.empty? || line.strip.start_with?('#') - - if line =~ /^SHAKAPACKER_VERSION\s*=\s*["'](.+)["']/ - @shakapacker_version = ::Regexp.last_match(1) - elsif line =~ /^REACT_ON_RAILS_VERSION\s*=\s*["'](.+)["']/ - @react_on_rails_version = ::Regexp.last_match(1) + File.readlines(@config_file).each do |line| + next if line.strip.empty? || line.strip.start_with?('#') + + if line =~ /^SHAKAPACKER_VERSION\s*=\s*["'](.+)["']/ + @shakapacker_version = ::Regexp.last_match(1) + elsif line =~ /^REACT_ON_RAILS_VERSION\s*=\s*["'](.+)["']/ + @react_on_rails_version = ::Regexp.last_match(1) + end + end +rescue Errno::EACCES, Errno::ENOENT => e + # File became inaccessible; silently fall back to defaults + warn "Warning: Could not read config file #{@config_file}: #{e.message}" if ENV['DEBUG'] +end + +private + +def load_config + begin + File.readlines(@config_file).each do |line| + next if line.strip.empty? || line.strip.start_with?('#') + + if line =~ /^SHAKAPACKER_VERSION\s*=\s*["'](.+)["']/ + @shakapacker_version = ::Regexp.last_match(1) + elsif line =~ /^REACT_ON_RAILS_VERSION\s*=\s*["'](.+)["']/ + @react_on_rails_version = ::Regexp.last_match(1) + end end + rescue Errno::EACCES, Errno::ENOENT => e + # Silently fall back to defaults, optionally warn in debug mode + warn "Warning: Could not read #{@config_file}: #{e.message}" if ENV['DEBUG'] end end
25-28: Regex patterns could be stricter.The regex patterns allow any characters within quotes (
.+), which could match malformed input or excessively long strings.Consider using a more restrictive pattern:
- if line =~ /^SHAKAPACKER_VERSION\s*=\s*["'](.+)["']/ + if line =~ /^SHAKAPACKER_VERSION\s*=\s*["']([~>= \d.]+)["']/ @shakapacker_version = ::Regexp.last_match(1) - elsif line =~ /^REACT_ON_RAILS_VERSION\s*=\s*["'](.+)["']/ + elsif line =~ /^REACT_ON_RAILS_VERSION\s*=\s*["']([~>= \d.]+)["']/ @react_on_rails_version = ::Regexp.last_match(1) endThis limits matches to valid gem version specifiers (digits, dots, and version operators).
bin/new-demo (1)
35-41: Comma-separated argument parsing may silently accept malformed input.The
split(',').map(&:strip)approach doesn't validate that arguments are well-formed Rails/React on Rails options. For example,--rails-args="--skip-test,,--api"would create an empty string element.Consider filtering out empty strings:
opts.on('--rails-args ARGS', 'Additional arguments to pass to rails new (comma-separated)') do |args| - options[:rails_args] = args.split(',').map(&:strip) + options[:rails_args] = args.split(',').map(&:strip).reject(&:empty?) end opts.on('--react-on-rails-args ARGS', 'Additional arguments to pass to react_on_rails:install (comma-separated)') do |args| - options[:react_on_rails_args] = args.split(',').map(&:strip) + options[:react_on_rails_args] = args.split(',').map(&:strip).reject(&:empty?) endlib/demo_scripts/pre_flight_checks.rb (1)
36-41: Handle repos with no initial commit.git diff-index HEAD fails on repos without HEAD. Prefer “git status --porcelain” to detect a clean tree.
- def check_uncommitted_changes! - if system('git diff-index --quiet HEAD -- 2>/dev/null') + def check_uncommitted_changes! + if `git status --porcelain 2>/dev/null`.strip.empty? puts '✓ No uncommitted changes' if @verbose return endlib/demo_scripts/demo_scaffolder.rb (1)
79-91: Prefer argv arrays with CommandRunner to avoid shell quoting issues.Once CommandRunner supports argv/chdir, pass arguments as arrays for safety. Example changes:
- @runner.run!( - "bundle exec rails generate react_on_rails:install #{all_args}", - dir: @demo_dir - ) + @runner.run!(["bundle", "exec", "rails", "generate", "react_on_rails:install", *all_args.split(' ')], dir: @demo_dir)- @runner.run!( - 'npm install --save-dev typescript @types/react @types/react-dom', - dir: @demo_dir - ) + @runner.run!(["npm", "install", "--save-dev", "typescript", "@types/react", "@types/react-dom"], dir: @demo_dir)- @runner.run!( - 'npm install --save-dev tailwindcss postcss autoprefixer', - dir: @demo_dir - ) - @runner.run!('npx tailwindcss init -p', dir: @demo_dir) + @runner.run!(["npm", "install", "--save-dev", "tailwindcss", "postcss", "autoprefixer"], dir: @demo_dir) + @runner.run!(["npx", "tailwindcss", "init", "-p"], dir: @demo_dir)- @runner.run!('npm install bootstrap react-bootstrap', dir: @demo_dir) + @runner.run!(["npm", "install", "bootstrap", "react-bootstrap"], dir: @demo_dir)- @runner.run!( - 'npm install @mui/material @emotion/react @emotion/styled', - dir: @demo_dir - ) + @runner.run!(["npm", "install", "@mui/material", "@emotion/react", "@emotion/styled"], dir: @demo_dir)- @runner.run!('npm install', dir: @demo_dir) + @runner.run!(["npm", "install"], dir: @demo_dir)- @runner.run('bundle exec rubocop -a --fail-level error', dir: @demo_dir) + @runner.run(["bundle", "exec", "rubocop", "-a", "--fail-level", "error"], dir: @demo_dir)Also applies to: 93-105, 107-128, 130-134, 136-143, 145-149, 183-187
lib/demo_scripts/demo_updater.rb (3)
86-101: Use argv arrays for bundle add (align with safer CommandRunner).Preps for the safer CommandRunner.
- @runner.run!( - "bundle add react_on_rails --version '#{@react_on_rails_version}' --skip-install", - dir: demo_path - ) + @runner.run!(["bundle", "add", "react_on_rails", "--version", @react_on_rails_version.to_s, "--skip-install"], dir: demo_path)- @runner.run!( - "bundle add shakapacker --version '#{@shakapacker_version}' --skip-install", - dir: demo_path - ) + @runner.run!(["bundle", "add", "shakapacker", "--version", @shakapacker_version.to_s, "--skip-install"], dir: demo_path)
102-105: Also switch bundle/rspec invocations to argv arrays.- @runner.run!('bundle install', dir: demo_path) + @runner.run!(["bundle", "install"], dir: demo_path)- success = @runner.run('bundle exec rspec --fail-fast', dir: demo_path) + success = @runner.run(["bundle", "exec", "rspec", "--fail-fast"], dir: demo_path)Also applies to: 135-148
130-133: Make README date update robust (handle existing “Updated:” lines).If README already has “Updated: …”, current logic won’t bump the date. Update both cases.
- content.gsub!(/Created:.*/, "Updated: #{current_date}") + if content =~ /Updated: .*/ + content.gsub!(/Updated:.*/, "Updated: #{current_date}") + else + content.gsub!(/Created:.*/, "Updated: #{current_date}") + endpackages/demo_common/lib/generators/demo_common/install/install_generator.rb (1)
7-140: Consider making the generator idempotent.The generator will overwrite existing configuration files without checking if they've been customized. For files created with
create_file(like.rubocop.yml,.eslintrc.js, etc.), consider usingcreate_file ... unless File.exist?(...)or adding a force/skip prompt to preserve user customizations when re-running the generator.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Gemfile.lockis excluded by!**/*.lock
📒 Files selected for processing (38)
.github/workflows/ci.yml(1 hunks).rspec(1 hunks).rubocop.yml(1 hunks)Gemfile(1 hunks)Gemfile.development_dependencies(1 hunks)README.md(1 hunks)Rakefile(1 hunks)bin/new-demo(1 hunks)bin/scaffold-demo(1 hunks)bin/update-all-demos(1 hunks)docs/CONTRIBUTING_SETUP.md(1 hunks)docs/VERSION_MANAGEMENT.md(1 hunks)lefthook.yml(1 hunks)lib/demo_scripts.rb(1 hunks)lib/demo_scripts/command_runner.rb(1 hunks)lib/demo_scripts/config.rb(1 hunks)lib/demo_scripts/demo_creator.rb(1 hunks)lib/demo_scripts/demo_scaffolder.rb(1 hunks)lib/demo_scripts/demo_updater.rb(1 hunks)lib/demo_scripts/pre_flight_checks.rb(1 hunks)lib/demo_scripts/version.rb(1 hunks)packages/demo_common/Gemfile(1 hunks)packages/demo_common/README.md(1 hunks)packages/demo_common/Rakefile(1 hunks)packages/demo_common/demo_common.gemspec(1 hunks)packages/demo_common/lib/demo_common.rb(1 hunks)packages/demo_common/lib/demo_common/railtie.rb(1 hunks)packages/demo_common/lib/demo_common/version.rb(1 hunks)packages/demo_common/lib/generators/demo_common/install/install_generator.rb(1 hunks)packages/demo_common/lib/tasks/demo_common.rake(2 hunks)scripts/new-demo.sh(1 hunks)scripts/scaffold-demo.sh(1 hunks)scripts/test-all.sh(1 hunks)spec/demo_scripts/command_runner_spec.rb(1 hunks)spec/demo_scripts/config_spec.rb(1 hunks)spec/demo_scripts/demo_creator_spec.rb(1 hunks)spec/demo_scripts/pre_flight_checks_spec.rb(1 hunks)spec/spec_helper.rb(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- packages/demo_common/Gemfile
- .rubocop.yml
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/demo_common/README.md
- scripts/test-all.sh
- packages/demo_common/demo_common.gemspec
- docs/VERSION_MANAGEMENT.md
🧰 Additional context used
🧬 Code graph analysis (12)
lib/demo_scripts/command_runner.rb (3)
lib/demo_scripts/demo_creator.rb (2)
initialize(5-217)initialize(6-26)lib/demo_scripts/demo_scaffolder.rb (2)
initialize(5-354)initialize(6-37)lib/demo_scripts/demo_updater.rb (2)
initialize(5-184)initialize(6-23)
spec/demo_scripts/pre_flight_checks_spec.rb (1)
lib/demo_scripts/pre_flight_checks.rb (1)
run!(11-19)
spec/demo_scripts/demo_creator_spec.rb (1)
lib/demo_scripts/demo_creator.rb (1)
create!(28-49)
lib/demo_scripts/pre_flight_checks.rb (2)
lib/demo_scripts/demo_creator.rb (2)
initialize(5-217)initialize(6-26)lib/demo_scripts/demo_scaffolder.rb (2)
initialize(5-354)initialize(6-37)
spec/demo_scripts/command_runner_spec.rb (1)
lib/demo_scripts/command_runner.rb (3)
run(13-24)run!(26-31)capture(33-42)
lib/demo_scripts/demo_updater.rb (2)
lib/demo_scripts/demo_creator.rb (2)
initialize(5-217)initialize(6-26)lib/demo_scripts/command_runner.rb (3)
initialize(8-11)run!(26-31)run(13-24)
lib/demo_scripts/config.rb (1)
lib/demo_scripts/demo_creator.rb (2)
initialize(5-217)initialize(6-26)
lib/demo_scripts/demo_creator.rb (4)
lib/demo_scripts/demo_scaffolder.rb (6)
initialize(5-354)initialize(6-37)create!(39-67)setup_database(71-77)print_completion_message(332-353)generate_readme_content(232-330)lib/demo_scripts/command_runner.rb (2)
initialize(8-11)run!(26-31)lib/demo_scripts/config.rb (1)
initialize(11-17)lib/demo_scripts/pre_flight_checks.rb (3)
initialize(5-54)initialize(6-9)run!(11-19)
lib/demo_scripts/demo_scaffolder.rb (4)
lib/demo_scripts/demo_creator.rb (13)
initialize(5-217)initialize(6-26)create!(28-49)run_pre_flight_checks(53-55)create_rails_app(57-73)setup_database(75-79)add_gems(81-95)add_demo_common(97-114)create_symlinks(116-121)install_shakapacker(123-127)create_readme(140-148)print_completion_message(202-216)generate_readme_content(150-200)lib/demo_scripts/command_runner.rb (3)
initialize(8-11)run!(26-31)run(13-24)lib/demo_scripts/config.rb (1)
initialize(11-17)lib/demo_scripts/pre_flight_checks.rb (3)
initialize(5-54)initialize(6-9)run!(11-19)
packages/demo_common/lib/generators/demo_common/install/install_generator.rb (1)
packages/demo_common/lib/demo_common.rb (2)
root(10-12)config_path(14-16)
scripts/scaffold-demo.sh (2)
scripts/new-demo.sh (2)
show_usage(26-41)run_cmd(97-104)scripts/update-all-demos.sh (2)
show_usage(12-31)run_cmd(80-86)
scripts/new-demo.sh (1)
scripts/scaffold-demo.sh (2)
show_usage(26-47)run_cmd(133-140)
🪛 actionlint (1.7.7)
.github/workflows/ci.yml
78-78: "matrix values" section should not be empty
(syntax-check)
🪛 Brakeman (7.0.2)
lib/demo_scripts/command_runner.rb
[medium] 41-41: Possible command injection
Type: Command Injection
Confidence: Medium
More info: https://brakemanscanner.org/docs/warning_types/command_injection/
(Command Injection)
[medium] 23-23: Possible command injection
Type: Command Injection
Confidence: Medium
More info: https://brakemanscanner.org/docs/warning_types/command_injection/
(Command Injection)
🪛 markdownlint-cli2 (0.18.1)
docs/CONTRIBUTING_SETUP.md
47-47: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
52-52: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
59-59: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
README.md
47-47: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
52-52: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
59-59: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🪛 Shellcheck (0.11.0)
scripts/scaffold-demo.sh
[warning] 138-138: eval negates the benefit of arrays. Drop eval to preserve whitespace/symbols (or eval as string).
(SC2294)
[warning] 381-381: CURRENT_DATE appears unused. Verify use (or export if used externally).
(SC2034)
scripts/new-demo.sh
[warning] 102-102: eval negates the benefit of arrays. Drop eval to preserve whitespace/symbols (or eval as string).
(SC2294)
🔇 Additional comments (45)
.rspec (1)
1-3: LGTM! Standard RSpec configuration.The configuration correctly enables spec_helper auto-require, colored output, and documentation formatting, which are standard best practices for RSpec projects.
packages/demo_common/lib/demo_common/version.rb (1)
1-5: LGTM! Standard version constant definition.The version module follows Ruby conventions with frozen string literal and a semantic version constant, appropriate for the initial 0.1.0 release of the demo_common gem.
Gemfile.development_dependencies (3)
1-24: Well-structured shared dependencies file with clear documentation.The file provides a clean, centralized manifest for demo development dependencies with helpful usage instructions. The gem selections and version constraints are appropriate for a modern Rails/RSpec development environment.
13-16: Addresses duplication concern with root Gemfile.These rubocop gems (rubocop, rubocop-performance, rubocop-rspec) also appear in the root Gemfile. Since this file is intended to be loaded by demo applications via
eval_gemfile, and the root Gemfile serves the monorepo root, the duplication may be intentional. However, consider whether demos should exclusively use this shared file while the root uses a different set, or if consolidation is possible.
23-23: Retain thelistengem for Rails 7+ evented file watching. Rails 7 still expects and recommendslistenfor the ActiveSupport::EventedFileUpdateChecker in development.Likely an incorrect or invalid review comment.
spec/spec_helper.rb (1)
1-27: LGTM! Comprehensive and well-configured RSpec setup.The spec helper follows RSpec best practices with appropriate configurations for expectations, mocks, example persistence, monkey patching disabled, profiling, and randomized execution. The setup properly supports the new DemoScripts test suite.
Gemfile (1)
7-12: No action required: development dependencies file isn’t evaluated by the root Gemfile.
The root Gemfile doesn’t reference Gemfile.development_dependencies (no eval_gemfile) so overlapping gems live in separate contexts and won’t conflict.Likely an incorrect or invalid review comment.
docs/CONTRIBUTING_SETUP.md (1)
1-180: Documentation is comprehensive and well-structured.The setup guide covers all essential development tasks, from initial setup through git hooks, testing, linting, and troubleshooting. The inclusion of Lefthook configuration details and best practices is particularly valuable for new contributors.
packages/demo_common/lib/demo_common.rb (1)
1-22: LGTM! Clean module structure with path helpers.The module provides a clear public API for accessing package paths. The use of
Pathnameand conditional Railtie loading follows Ruby best practices..github/workflows/ci.yml (1)
10-124: CI workflow is well-structured for the monorepo.The workflow appropriately separates linting and testing concerns across demo_common and individual demos. The dynamic demo detection for PRs is a good approach for selective testing.
README.md (2)
31-46: Clarify where bundle install should be run.The prerequisites mention Ruby 3.3+, but the setup instructions show
bundle installwithout specifying the working directory. Should this be run from the repository root or frompackages/demo_common/?Consider adding a working directory comment:
```bash -# Install dependencies +# Install dependencies (run from repository root) bundle install
1-141: README provides clear guidance for monorepo navigation.The documentation effectively communicates the new monorepo structure, script-driven workflows, and version management. The distinction between Ruby and Bash scripts is helpful for users.
Rakefile (1)
1-14: LGTM! Clean integration of linting into the default test flow.The Rakefile now provides a unified test-and-lint workflow through the
defaulttask, with a convenienttestalias. Removing the dynamic task loading simplifies the build configuration.spec/demo_scripts/config_spec.rb (2)
16-60: LGTM!The tests properly cover custom version overrides, file-based config loading, and edge cases like comments and empty lines. The use of
Dir.mktmpdirensures proper cleanup and isolation.
62-79: LGTM!The test correctly validates that constructor-provided versions take precedence over config file values, and demonstrates partial override behavior (only
react_on_rails_versionis overridden whileshakapacker_versionis loaded from the file).bin/scaffold-demo (3)
1-20: LGTM!The executable setup is clean with proper requires and well-structured default options. All flags are explicitly initialized.
22-82: LGTM!The option parsing is well-structured with clear help text and examples. The handling of comma-separated arguments with
split(',').map(&:strip)is appropriate for CLI input.
84-107: LGTM!The main execution flow properly validates that a demo name is provided, initializes the scaffolder with the parsed options, and handles both application errors (
DemoScripts::Error) and option parsing errors appropriately. Exit status 1 is correctly used for all error conditions.lib/demo_scripts.rb (2)
1-9: LGTM!The require structure is clean and well-organized, loading core components (version, config) before higher-level functionality (creators, scaffolders, updater).
11-16: LGTM!The exception hierarchy is well-designed with a base
Errorclass inheriting fromStandardError(Ruby best practice) and specialized error types (PreFlightCheckError,CommandError) for different failure modes, enabling precise error handling in client code.spec/demo_scripts/pre_flight_checks_spec.rb (4)
1-19: LGTM!The test setup properly isolates each test with cleanup in both
beforeandafterblocks. Usingverbose: falseprevents output pollution during test runs.
32-43: LGTM!The test properly validates that an existing directory triggers a
PreFlightCheckError. The regex matcher allows for flexible message matching.
45-56: LGTM!The test correctly stubs the git repository check and validates the expected error. Using a regex for the command allows flexibility in the exact git command format.
58-71: LGTM!The test correctly simulates being in a git repository with uncommitted changes by stubbing both
git rev-parse(returns true) andgit diff-index(returns false). This properly validates the uncommitted changes check.spec/demo_scripts/demo_creator_spec.rb (5)
1-21: LGTM!The initialization test provides good baseline coverage, verifying that a
DemoCreatorcan be instantiated with the expected options.
23-42: LGTM!The tests properly validate dry-run mode behavior: output indicates dry-run status and no demo directory is created. Using
skip_pre_flight: trueappropriately avoids git state dependencies in unit tests.
44-61: LGTM!The test appropriately uses
sendto access the privategenerate_readme_contentmethod for validation. It correctly verifies that gem versions and the version header are included in the generated README.
63-68: LGTM!The test correctly validates that the creation date in
YYYY-MM-DDformat is included in the generated README.
70-75: LGTM!The test validates that the README includes a link to the version management documentation, ensuring discoverability of important documentation for demo users.
scripts/new-demo.sh (3)
83-88: Good validation and pre-flight checks!The demo name validation prevents path traversal, and the comprehensive pre-flight checks (directory existence, git status, git repository) prevent common errors. This addresses the concerns from previous reviews.
Also applies to: 109-134
204-209: JS dependency installation is now included.The script correctly installs JavaScript dependencies after running the installers, addressing the previous review concern. The conditional check for
pnpmwith fallback tonpmis a good practice.
147-157: No action needed: multi-linerails newis handled correctly
The backslash-newline escapes collapse at parse time into a single string argument, sorun_cmd’seval "$@"executes the full command as intended.lib/demo_scripts/config.rb (1)
1-17: LGTM! Clean configuration loader with proper precedence.The initialization logic correctly implements the precedence order (explicit arguments → file-loaded values → defaults), and the default constants are well-defined.
bin/new-demo (2)
1-14: LGTM! Clean setup with proper dependencies.The script correctly requires dependencies and initializes the options hash with appropriate defaults.
54-77: Good error handling with specific exception types.The error handling appropriately catches
DemoScripts::Errorfor domain errors andOptionParser::InvalidOptionfor CLI parsing errors, providing clear messages and proper exit codes.lib/demo_scripts/demo_updater.rb (1)
34-38: Confirm error type resolves to DemoScripts::Error.Ensure DemoScripts::Error exists and is required before DemoUpdater loads; otherwise qualify or require the defining file.
Would you like me to scan the repo to confirm the definition and load order?
packages/demo_common/lib/generators/demo_common/install/install_generator.rb (9)
12-15: Verify error handling for npm command.The
runmethod doesn't halt the generator on command failure by default. If npm is unavailable or the path is invalid, the installation will continue silently.Consider whether explicit error checking is needed:
def add_npm_package say 'Adding @shakacode/react-on-rails-demo-common to package.json' unless run "npm install --save-dev @shakacode/react-on-rails-demo-common@file:#{gem_root_path}", abort_on_failure: true say 'Failed to install npm package', :red exit(1) end end
17-22: Verify error handling for sequential commands.Multiple shell commands are executed without checking for failures. If npm or lefthook is unavailable, or if any command fails, subsequent commands may produce unexpected results.
24-32: LGTM!The RuboCop configuration creation is well-structured with proper YAML formatting and clear guidance for project-specific overrides.
34-44: LGTM!The ESLint configuration follows a good pattern for extending shared config with clear guidance for project-specific overrides.
46-53: LGTM!The Prettier configuration setup correctly reuses the shared config and copies the ignore file.
75-82: LGTM!The Commitlint configuration is correctly structured.
84-87: LGTM!The GitHub Actions workflow setup uses the standard Rails generator
templatemethod appropriately.
89-105: LGTM!The .gitignore updates are well-organized with clear section comments.
107-119: LGTM!The post-install instructions are clear, well-formatted, and provide helpful next steps.
.github/workflows/ci.yml
Outdated
| run: npm run lint | ||
| continue-on-error: true # Allow to continue if lint script doesn't exist | ||
| - name: Check Prettier formatting | ||
| run: npm run format:check | ||
| continue-on-error: true # Allow to continue if format script doesn't exist |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify that npm scripts exist before using continue-on-error.
Both npm run lint and npm run format:check use continue-on-error: true, which silently ignores failures if the scripts don't exist. This can mask configuration issues.
Run this script to verify the npm scripts are defined in package.json:
🏁 Script executed:
#!/bin/bash
# Description: Check if lint and format:check scripts exist in package.json
if [ -f "packages/demo_common/package.json" ]; then
echo "Checking for npm scripts in packages/demo_common/package.json:"
jq -r '.scripts | keys[]' packages/demo_common/package.json | grep -E '^(lint|format:check)$' || echo "Missing lint or format:check scripts"
else
echo "package.json not found at packages/demo_common/package.json"
fiLength of output: 176
Lint and formatting CI steps silently ignored
In .github/workflows/ci.yml (lines 66–70), the npm run lint and npm run format:check steps use continue-on-error: true despite the corresponding scripts missing in packages/demo_common/package.json. This masks failures.
- Add
lintandformat:checkscripts topackages/demo_common/package.json. - Remove
continue-on-error: trueso CI fails on errors. - Or switch to
npm run lint --if-presentandnpm run format:check --if-present.
🤖 Prompt for AI Agents
.github/workflows/ci.yml lines 66-70: the workflow currently runs `npm run lint`
and `npm run format:check` with `continue-on-error: true`, which masks failures
because the scripts are missing; fix by either (A) adding `lint` and
`format:check` scripts to packages/demo_common/package.json so the commands
exist and then remove the `continue-on-error: true` lines so CI fails on errors,
or (B) update the workflow commands to `npm run lint --if-present` and `npm run
format:check --if-present` and remove `continue-on-error: true` so the steps are
no-ops when scripts are absent but still fail for real script errors—make the
change consistently for both steps and remove the `continue-on-error` keys.
| demo_name = ARGV[0] | ||
|
|
||
| creator = DemoScripts::DemoCreator.new( | ||
| demo_name: demo_name, | ||
| **options | ||
| ) | ||
|
|
||
| creator.create! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Validate demo name before passing to DemoCreator.
The script accepts any ARGV[0] as the demo name without validation. While DemoCreator might validate internally, the CLI should provide early feedback to avoid unnecessary work.
Let's verify whether DemoCreator validates the demo name:
🏁 Script executed:
#!/bin/bash
# Check if DemoCreator validates demo names
ast-grep --pattern 'class DemoCreator
$$$
def initialize($$$)
$$$
end
$$$
'
# Also search for validation methods
rg -n "def.*validate" lib/demo_scripts/demo_creator.rbLength of output: 0
🏁 Script executed:
#!/bin/bash
# Locate the DemoCreator source file
fd demo_creator\.rb
# Inspect the first 200 lines of the file to find initialize and any validation logic
sed -n '1,200p' lib/demo_scripts/demo_creator.rb
# Search within for demo_name handling and validation methods
rg -n "demo_name" -C3 lib/demo_scripts/demo_creator.rb
rg -n "validate" -C3 lib/demo_scripts/demo_creator.rbLength of output: 6682
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show occurrences of PreFlightChecks
rg -n "PreFlightChecks" -S || true
# If the common location exists, print it
if [ -f lib/demo_scripts/pre_flight_checks.rb ]; then
sed -n '1,240p' lib/demo_scripts/pre_flight_checks.rb
fi
# Print the CLI script to check ARGV handling
sed -n '1,260p' bin/new-demoLength of output: 3609
Add demo name validation in bin/new-demo
The CLI currently accepts any string as DEMO_NAME and neither DemoCreator nor PreFlightChecks enforce a valid format or sanitize path inputs. Add a validation step in bin/new-demo—for example, enforce something like /\A[a-zA-Z0-9_-]+\z/—and exit early with a clear error if the name is invalid.
🤖 Prompt for AI Agents
In bin/new-demo around lines 62 to 69, the script currently passes any demo_name
from ARGV[0] into DemoCreator; add a validation step before constructing
DemoCreator that checks ARGV[0] exists and matches the allowed pattern (for
example /\A[a-zA-Z0-9_-]+\z/), and if it fails print a clear error to STDERR and
exit with a nonzero status; ensure this validation occurs before any filesystem
or creator actions so invalid names are rejected early (optionally also enforce
a max length and reject values containing path separators to prevent traversal).
| parallel: true | ||
| commands: | ||
| trailing-newline: | ||
| glob: "*.{rb,js,ts,jsx,tsx,yml,yaml,json,md,sh}" | ||
| run: | | ||
| for file in {staged_files}; do | ||
| if [ -f "$file" ]; then | ||
| # Check if file ends with newline | ||
| if [ -n "$(tail -c 1 "$file")" ]; then | ||
| echo "❌ Missing trailing newline: $file" | ||
| # Add trailing newline | ||
| echo "" >> "$file" | ||
| git add "$file" | ||
| echo "✅ Added trailing newline to: $file" | ||
| fi | ||
| fi | ||
| done | ||
| rubocop: | ||
| glob: "*.rb" | ||
| run: bundle exec rubocop --force-exclusion {staged_files} | ||
| stage_fixed: true | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Run pre-commit commands sequentially when they git add.
With parallel: true, Lefthook can launch trailing-newline and rubocop at the same time. Both commands ultimately execute git add (explicitly in the newline fixer and implicitly via stage_fixed: true), so they’ll race on .git/index and intermittently fail with “index.lock” errors. Flip the block back to sequential execution (or move the newline fixer into a separate serial block) so only one command touches the index at a time.
Apply this diff:
pre-commit:
- parallel: true
+ parallel: false🤖 Prompt for AI Agents
In lefthook.yml around lines 5 to 27, running commands in parallel causes races
on git index because both trailing-newline (which calls git add) and rubocop
(which uses stage_fixed) can touch .git/index concurrently; change execution to
sequential by removing or setting parallel to false for this block (or move the
trailing-newline hook into a separate serial block) so only one command performs
git add at a time, preventing intermittent index.lock errors.
| for file in {staged_files}; do | ||
| if [ -f "$file" ]; then | ||
| # Check if file ends with newline | ||
| if [ -n "$(tail -c 1 "$file")" ]; then | ||
| echo "❌ Missing trailing newline: $file" | ||
| # Add trailing newline | ||
| echo "" >> "$file" | ||
| git add "$file" | ||
| echo "✅ Added trailing newline to: $file" | ||
| fi | ||
| fi | ||
| done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle staged paths with spaces.
for file in {staged_files}; do splits on whitespace, so a staged file like docs/Release Notes.md is never processed and the hook silently fails to add the newline. Read the staged list with a NUL‑delimited loop (via git diff --cached --name-only -z) to preserve spaces and other special characters.
Apply this diff:
- for file in {staged_files}; do
- if [ -f "$file" ]; then
- # Check if file ends with newline
- if [ -n "$(tail -c 1 "$file")" ]; then
- echo "❌ Missing trailing newline: $file"
- # Add trailing newline
- echo "" >> "$file"
- git add "$file"
- echo "✅ Added trailing newline to: $file"
- fi
- fi
- done
+ git diff --cached --name-only -z -- '*.{rb,js,ts,jsx,tsx,yml,yaml,json,md,sh}' |
+ while IFS= read -r -d '' file; do
+ if [ -f "$file" ] && [ -n "$(tail -c 1 "$file")" ]; then
+ echo "❌ Missing trailing newline: $file"
+ echo "" >> "$file"
+ git add "$file"
+ echo "✅ Added trailing newline to: $file"
+ fi
+ done📝 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.
| for file in {staged_files}; do | |
| if [ -f "$file" ]; then | |
| # Check if file ends with newline | |
| if [ -n "$(tail -c 1 "$file")" ]; then | |
| echo "❌ Missing trailing newline: $file" | |
| # Add trailing newline | |
| echo "" >> "$file" | |
| git add "$file" | |
| echo "✅ Added trailing newline to: $file" | |
| fi | |
| fi | |
| done | |
| git diff --cached --name-only -z -- '*.{rb,js,ts,jsx,tsx,yml,yaml,json,md,sh}' | | |
| while IFS= read -r -d '' file; do | |
| if [ -f "$file" ] && [ -n "$(tail -c 1 "$file")" ]; then | |
| echo "❌ Missing trailing newline: $file" | |
| echo "" >> "$file" | |
| git add "$file" | |
| echo "✅ Added trailing newline to: $file" | |
| fi | |
| done |
🤖 Prompt for AI Agents
In lefthook.yml around lines 10 to 21, the current for-loop splits staged file
paths on whitespace so files with spaces are skipped; replace the iteration with
a NUL-delimited read loop that obtains staged paths using git diff --cached
--name-only -z and then uses while IFS= read -r -d '' file; do ... done to
handle filenames with spaces and special characters safely, keeping the same
checks (ensure file exists, check trailing newline with tail -c 1, append a
newline when missing, and git add the modified file) and ensure all uses of
$file are properly quoted.
| @@ -0,0 +1,44 @@ | |||
| # frozen_string_literal: true | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Add required dependency.
Needed for Open3 usage above.
# frozen_string_literal: true
+
+require 'open3'📝 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.
| # frozen_string_literal: true | |
| # frozen_string_literal: true | |
| require 'open3' |
🤖 Prompt for AI Agents
In lib/demo_scripts/command_runner.rb around lines 1 to 1, the file uses Open3
but doesn't require it; add the missing dependency by inserting require 'open3'
at the top of the file (immediately after the frozen_string_literal comment) so
Open3 methods are available.
| def add_npm_scripts | ||
| say 'Adding npm scripts' | ||
| package_json_path = Rails.root.join('package.json') | ||
|
|
||
| return unless File.exist?(package_json_path) | ||
|
|
||
| package_json = JSON.parse(File.read(package_json_path)) | ||
|
|
||
| package_json['scripts'] ||= {} | ||
| package_json['scripts'].merge!({ | ||
| 'lint' => 'eslint . --ext .js,.jsx,.ts,.tsx', | ||
| 'lint:fix' => 'eslint . --ext .js,.jsx,.ts,.tsx --fix', | ||
| 'format' => "prettier --write '**/*.{js,jsx,ts,tsx,json,css,scss,md}'", | ||
| 'format:check' => "prettier --check '**/*.{js,jsx,ts,tsx,json,css,scss,md}'", | ||
| 'prepare' => 'lefthook install' | ||
| }) | ||
|
|
||
| File.write(package_json_path, JSON.pretty_generate(package_json)) | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for JSON parsing and consider merge behavior.
Two concerns:
JSON.parsewill raise an exception if package.json is malformed, halting the generator unexpectedly.merge!will silently overwrite any existing scripts with the same keys. Consider whether this is intentional or if you should preserve existing scripts.
Consider adding error handling:
def add_npm_scripts
say 'Adding npm scripts'
package_json_path = Rails.root.join('package.json')
return unless File.exist?(package_json_path)
begin
package_json = JSON.parse(File.read(package_json_path))
rescue JSON::ParserError => e
say "Failed to parse package.json: #{e.message}", :red
return
end
package_json['scripts'] ||= {}
# Consider using reverse_merge! to preserve existing scripts
package_json['scripts'].merge!({
# ... scripts
})
File.write(package_json_path, JSON.pretty_generate(package_json))
end🤖 Prompt for AI Agents
In packages/demo_common/lib/generators/demo_common/install/install_generator.rb
around lines 55 to 73, JSON.parse(File.read(package_json_path)) can raise
JSON::ParserError and halt the generator, and merge! will silently overwrite
existing npm scripts; wrap the parse in a begin/rescue that catches
JSON::ParserError, say a clear error (e.g., say "Failed to parse package.json:
#{e.message}", :red) and return early so you don't overwrite the file, and
change the merging behavior to preserve existing scripts (use a non-destructive
approach such as only adding keys that don't exist or using reverse_merge-like
semantics) before writing the updated package.json.
...ages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/install_generator.rb
Show resolved
Hide resolved
|
|
||
| # Validate demo name: alphanumeric, hyphens, underscores only; no path separators | ||
| if [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then | ||
| echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undefined color variables will cause display issues.
Line 85 references ${RED} and ${NC} but these variables are never defined in the script, resulting in empty strings being output.
Apply this diff to define the color variables:
set -euo pipefail
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
# Load default versions from config file📝 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.
| echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" | |
| set -euo pipefail | |
| # Colors for output | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| NC='\033[0m' # No Color | |
| # Load default versions from config file | |
| # (rest of script continues…) |
🤖 Prompt for AI Agents
In scripts/new-demo.sh around line 85, the echo uses undefined color variables
${RED} and ${NC}; define ANSI color variables (e.g., RED and NC/reset) near the
top of the script (or before use) so they are non-empty and safe, e.g., add
assignments like RED='\033[0;31m' and NC='\033[0m' (or wrap in a conditional to
only set when output is a tty) so the error message prints with proper coloring
without producing empty strings.
| # Validate demo name: alphanumeric, hyphens, underscores only; no path separators | ||
| if [[ -z "$DEMO_NAME" ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then | ||
| echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" | ||
| echo "Demo name must contain only letters, numbers, hyphens, and underscores" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reject demo names starting with “-”. Allowing a leading hyphen means every subsequent cd '$DEMO_DIR' is interpreted as an option (cd -foo), so the scaffold fails immediately after rails new. Add an explicit guard so names beginning with - are rejected up front.
Apply this diff:
-if [[ -z "$DEMO_NAME" ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then
+if [[ -z "$DEMO_NAME" ]] || [[ "$DEMO_NAME" =~ ^- ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then📝 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.
| # Validate demo name: alphanumeric, hyphens, underscores only; no path separators | |
| if [[ -z "$DEMO_NAME" ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then | |
| echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" | |
| echo "Demo name must contain only letters, numbers, hyphens, and underscores" | |
| exit 1 | |
| fi | |
| # Validate demo name: alphanumeric, hyphens, underscores only; no path separators | |
| if [[ -z "$DEMO_NAME" ]] || [[ "$DEMO_NAME" =~ ^- ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then | |
| echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" | |
| echo "Demo name must contain only letters, numbers, hyphens, and underscores" | |
| exit 1 | |
| fi |
🤖 Prompt for AI Agents
In scripts/scaffold-demo.sh around lines 69 to 74, the demo name validation
currently allows names that begin with a hyphen which causes commands like cd to
treat them as options; add an explicit guard rejecting names that start with '-'
(for example check if DEMO_NAME begins with '-' and fail with the same error
message), ensuring the script exits with status 1 when a leading hyphen is
detected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR reorganizes the repository into a monorepo structure to support multiple React on Rails demo applications. The existing code has been moved to packages/demo_common/ subdirectory and infrastructure has been added for managing multiple demos.
Key changes:
- Reorganized codebase into monorepo structure with
packages/anddemos/directories - Renamed Ruby gem from
react_on_rails_demo_commontodemo_common - Added comprehensive tooling for creating, managing, and testing demos with both Ruby and Bash scripts
Reviewed Changes
Copilot reviewed 48 out of 65 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/demo_common/ | Contains renamed and relocated shared configuration gem |
| lib/demo_scripts/ | New Ruby classes for demo creation and management |
| scripts/ | Bash scripts for demo operations (bootstrap, scaffold, test, update) |
| bin/ | Ruby executable scripts (recommended over bash versions) |
| docs/ | New documentation for version management and development setup |
| spec/ | Test coverage for new Ruby demo scripts |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
packages/demo_common/Rakefile
Outdated
|
|
||
| Example: `rake demo_common:release[1.2.0]` or `rake demo_common:release[1.2.0,true]` for dry run" | ||
| task :release, %i[gem_version dry_run] do |_t, args| | ||
| require_relative 'lib/react_on_rails_demo_common/version' |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The require path is incorrect. It should require demo_common/version since the gem was renamed from react_on_rails_demo_common to demo_common.
packages/demo_common/Rakefile
Outdated
| end | ||
|
|
||
| # Update version in version.rb | ||
| version_file = 'lib/react_on_rails_demo_common/version.rb' |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version file path is incorrect. It should be lib/demo_common/version.rb to match the renamed gem structure.
packages/demo_common/Rakefile
Outdated
| sh 'gem build react_on_rails_demo_common.gemspec' | ||
|
|
||
| puts "\nReady to push gem to RubyGems.org" | ||
| puts 'You may need to enter your RubyGems OTP' | ||
| sh "gem push react_on_rails_demo_common-#{gem_version}.gem" | ||
|
|
||
| # Clean up gem file | ||
| sh "rm react_on_rails_demo_common-#{gem_version}.gem" |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gemspec filename is incorrect. It should be demo_common.gemspec to match the renamed gem.
| sh 'gem build react_on_rails_demo_common.gemspec' | |
| puts "\nReady to push gem to RubyGems.org" | |
| puts 'You may need to enter your RubyGems OTP' | |
| sh "gem push react_on_rails_demo_common-#{gem_version}.gem" | |
| # Clean up gem file | |
| sh "rm react_on_rails_demo_common-#{gem_version}.gem" | |
| sh 'gem build demo_common.gemspec' | |
| puts "\nReady to push gem to RubyGems.org" | |
| puts 'You may need to enter your RubyGems OTP' | |
| sh "gem push demo_common-#{gem_version}.gem" | |
| # Clean up gem file | |
| sh "rm demo_common-#{gem_version}.gem" |
packages/demo_common/Rakefile
Outdated
| sh "gem push react_on_rails_demo_common-#{gem_version}.gem" | ||
|
|
||
| # Clean up gem file | ||
| sh "rm react_on_rails_demo_common-#{gem_version}.gem" |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gem filename is incorrect. It should be demo_common-#{gem_version}.gem to match the renamed gem.
| sh "gem push react_on_rails_demo_common-#{gem_version}.gem" | |
| # Clean up gem file | |
| sh "rm react_on_rails_demo_common-#{gem_version}.gem" | |
| sh "gem push demo_common-#{gem_version}.gem" | |
| # Clean up gem file | |
| sh "rm demo_common-#{gem_version}.gem" |
packages/demo_common/Rakefile
Outdated
| sh 'gem build react_on_rails_demo_common.gemspec' | ||
|
|
||
| puts "\nReady to push gem to RubyGems.org" | ||
| puts 'You may need to enter your RubyGems OTP' | ||
| sh "gem push react_on_rails_demo_common-#{gem_version}.gem" | ||
|
|
||
| # Clean up gem file | ||
| sh "rm react_on_rails_demo_common-#{gem_version}.gem" |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gem filename is incorrect. It should be demo_common-#{gem_version}.gem to match the renamed gem.
| sh 'gem build react_on_rails_demo_common.gemspec' | |
| puts "\nReady to push gem to RubyGems.org" | |
| puts 'You may need to enter your RubyGems OTP' | |
| sh "gem push react_on_rails_demo_common-#{gem_version}.gem" | |
| # Clean up gem file | |
| sh "rm react_on_rails_demo_common-#{gem_version}.gem" | |
| sh 'gem build demo_common.gemspec' | |
| puts "\nReady to push gem to RubyGems.org" | |
| puts 'You may need to enter your RubyGems OTP' | |
| sh "gem push demo_common-#{gem_version}.gem" | |
| # Clean up gem file | |
| sh "rm demo_common-#{gem_version}.gem" |
packages/demo_common/Rakefile
Outdated
| require_relative 'lib/react_on_rails_demo_common/version' | ||
| package_json = JSON.parse(File.read('package.json')) | ||
|
|
||
| puts "Gem version: #{ReactOnRailsDemoCommon::VERSION}" |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The require path and module reference are incorrect. They should use demo_common/version and DemoCommon::VERSION respectively to match the renamed gem.
| require_relative 'lib/react_on_rails_demo_common/version' | |
| package_json = JSON.parse(File.read('package.json')) | |
| puts "Gem version: #{ReactOnRailsDemoCommon::VERSION}" | |
| require 'demo_common/version' | |
| package_json = JSON.parse(File.read('package.json')) | |
| puts "Gem version: #{DemoCommon::VERSION}" |
| if [[ -z "$DEMO_NAME" ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then | ||
| echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variables RED and NC are referenced before they are defined. These color variables are defined later in the script on lines 7-10, but this validation happens before those definitions are reached.
| if [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then | ||
| echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variables RED and NC are referenced before they are defined. The color variables need to be moved before this validation block.
The DemoScaffolder class now has 13 parameters after adding rails_args and react_on_rails_args to support custom arguments for rails new and react_on_rails:install commands. This is reasonable given the class's responsibility for scaffolding demos with many configuration options. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Added Prettier configuration and tooling for consistent formatting across the monorepo: - Created package.json with Prettier dependency and npm scripts - Added .prettierrc configuration with standard settings - Added .prettierignore to exclude build outputs and dependencies - Formatted all existing files (markdown, YAML, JSON, JavaScript) - Updated README.md with Prettier usage instructions Demos will still use Prettier from @shakacode/react-on-rails-demo-common, but this allows formatting of root-level files and documentation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 56 out of 70 changed files in this pull request and generated 1 comment.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
scripts/scaffold-demo.sh
Outdated
| - **React on Rails**: \`$REACT_ON_RAILS_VERSION\` | ||
| - **Shakapacker**: \`$SHAKAPACKER_VERSION\` | ||
| Created: \$CURRENT_DATE |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable expansion syntax is incorrect. It should be Created: $CURRENT_DATE (without the backslash) to properly expand the CURRENT_DATE variable in the generated README.
| Created: \$CURRENT_DATE | |
| Created: $CURRENT_DATE |
…mands Improved user experience with detailed command descriptions and examples: Command Help Messages: - bin/new-demo: Added description explaining basic demo creation - bin/scaffold-demo: Added description for advanced demo scaffolding - bin/update-all-demos: Added description for bulk version updates - All commands now show clear usage, examples, and available options Documentation Updates: - README.md: Reorganized demo management section with detailed examples for all three commands - CONTRIBUTING.md: Updated with Ruby script recommendations and help flag usage - CONTRIBUTING_SETUP.md: Added links to main README for detailed examples - .gitignore: Added pr_description.md and commit_message.txt Users can now run --help on any command to see: - What the command does - Usage syntax - Example invocations - All available options 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Renamed the version configuration file for better clarity: - .demo-versions → .new-demo-versions This makes it clearer that this file configures defaults for NEW demos, and doesn't affect existing demos (as documented in the file itself). Updated all references: - lib/demo_scripts/config.rb: Updated default config file path - spec/demo_scripts/config_spec.rb: Updated test file names - scripts/new-demo.sh: Updated VERSION_FILE path - scripts/scaffold-demo.sh: Updated VERSION_FILE path - bin/new-demo: Updated help text references - README.md: Updated all documentation references - docs/VERSION_MANAGEMENT.md: Updated all documentation references Also fixed encoding issue: - Added UTF-8 encoding specification to File.readlines in config.rb to handle Unicode characters in the config file All tests pass ✓ RuboCop passes ✓ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Changed the gem name to be more specific and avoid conflicts: - demo_common → shakacode-demo-common The name 'demo_common' is too generic and could conflict with other gems. 'shakacode-demo-common' clearly indicates it's from ShakaCode and is for demos. Updated all references: - packages/demo_common/demo_common.gemspec: Changed spec.name - lib/demo_scripts/demo_creator.rb: Updated gem installation code - scripts/new-demo.sh: Updated gem reference - scripts/scaffold-demo.sh: Updated gem reference - scripts/apply-shared.sh: Updated gem reference - packages/demo_common/README.md: Updated all installation examples Note: The module name (DemoCommon) and directory structure remain unchanged, only the published gem name is different. Installation in demos: gem 'shakacode-demo-common', path: '../../packages/demo_common' RuboCop passes ✓ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Rename the entire package to use the full shakacode_demo_common name consistently across the codebase for better clarity and to avoid generic naming conflicts. Changes: - Rename packages/demo_common/ to packages/shakacode_demo_common/ - Update gem name from 'demo_common' to 'shakacode_demo_common' - Update module name from DemoCommon to ShakacodeDemoCommon - Rename all lib/ files and directories to use shakacode_demo_common - Update all require statements and references in Ruby code - Update all bash scripts to reference the new package name - Update documentation (README.md, CONTRIBUTING.md, etc.) - Update rake tasks namespace from :demo_common to :shakacode_demo_common - Update .rubocop.yml to reference new directory and remove unused plugins This ensures the gem name matches the directory name convention where both use underscores (shakacode_demo_common), following Ruby best practices. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Remove backslash escape from $CURRENT_DATE to allow proper variable expansion in generated README files. Without this fix, the literal text "$CURRENT_DATE" would appear instead of the actual date. This brings scaffold-demo.sh in line with new-demo.sh which already uses the correct unescaped syntax. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 58 out of 72 changed files in this pull request and generated 3 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| if line =~ /^SHAKAPACKER_VERSION\s*=\s*["'](.+)["']/ | ||
| @shakapacker_version = ::Regexp.last_match(1) | ||
| elsif line =~ /^REACT_ON_RAILS_VERSION\s*=\s*["'](.+)["']/ | ||
| @react_on_rails_version = ::Regexp.last_match(1) |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The explicit ::Regexp.last_match(1) is unnecessarily verbose. Use $1 or Regexp.last_match(1) for better readability.
| @react_on_rails_version = ::Regexp.last_match(1) | |
| @react_on_rails_version = $1 |
|
|
||
| # Run tests first | ||
| Rake::Task["demo_common:all"].invoke | ||
| Rake::Task['demo_common:all'].invoke |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rake task reference is incorrect. It should be 'shakacode_demo_common:all' to match the namespace defined on line 3.
| Rake::Task['demo_common:all'].invoke | |
| Rake::Task['shakacode_demo_common:all'].invoke |
|
|
||
| puts "\nReinstalling..." | ||
| Rake::Task["demo_common:setup"].invoke | ||
| Rake::Task['demo_common:setup'].invoke |
Copilot
AI
Oct 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rake task reference is incorrect. It should be 'shakacode_demo_common:setup' to match the namespace defined on line 3.
| Rake::Task['demo_common:setup'].invoke | |
| Rake::Task['shakacode_demo_common:setup'].invoke |
Pull Request Review: Monorepo Structure SetupSummaryThis is an excellent foundation for a monorepo structure supporting multiple React on Rails demo applications. The PR demonstrates strong engineering practices with comprehensive tooling, testing, documentation, and automation. The conversion from bash to Ruby scripts with full test coverage is particularly impressive. ✅ StrengthsArchitecture & Design
Code Quality
Documentation
Security
🔍 Areas for Improvement1. Security - Path Traversal Validation (Priority: HIGH)Issue: While the PR description mentions path traversal protection, I do not see explicit validation in the code. Location: Concern: A malicious demo name like Recommendation: Add explicit validation for demo names to prevent path traversal attacks. 2. Code Quality - Logic Bug in PreFlightChecks (Priority: MEDIUM)Issue: Incorrect logic in target directory check at The method returns early if directory exists, but then tries to print success message which is never executed. The logic should check if directory exists first, raise error, then print success message. 3. Testing - Missing Edge Cases (Priority: MEDIUM)Gaps identified:
🎯 Test Coverage AssessmentOverall: Good (estimated 75-80% coverage of critical paths) Well-covered: Config loading, command runner dry-run, pre-flight checks for git state 🔒 Security AssessmentOverall: Good with one critical gap Critical Gap: Missing path traversal validation for demo names 📋 Recommendations SummaryMust Fix (before merge)
Should Fix (can be follow-up PR)
Nice to Have
✨ Final ThoughtsThis is production-ready code with minor issues to address. The thoughtful architecture, comprehensive testing, excellent documentation, and developer-friendly tooling make this an exemplary monorepo setup. Recommendation: ✅ Approve with minor changes Fix the two must-fix items (path validation and logic bug), and this will be an excellent foundation for the React on Rails demos repository. Great work! 🎉 Review conducted using Claude Code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
spec/examples.txt (1)
1-28: Add spec/examples.txt to .gitignore and remove it from version control
This file is auto-generated by RSpec’sconfig.example_status_persistence_file_path = 'spec/examples.txt'(in spec/spec_helper.rb) and will constantly change, leading to merge conflicts if tracked.commit_message.txt (1)
1-57: Don’t track commit_message.txt; remove from repo.This file is already ignored in .gitignore and its content conflicts with the finalized naming used elsewhere. Delete it and keep canonical details in the PR body/CHANGELOG.
-commit_message.txt +# Remove this tracked file from the repo: +# git rm --cached commit_message.txt
♻️ Duplicate comments (12)
lefthook.yml (2)
5-5: Disable parallel execution to prevent git index races.With
parallel: true, bothtrailing-newlineandrubocopcan executegit addconcurrently (line 17 andstage_fixed: trueon line 26), causing intermittent.git/index.lockerrors.Apply this diff:
pre-commit: - parallel: true + parallel: false
10-21: Fix file iteration to handle paths with spaces.The
for file in {staged_files}construct splits on whitespace, so files likedocs/Release Notes.mdare silently skipped. Use a NUL-delimited loop instead.Apply this diff:
- run: | - for file in {staged_files}; do - if [ -f "$file" ]; then - # Check if file ends with newline - if [ -n "$(tail -c 1 "$file")" ]; then - echo "❌ Missing trailing newline: $file" - # Add trailing newline - echo "" >> "$file" - git add "$file" - echo "✅ Added trailing newline to: $file" - fi - fi - done + run: | + git diff --cached --name-only -z -- '*.{rb,js,ts,jsx,tsx,yml,yaml,json,md,sh}' | + while IFS= read -r -d '' file; do + if [ -f "$file" ] && [ -n "$(tail -c 1 "$file")" ]; then + echo "❌ Missing trailing newline: $file" + echo "" >> "$file" + git add "$file" + echo "✅ Added trailing newline to: $file" + fi + donepackages/shakacode_demo_common/lib/tasks/shakacode_demo_common.rake (2)
45-45: Fix task reference to match renamed namespace.Line 45 invokes
demo_common:allbut the namespace was renamed toshakacode_demo_commonon line 3. This will raise a runtime error.Apply this diff:
- Rake::Task['demo_common:all'].invoke + Rake::Task['shakacode_demo_common:all'].invoke
63-63: Fix task reference to match renamed namespace.Line 63 invokes
demo_common:setupbut the namespace was renamed toshakacode_demo_commonon line 3. This will raise a runtime error.Apply this diff:
- Rake::Task['demo_common:setup'].invoke + Rake::Task['shakacode_demo_common:setup'].invokescripts/test-all.sh (1)
4-16: Good: robust shell options and subshell fix.Using set -euo pipefail with pushd/popd addresses prior subshell mutation bug; flow and summary handling look solid.
Also applies to: 35-41, 69-82
bin/new-demo (1)
62-74: CRITICAL: Add demo name validation to prevent path traversal.The script accepts any string from
ARGV[0]as the demo name without validation. This creates a path traversal vulnerability where a malicious or accidental input like../../../etc/passwdcould be passed toDemoCreator, potentially creating files outside the intendeddemos/directory.As noted in the previous review, add validation before line 67:
if ARGV.empty? puts parser exit 1 end + demo_name = ARGV[0] + + # Validate demo name format + unless demo_name.match?(/\A[a-zA-Z0-9_-]+\z/) && demo_name.length <= 100 + warn "Error: Invalid demo name '#{demo_name}'" + warn "Demo name must contain only letters, numbers, hyphens, and underscores (max 100 chars)" + exit 1 + end + - demo_name = ARGV[0] - creator = DemoScripts::DemoCreator.new(This check should happen before any DemoCreator instantiation to prevent path traversal attacks.
.github/workflows/ci.yml (2)
65-70: Don’t mask ESLint/Prettier failures; use --if-present instead of continue-on-error.
Currently failures are ignored and scripts may not exist in the package. Make failures actionable while remaining optional.Apply this diff:
- - name: Run ESLint - run: npm run lint - continue-on-error: true # Allow to continue if lint script doesn't exist + - name: Run ESLint (if present) + run: npm run lint --if-present @@ - - name: Check Prettier formatting - run: npm run format:check - continue-on-error: true # Allow to continue if format script doesn't exist + - name: Check Prettier formatting (if present) + run: npm run format:check --if-present
76-80: Remove empty matrix; it triggers actionlint and adds no value.
You already loop over demos; the matrix is unused and empty.Apply this diff:
- strategy: - matrix: - demo: [] # Will be populated as demos are added - fail-fast: falsescripts/new-demo.sh (1)
83-89: Define color variables before use.
${RED} and ${NC} are used but never defined.Apply this diff near the top (after set -euo pipefail):
set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Colorpackages/shakacode_demo_common/package.json (1)
1-45: Add scripts used by CI (lint, format:check).
Workflow runs npm run lint/format:check; scripts are missing.{ "name": "@shakacode/react-on-rails-demo-common", "version": "0.1.0", "description": "Common JavaScript/TypeScript configurations for React on Rails demos", "main": "index.js", + "scripts": { + "lint": "eslint --max-warnings=0 .", + "format": "prettier --write .", + "format:check": "prettier --check ." + },scripts/scaffold-demo.sh (1)
69-74: Validation still allows leading hyphens.The regex
^[a-zA-Z0-9_-]+$permits names starting with-, causingcd "$DEMO_DIR"to fail (the hyphen is interpreted as an option). The past review flagged this, but the fix wasn't applied.Apply this diff:
-if [[ -z "$DEMO_NAME" ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then +if [[ -z "$DEMO_NAME" ]] || [[ "$DEMO_NAME" =~ ^- ]] || [[ ! "$DEMO_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then echo -e "${RED}Error: Invalid demo name '$DEMO_NAME'${NC}" echo "Demo name must contain only letters, numbers, hyphens, and underscores" exit 1 fipackages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/install_generator.rb (1)
55-73: Add error handling for JSON parsing and consider merge behavior.Two concerns remain from previous reviews:
JSON.parse(line 61) will raise an exception if package.json is malformed, halting the generator.merge!(line 64) overwrites existing scripts with the same keys. Consider usingreverse_merge!or checking for existing keys to preserve user customizations.Apply this diff:
def add_npm_scripts say 'Adding npm scripts' package_json_path = Rails.root.join('package.json') return unless File.exist?(package_json_path) + begin package_json = JSON.parse(File.read(package_json_path)) + rescue JSON::ParserError => e + say "Failed to parse package.json: #{e.message}", :red + return + end package_json['scripts'] ||= {} - package_json['scripts'].merge!({ + # Preserve existing scripts by only adding keys that don't exist + new_scripts = { 'lint' => 'eslint . --ext .js,.jsx,.ts,.tsx', 'lint:fix' => 'eslint . --ext .js,.jsx,.ts,.tsx --fix', 'format' => "prettier --write '**/*.{js,jsx,ts,tsx,json,css,scss,md}'", 'format:check' => "prettier --check '**/*.{js,jsx,ts,tsx,json,css,scss,md}'", 'prepare' => 'lefthook install' - }) + } + package_json['scripts'].reverse_merge!(new_scripts) File.write(package_json_path, JSON.pretty_generate(package_json)) end
🧹 Nitpick comments (21)
packages/shakacode_demo_common/shakacode_demo_common.gemspec (2)
6-13: Add helpful gem metadata URIs.Improve discoverability on RubyGems by adding source, docs, and changelog links.
spec.homepage = 'https://github.com/shakacode/react_on_rails-demos' + spec.metadata['source_code_uri'] = 'https://github.com/shakacode/react_on_rails-demos' + spec.metadata['changelog_uri'] = 'https://github.com/shakacode/react_on_rails-demos/blob/main/CHANGELOG.md' + spec.metadata['documentation_uri']= 'https://github.com/shakacode/react_on_rails-demos/tree/main/packages/shakacode_demo_common'
25-27: Ensure a license file is present
Add aLICENSE(or rename yourMIT-LICENSE) inpackages/shakacode_demo_commonand update the gemspec paths if necessary.scripts/test-all.sh (3)
48-60: Tighten Rails detection and guard RuboCop.Use executable check for Rails and only run RuboCop when a Gemfile exists to avoid false failures in non-Rails demos.
- if [ -f "bin/rails" ]; then + if [ -x "bin/rails" ]; then if [ -d "spec" ]; then echo " Running RSpec tests..." bundle exec rspec || FAILED_DEMOS="$FAILED_DEMOS $demo_name" elif [ -d "test" ]; then echo " Running Rails tests..." bin/rails test || FAILED_DEMOS="$FAILED_DEMOS $demo_name" fi - # Run RuboCop - echo " Running RuboCop..." - bundle exec rubocop || FAILED_DEMOS="$FAILED_DEMOS $demo_name-rubocop" + # Run RuboCop + if [ -f "Gemfile" ]; then + echo " Running RuboCop..." + bundle exec rubocop || FAILED_DEMOS="$FAILED_DEMOS $demo_name-rubocop" + fi fi
39-45: Handle demo paths with spaces (optional).Current glob can split on spaces. Consider a nullglob + loop or find -print0 for robustness.
-if [ -d "demos" ] && [ "$(ls -A demos 2>/dev/null)" ]; then - for demo in demos/*; do +shopt -s nullglob +if [ -d "demos" ] && compgen -G "demos/*" >/dev/null; then + for demo in demos/*; do if [ -d "$demo" ]; then
29-33: Detect pnpm when present (keeps PR’s “npm/pnpm support” promise).Prefer pnpm if pnpm-lock.yaml exists; fall back to npm.
- echo " Running JavaScript tests..." - if ! npm test; then + PM="npm"; [ -f "pnpm-lock.yaml" ] && PM="pnpm" + echo " Running JavaScript tests with $PM..." + if ! $PM test; then FAILED_DEMOS="$FAILED_DEMOS shakacode_demo_common-js" fi - if ! npm run lint; then + if ! $PM run lint; then FAILED_DEMOS="$FAILED_DEMOS shakacode_demo_common-eslint" fi- echo " Running JavaScript tests..." - if ! npm test; then + PM="npm"; [ -f "pnpm-lock.yaml" ] && PM="pnpm" + echo " Running JavaScript tests with $PM..." + if ! $PM test; then FAILED_DEMOS="$FAILED_DEMOS ${demo_name}-js" fi - if ! npm run lint; then + if ! $PM run lint; then FAILED_DEMOS="$FAILED_DEMOS ${demo_name}-eslint" fiAlso applies to: 64-67
package.json (1)
6-12: Prettier setup looks fine; consider minor hardening.Optional:
- Add a .prettierignore for build/coverage/tmp to avoid accidental walks.
- Consider bumping Prettier to latest 3.x and adding an engines.node constraint for consistency across contributors.
pr_description.md (1)
209-214: Remove AI tool attribution lines from PR description.Keep PR text vendor-neutral and focused on changes.
-🤖 Generated with [Claude Code](https://claude.com/claude-code) - -Co-Authored-By: Claude <[email protected]>.new-demo-versions (1)
10-13: Consider documenting the version constraint format.The pessimistic version constraints (
~> 8.0,~> 16.0) are standard Ruby gem syntax, but the file format mixing shell-style comments with gem version syntax may be confusing. Consider adding a note explaining that these follow Ruby gem version constraint conventions if they're consumed by Ruby code, or converting to a format more appropriate for the actual consumer (e.g., YAML, JSON, or pure shell variables).bin/update-all-demos (2)
60-64: Consider validating that at least one version is specified.The script allows execution without specifying
--react-on-rails-versionor--shakapacker-version, which would result in no updates being performed. Consider adding a check to ensure at least one version option is provided before instantiating the updater, or document this as expected behavior if DemoUpdater handles it gracefully.begin parser.parse! + + if options[:react_on_rails_version].nil? && options[:shakapacker_version].nil? + warn "Error: At least one of --react-on-rails-version or --shakapacker-version must be specified" + puts parser + exit 1 + end updater = DemoScripts::DemoUpdater.new(**options) updater.update!
44-46: Document glob pattern constraints for the --demos option.The
--demosoption accepts an arbitrary glob pattern without validation. While glob patterns are powerful, consider adding a usage note in the help text about expected patterns (e.g.,'*typescript*','demo-v16-*') to guide users and prevent confusion with unexpected pattern matching behavior.- opts.on('--demos PATTERN', 'Only update demos matching pattern (glob)') do |pattern| + opts.on('--demos PATTERN', 'Only update demos matching pattern (glob, e.g., "*typescript*")') do |pattern| options[:demo_pattern] = pattern endbin/scaffold-demo (1)
70-76: Consider alternative parsing for arguments containing commas.The
--rails-argsand--react-on-rails-argsoptions split on commas (lines 71, 75), which will break if any argument value contains a comma. Consider using a different delimiter (e.g., space or semicolon) or accepting multiple instances of the flag instead.- opts.on('--rails-args ARGS', 'Additional arguments to pass to rails new (comma-separated)') do |args| - options[:rails_args] = args.split(',').map(&:strip) + opts.on('--rails-args ARGS', 'Additional arguments to pass to rails new (space-separated, quoted if needed)') do |args| + options[:rails_args] = args.split(/\s+/) end - opts.on('--react-on-rails-args ARGS', 'Additional arguments to pass to react_on_rails:install (comma-separated)') do |args| - options[:react_on_rails_args] = args.split(',').map(&:strip) + opts.on('--react-on-rails-args ARGS', 'Additional arguments to pass to react_on_rails:install (space-separated, quoted if needed)') do |args| + options[:react_on_rails_args] = args.split(/\s+/) endAlternatively, allow multiple flag instances:
+ options[:rails_args] = [] + options[:react_on_rails_args] = [] + - opts.on('--rails-args ARGS', 'Additional arguments to pass to rails new (comma-separated)') do |args| - options[:rails_args] = args.split(',').map(&:strip) + opts.on('--rails-args ARG', 'Additional argument to pass to rails new (can be specified multiple times)') do |arg| + options[:rails_args] << arg end - opts.on('--react-on-rails-args ARGS', 'Additional arguments to pass to react_on_rails:install (comma-separated)') do |args| - options[:react_on_rails_args] = args.split(',').map(&:strip) + opts.on('--react-on-rails-args ARG', 'Additional argument to pass to react_on_rails:install (can be specified multiple times)') do |arg| + options[:react_on_rails_args] << arg endscripts/apply-shared.sh (1)
36-44: Improve Gemfile modification robustness.Two concerns:
- Line 38:
grep -q "shakacode_demo_common"matches any occurrence, including comments or strings. This could skip adding the gem if it appears in a comment.- Lines 40-42: Appending without ensuring the file ends with a newline could cause formatting issues.
Apply this diff to make the check more precise and ensure proper formatting:
- if ! grep -q "shakacode_demo_common" "$demo/Gemfile"; then + if ! grep -q "^[[:space:]]*gem[[:space:]]*[\"']shakacode_demo_common[\"']" "$demo/Gemfile"; then echo " Adding shakacode_demo_common to Gemfile..." - echo '' >> "$demo/Gemfile" + # Ensure file ends with newline before appending + [ -n "$(tail -c1 "$demo/Gemfile")" ] && echo '' >> "$demo/Gemfile" + echo '' >> "$demo/Gemfile" echo '# Shared demo configuration and utilities' >> "$demo/Gemfile"scripts/new-demo.sh (3)
96-105: Avoid eval in run_cmd; preserve quoting safely.
eval is error‑prone for spaces/special chars. Use bash -lc and show colored prefixes.-run_cmd() { - if [ "$DRY_RUN" = true ]; then - echo "[DRY-RUN] $*" - else - echo "▶ $*" - eval "$@" - fi -} +run_cmd() { + if [ "$DRY_RUN" = true ]; then + echo -e "${YELLOW}[DRY-RUN]${NC} $*" + else + echo -e "${GREEN}▶${NC} $*" + bash -lc "$*" + fi +}Based on learnings (consistency with scaffold-demo.sh run_cmd).
116-135: Check “in git repo” before running git diff-index.
Current order can emit misleading errors if not in a repo (stderr hidden). Swap checks.-# Check 1: No uncommitted changes (staged or unstaged) -if ! git diff-index --quiet HEAD -- 2>/dev/null; then - echo "❌ Error: Repository has uncommitted changes" - ... - exit 1 -fi -echo "✓ No uncommitted changes" - -# Check if we're in a git repository -if ! git rev-parse --git-dir > /dev/null 2>&1; then - echo "❌ Error: Not in a git repository" - exit 1 -fi -echo "✓ In git repository" +# Check if we're in a git repository +if ! git rev-parse --git-dir > /dev/null 2>&1; then + echo "❌ Error: Not in a git repository" + exit 1 +fi +echo "✓ In git repository" + +# Check 1: No uncommitted changes (staged or unstaged) +if ! git diff-index --quiet HEAD --; then + echo "❌ Error: Repository has uncommitted changes" + ... + exit 1 +fi +echo "✓ No uncommitted changes"
203-209: Prefer reproducible JS installs.
Use pnpm if present; otherwise npm ci when lockfile exists, else npm install.-if command -v pnpm &> /dev/null; then - run_cmd "cd '$DEMO_DIR' && pnpm install" -else - run_cmd "cd '$DEMO_DIR' && npm install" -fi +if command -v pnpm >/dev/null 2>&1; then + run_cmd "cd '$DEMO_DIR' && pnpm install" +else + if [ -f "$DEMO_DIR/package-lock.json" ]; then + run_cmd "cd '$DEMO_DIR' && npm ci" + else + run_cmd "cd '$DEMO_DIR' && npm install" + fi +fipackages/shakacode_demo_common/package.json (3)
21-25: Ensure first-time publish works for scoped package.
Add publishConfig access: public; otherwise npm publish may fail."files": [ "configs/", "playwright/", "index.js" ], + "publishConfig": { + "access": "public" + },
37-44: Mark playwright peer as optional (avoid install warnings).
Many consumers won’t use Playwright directly."peerDependencies": { "playwright": "^1.35.0" }, + "peerDependenciesMeta": { + "playwright": { + "optional": true + } + },
6-9: Repository metadata should point to monorepo and package directory.
Set repository.url to the monorepo and add directory for clarity on npm."repository": { "type": "git", - "url": "https://github.com/shakacode/react-on-rails-demo-common.git" + "url": "https://github.com/shakacode/react_on_rails-demos.git", + "directory": "packages/shakacode_demo_common" },packages/shakacode_demo_common/Rakefile (1)
95-101: Make npm publish explicit for scoped public package.
Align with package.json publishConfig and avoid interactive failure.- sh 'npm publish' + sh 'npm publish --access public'lib/demo_scripts/demo_creator.rb (1)
57-73: Consider path safety in shell command construction.Line 72 uses single quotes around
@demo_dirin the shell command. While demo names are validated to contain only safe characters, consider usingShellwords.escapefor extra safety if validation ever changes.Optional refactor:
require 'shellwords' def create_rails_app puts '📦 Creating Rails application...' base_args = [ '--database=postgresql', '--skip-javascript', '--skip-hotwire', '--skip-action-mailbox', '--skip-action-text', '--skip-active-storage', '--skip-action-cable', '--skip-sprockets', '--skip-system-test', '--skip-turbolinks' ] all_args = (base_args + @rails_args).join(' ') @runner.run!("rails new #{Shellwords.escape(@demo_dir)} #{all_args}") endpackages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/install_generator.rb (1)
17-22: Consider adding error handling for npm install commands.Each public method in a generator is executed sequentially, but the
runmethod for npm install commands (lines 14, 20-21) doesn't check exit status. If npm install fails (network issues, permission problems, etc.), the generator continues silently, potentially leaving the project in a broken state.Consider checking command success:
def copy_lefthook_config say 'Installing Lefthook configuration' copy_file lefthook_config_path, 'lefthook.yml' unless run 'npm install --save-dev lefthook @commitlint/cli @commitlint/config-conventional' say 'Warning: npm install failed for Lefthook dependencies', :yellow end unless run 'npx lefthook install' say 'Warning: Lefthook installation failed', :yellow end end
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
-
package-lock.jsonis excluded by!**/package-lock.json -
packages/shakacode_demo_common/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (46)
-
.github/workflows/ci.yml(1 hunks) -
.gitignore(1 hunks) -
.new-demo-versions(1 hunks) -
.prettierignore(1 hunks) -
.prettierrc(1 hunks) -
.rubocop.yml(1 hunks) -
CONTRIBUTING.md(1 hunks) -
README.md(1 hunks) -
bin/new-demo(1 hunks) -
bin/scaffold-demo(1 hunks) -
bin/update-all-demos(1 hunks) -
commit_message.txt(1 hunks) -
docs/CONTRIBUTING_SETUP.md(1 hunks) -
docs/VERSION_MANAGEMENT.md(1 hunks) -
lefthook.yml(1 hunks) -
lib/demo_scripts/config.rb(1 hunks) -
lib/demo_scripts/demo_creator.rb(1 hunks) -
package.json(1 hunks) -
packages/shakacode_demo_common/.gitignore(1 hunks) -
packages/shakacode_demo_common/Gemfile(1 hunks) -
packages/shakacode_demo_common/README.md(1 hunks) -
packages/shakacode_demo_common/RELEASING.md(2 hunks) -
packages/shakacode_demo_common/Rakefile(1 hunks) -
packages/shakacode_demo_common/config/lefthook.yml(2 hunks) -
packages/shakacode_demo_common/config/rubocop.yml(3 hunks) -
packages/shakacode_demo_common/configs/eslint.config.js(1 hunks) -
packages/shakacode_demo_common/configs/prettier.config.js(1 hunks) -
packages/shakacode_demo_common/index.js(1 hunks) -
packages/shakacode_demo_common/lefthook.yml(1 hunks) -
packages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/install_generator.rb(1 hunks) -
packages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/templates/github_workflow.yml(2 hunks) -
packages/shakacode_demo_common/lib/shakacode_demo_common.rb(1 hunks) -
packages/shakacode_demo_common/lib/shakacode_demo_common/railtie.rb(1 hunks) -
packages/shakacode_demo_common/lib/shakacode_demo_common/version.rb(1 hunks) -
packages/shakacode_demo_common/lib/tasks/shakacode_demo_common.rake(2 hunks) -
packages/shakacode_demo_common/package.json(1 hunks) -
packages/shakacode_demo_common/playwright/helpers.js(1 hunks) -
packages/shakacode_demo_common/shakacode_demo_common.gemspec(1 hunks) -
pr_description.md(1 hunks) -
scripts/apply-shared.sh(1 hunks) -
scripts/bootstrap-all.sh(1 hunks) -
scripts/new-demo.sh(1 hunks) -
scripts/scaffold-demo.sh(1 hunks) -
scripts/test-all.sh(1 hunks) -
spec/demo_scripts/config_spec.rb(1 hunks) -
spec/examples.txt(1 hunks)
✅ Files skipped from review due to trivial changes (13)
- packages/shakacode_demo_common/configs/prettier.config.js
- packages/shakacode_demo_common/.gitignore
- docs/CONTRIBUTING_SETUP.md
- packages/shakacode_demo_common/RELEASING.md
- .prettierignore
- packages/shakacode_demo_common/Gemfile
- packages/shakacode_demo_common/playwright/helpers.js
- packages/shakacode_demo_common/lefthook.yml
- packages/shakacode_demo_common/index.js
- .prettierrc
- packages/shakacode_demo_common/config/lefthook.yml
- packages/shakacode_demo_common/configs/eslint.config.js
- packages/shakacode_demo_common/README.md
🚧 Files skipped from review as they are similar to previous changes (4)
- lib/demo_scripts/config.rb
- .rubocop.yml
- spec/demo_scripts/config_spec.rb
- scripts/bootstrap-all.sh
🧰 Additional context used
🧬 Code graph analysis (4)
scripts/scaffold-demo.sh (2)
scripts/new-demo.sh (2)
show_usage(26-41)run_cmd(97-104)scripts/update-all-demos.sh (2)
show_usage(12-31)run_cmd(80-86)
scripts/new-demo.sh (2)
scripts/scaffold-demo.sh (2)
show_usage(26-47)run_cmd(133-140)scripts/update-all-demos.sh (2)
show_usage(12-31)run_cmd(80-86)
lib/demo_scripts/demo_creator.rb (4)
lib/demo_scripts/config.rb (1)
initialize(11-17)lib/demo_scripts/command_runner.rb (2)
initialize(8-11)run!(26-31)lib/demo_scripts/pre_flight_checks.rb (3)
initialize(5-54)initialize(6-9)run!(11-19)lib/demo_scripts/demo_scaffolder.rb (5)
initialize(5-354)initialize(6-37)create!(39-67)setup_database(71-77)print_completion_message(332-353)
packages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/install_generator.rb (1)
packages/shakacode_demo_common/lib/shakacode_demo_common.rb (2)
root(10-12)config_path(14-16)
🪛 actionlint (1.7.7)
.github/workflows/ci.yml
78-78: "matrix values" section should not be empty
(syntax-check)
🪛 Shellcheck (0.11.0)
scripts/scaffold-demo.sh
[warning] 138-138: eval negates the benefit of arrays. Drop eval to preserve whitespace/symbols (or eval as string).
(SC2294)
scripts/new-demo.sh
[warning] 102-102: eval negates the benefit of arrays. Drop eval to preserve whitespace/symbols (or eval as string).
(SC2294)
⏰ 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). (1)
- GitHub Check: claude-review
🔇 Additional comments (34)
packages/shakacode_demo_common/shakacode_demo_common.gemspec (2)
15-17: Retain current spec.files glob
The existing pattern packages onlylib/**/*,Rakefile, andREADME.md; no extraneous files are included, and switching togit ls-fileswould pull in dotfiles and other tracked files you likely don’t want in the gem.Likely an incorrect or invalid review comment.
3-3: Verified version file and constant presence. Theversion.rbexists and definesShakacodeDemoCommon::VERSION.packages/shakacode_demo_common/lib/shakacode_demo_common/version.rb (1)
1-5: LGTM!The version file follows Ruby gem conventions correctly with frozen string literal, proper module nesting, and semantic versioning for the initial release.
lefthook.yml (1)
28-36: LGTM!The commit-msg validation correctly checks for non-empty commit messages using a robust regex pattern.
packages/shakacode_demo_common/lib/tasks/shakacode_demo_common.rake (2)
3-3: LGTM!The namespace rename from
demo_commontoshakacode_demo_commonaligns with the broader gem/module renaming in this PR.
6-19: LGTM!The quote style changes from double to single quotes are consistent and the task logic remains correct.
CONTRIBUTING.md (5)
1-17: LGTM!Clear and welcoming introduction with a structured getting-started workflow.
18-36: LGTM!Prerequisites are well-defined and the setup instructions correctly reference the new
bootstrap-all.shscript introduced in this PR.
49-61: LGTM!The documentation correctly references the new Ruby-based demo creation scripts (
bin/new-demo,bin/scaffold-demo) and appropriately recommends them as "fully tested and recommended."
96-112: LGTM!Clear commit message guidelines with helpful examples following conventional commit format.
130-143: LGTM!Excellent demo standards checklist that establishes clear quality expectations for contributors.
packages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/templates/github_workflow.yml (1)
5-7: LGTM: YAML formatting normalized.The array formatting changes (removing spaces inside brackets) standardize the YAML style consistently with the monorepo's conventions.
packages/shakacode_demo_common/config/rubocop.yml (1)
12-18: LGTM: Quote style normalized.The switch from double to single quotes in Exclude lists is a pure formatting change with no functional impact.
Also applies to: 49-49, 53-56, 75-75
bin/update-all-demos (1)
65-72: LGTM: Error handling is appropriate.The script properly handles both domain errors (DemoScripts::Error) and parsing errors (OptionParser::InvalidOption) with clear messages and appropriate exit codes.
bin/scaffold-demo (1)
105-112: LGTM: Error handling follows established pattern.The error handling is consistent with bin/update-all-demos and properly handles both domain errors and parsing errors with clear messages and appropriate exit codes.
.new-demo-versions (1)
1-32: .new-demo-versions is sourced by bash scripts and parsed by Ruby code
Both scripts/new-demo.sh and scripts/scaffold-demo.sh usesource "$VERSION_FILE"to load defaults, and DemoScripts::Config in lib/demo_scripts/config.rb reads and parses the same file. No changes required.scripts/apply-shared.sh (1)
1-11: LGTM!Good use of strict error handling with
set -euo pipefailand clear validation of required directories.packages/shakacode_demo_common/lib/shakacode_demo_common/railtie.rb (2)
1-4: LGTM!Standard Railtie setup with proper frozen string literal pragma.
7-13: Paths for rake task and generator are correct.packages/shakacode_demo_common/lib/shakacode_demo_common.rb (2)
1-7: LGTM!Good practice to conditionally load Rails-specific code and define a custom error class for the gem.
9-22: LGTM!The path calculations correctly resolve to the gem root and expected subdirectories. The module singleton methods provide clean access to key gem paths.
docs/VERSION_MANAGEMENT.md (1)
1-528: Documentation is comprehensive and addresses past review feedback.The version management workflow is well-documented with clear examples, troubleshooting guidance, and best practices. Past review comments appear to have been addressed:
- Line 5 includes the cypress-playwright-on-rails reference
- Line 47 recommends Ruby scripts in bin/
- Lines 99-105 document Gemfile.development_dependencies inheritance
- Line 84 acknowledges git branch support as a future enhancement
bin/new-demo (3)
1-14: LGTM!Clean setup with proper requires and options initialization.
16-57: LGTM!Well-structured option parser with clear help text and good handling of comma-separated arguments.
75-82: LGTM!Appropriate error handling with clear user feedback and proper exit codes.
packages/shakacode_demo_common/package.json (1)
5-5: Entry point verified
packages/shakacode_demo_common/index.jsexists, so themainfield in package.json is correct.scripts/scaffold-demo.sh (3)
133-140:evalusage is acceptable here despite shellcheck warning.Shellcheck warns that
evalnegates array benefits (SC2294). In this context,eval "$@"is needed to handle complex commands with pipes, redirects, and compound statements thatrun_cmdreceives. The pattern is safe because all input is controlled by the script itself, not user input.
26-47: LGTM! Clear and helpful usage documentation.The usage function provides comprehensive help with practical examples and follows the same pattern as other scripts in the repo.
377-477: README generation is correct.The date variable expansion and heredoc syntax are correct. The past comment about escaping issues appears to be a false positive—
EOF(unquoted) allows variable expansion, and$CURRENT_DATEwill expand properly at line 393.lib/demo_scripts/demo_creator.rb (3)
6-26: LGTM! Clean initialization with proper dependency injection.The initializer properly sets up all dependencies (Config, CommandRunner) and instance variables with sensible defaults.
28-49: LGTM! Clear orchestration of demo creation steps.The
create!method follows a logical sequence of steps and properly handles pre-flight checks and dry-run mode.
150-200: LGTM! Well-structured README template.The generated README includes all essential information: gem versions, setup instructions, and helpful links. The interpolation of config values and current date is handled correctly.
packages/shakacode_demo_common/lib/generators/shakacode_demo_common/install/install_generator.rb (1)
107-119: LGTM! Helpful post-install guidance.The completion message provides clear next steps and customization guidance for users.
README.md (1)
1-206: All referenced documentation files exist. Verified that every file cited in the README is present—no updates required.
| working-directory: packages/demo_common | ||
| steps: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix paths to renamed package directory (breaking).
Jobs still use packages/demo_common. The repo renamed to packages/shakacode_demo_common, so steps will run in a non-existent path and fail.
Apply this diff:
- working-directory: packages/demo_common
+ working-directory: packages/shakacode_demo_common
@@
- working-directory: packages/demo_common
+ working-directory: packages/shakacode_demo_common
@@
- working-directory: packages/demo_common
+ working-directory: packages/shakacode_demo_common
@@
- working-directory: packages/demo_common
+ working-directory: packages/shakacode_demo_common
@@
- cache-dependency-path: packages/demo_common/package-lock.json
+ cache-dependency-path: packages/shakacode_demo_common/package-lock.json
@@
- working-directory: packages/demo_common
+ working-directory: packages/shakacode_demo_common
@@
- cache-dependency-path: packages/demo_common/package-lock.json
+ cache-dependency-path: packages/shakacode_demo_common/package-lock.jsonAlso applies to: 22-22, 30-31, 38-38, 44-45, 54-55, 62-62
🤖 Prompt for AI Agents
.github/workflows/ci.yml around lines 14-15 (and also at 22, 30-31, 38, 44-45,
54-55, 62): CI steps reference the old package path packages/demo_common which
no longer exists; update every occurrence of packages/demo_common in this
workflow to the new directory name packages/shakacode_demo_common so all
working-directory and path entries point to the renamed package; ensure no
remaining references to the old name remain in the listed line ranges.
| # Ignore master key for decrypting credentials and more | ||
| /demos/*/config/master.key | ||
| /demos/*/config/credentials.yml.encpr_description.md | ||
| commit_message.txt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix malformed ignore entry; potential secret handling confusion.
/demos/*/config/credentials.yml.encpr_description.md is a concatenation typo. It won’t ignore credentials.yml.enc and accidentally references pr_description.md.
-/demos/*/config/credentials.yml.encpr_description.md
+/demos/*/config/credentials.yml.enc
+# keep PR docs tracked
+# pr_description.md should not be ignored here📝 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.
| # Ignore master key for decrypting credentials and more | |
| /demos/*/config/master.key | |
| /demos/*/config/credentials.yml.encpr_description.md | |
| commit_message.txt | |
| # Ignore master key for decrypting credentials and more | |
| /demos/*/config/master.key | |
| /demos/*/config/credentials.yml.enc | |
| # keep PR docs tracked | |
| # pr_description.md should not be ignored here | |
| commit_message.txt |
🤖 Prompt for AI Agents
In .gitignore around lines 52 to 55, the line
"/demos/*/config/credentials.yml.encpr_description.md" is a concatenation typo
that prevents credentials.yml.enc from being ignored and accidentally references
pr_description.md; fix it by replacing that single malformed entry with the
correct ignore entry "/demos/*/config/credentials.yml.enc" and remove the
accidental "pr_description.md" fragment (or add "pr_description.md" as a
separate ignore line only if you actually intend to ignore that file).
| if ARGV.empty? | ||
| puts parser | ||
| exit 1 | ||
| end | ||
|
|
||
| demo_name = ARGV[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify demo name validation in DemoScaffolder.
The script extracts demo_name directly from ARGV[0] without validation. The PR objectives mention "input validation to prevent path traversal in demo creation" as a security fix. Ensure that DemoScripts::DemoScaffolder validates the demo_name to reject path separators, special characters, or patterns that could lead to path traversal vulnerabilities.
Run the following script to verify the validation logic:
🏁 Script executed:
#!/bin/bash
# Check if DemoScaffolder or related modules validate demo_name
echo "=== Checking demo_name validation in DemoScaffolder ==="
ast-grep --pattern $'class DemoScaffolder
$$$
def initialize($$$)
$$$
end
$$$
end' | head -50
echo "=== Checking for path traversal validation ==="
rg -n 'demo_name.*\.\.|demo_name.*/' lib/demo_scripts/ -A3 -B3
echo "=== Checking validation methods ==="
rg -n 'def validate.*name|valid.*name|sanitize.*name' lib/demo_scripts/ -A5Length of output: 612
🏁 Script executed:
#!/bin/bash
echo "=== Locate DemoScaffolder class file ==="
rg -n 'class DemoScaffolder' -C2 -g '*.rb'
demo_file=$(rg -l 'class DemoScaffolder' -g '*.rb')
echo "Found: $demo_file"
echo "=== Inspect initialize method ==="
if [[ -f "$demo_file" ]]; then
awk '/class DemoScaffolder/,/end/' "$demo_file" | sed -n '/def initialize/,/end/p'
else
echo "DemoScaffolder file not found"
fiLength of output: 1296
Enforce demo_name validation in DemoScaffolder
In lib/demo_scripts/demo_scaffolder.rb within initialize, validate demo_name before calling super(…) to reject any ../, path separators (/ or \), or disallowed characters (e.g. only allow /\A[\w-]+\z/). Raise an error or exit with a clear message on invalid input to prevent path traversal.
🤖 Prompt for AI Agents
In bin/scaffold-demo around lines 92 to 97, the CLI accepts ARGV[0] without
enforcing a safe demo_name; update lib/demo_scripts/demo_scaffolder.rb's
initialize to validate demo_name before calling super(...) by rejecting any path
traversal or separators (../, '/' or '\') and allow only a safe pattern such as
/\A[\w-]+\z/; if validation fails, raise a descriptive error or exit with a
clear message and non-zero status so invalid input is rejected early and no
unsafe filesystem paths are used.
| grep -l "prerender: true" demos/*/app/views/**/*.erb | \ | ||
| xargs dirname | xargs dirname | xargs dirname | \ | ||
| while read demo; do | ||
| ( | ||
| cd "$demo" | ||
| bundle add react_on_rails --version '~> 16.1' | ||
| ) | ||
| done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix bash glob pattern for recursive file matching.
Line 324 uses demos/*/app/views/**/*.erb which requires bash's globstar option to work recursively. Without it, ** is treated as a literal.
Apply this diff to fix the example:
-grep -l "prerender: true" demos/*/app/views/**/*.erb | \
+# Enable globstar for recursive matching
+shopt -s globstar
+grep -l "prerender: true" demos/*/app/views/**/*.erb | \
xargs dirname | xargs dirname | xargs dirname | \
while read demo; doOr use find which doesn't require globstar:
-grep -l "prerender: true" demos/*/app/views/**/*.erb | \
- xargs dirname | xargs dirname | xargs dirname | \
- while read demo; do
+find demos/*/app/views -name "*.erb" -exec grep -l "prerender: true" {} + | \
+ while read file; do
+ demo=$(echo "$file" | cut -d/ -f1-2)🤖 Prompt for AI Agents
In docs/VERSION_MANAGEMENT.md around lines 324 to 331, the shell example uses
the glob pattern demos/*/app/views/**/*.erb which requires bash's globstar to be
enabled or will not match recursively; fix by either enabling globstar before
the loop (add shopt -s globstar) so ** works as intended, or replace the glob
usage with a find-based command that searches recursively (e.g., use find demos
-path '*/app/views/*.erb' or similar) and pipe results through the same
dirname/xargs workflow; update the example to use one of these two approaches
and ensure portability by documenting the chosen option.
| rubocop: | ||
| glob: '*.rb' | ||
| run: bundle exec rubocop --force-exclusion {staged_files} | ||
| stage_fixed: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RuboCop command also vulnerable to filename whitespace issues.
Line 25 uses {staged_files} without quoting, which will break if any Ruby file path contains spaces. Although less common in Ruby projects, this should be quoted for robustness.
Apply this diff:
- run: bundle exec rubocop --force-exclusion {staged_files}
+ run: bundle exec rubocop --force-exclusion -- {staged_files}Note: Lefthook expands {staged_files} as space-separated arguments. The -- delimiter helps, but the underlying issue remains. Consider using the files command instead:
rubocop:
glob: '*.rb'
- run: bundle exec rubocop --force-exclusion {staged_files}
+ run: bundle exec rubocop --force-exclusion {files}
stage_fixed: true📝 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.
| rubocop: | |
| glob: '*.rb' | |
| run: bundle exec rubocop --force-exclusion {staged_files} | |
| stage_fixed: true | |
| rubocop: | |
| glob: '*.rb' | |
| run: bundle exec rubocop --force-exclusion -- {staged_files} | |
| stage_fixed: true |
🤖 Prompt for AI Agents
In lefthook.yml around lines 23 to 26, the rubocop run command uses
{staged_files} unquoted which breaks on paths with spaces; update the hook so
staged filenames are passed safely — either add the POSIX argument separator and
quote the expansion (e.g., include -- before and quote {staged_files}) or,
preferably, switch to Lefthook's files mechanism so each filename is passed
separately to RuboCop (replace the run line with a files-based invocation that
calls rubocop per file or uses Lefthook's files expansion).
| if [ -f "packages/shakacode_demo_common/config/.rubocop.yml" ]; then | ||
| echo " Linking .rubocop.yml..." | ||
| ln -sf ../../packages/shakacode_demo_common/config/.rubocop.yml "$demo/.rubocop.yml" | ||
| fi | ||
|
|
||
| if [ -f "packages/shakacode_demo_common/config/.eslintrc.js" ]; then | ||
| echo " Linking .eslintrc.js..." | ||
| ln -sf ../../packages/shakacode_demo_common/config/.eslintrc.js "$demo/.eslintrc.js" | ||
| fi | ||
|
|
||
| if [ -f "packages/shakacode_demo_common/config/.prettierrc" ]; then | ||
| echo " Linking .prettierrc..." | ||
| ln -sf ../../packages/shakacode_demo_common/config/.prettierrc "$demo/.prettierrc" | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Verify script execution context and symlink target paths.
The symlink paths (../../packages/shakacode_demo_common/config/...) assume the script is executed from the repository root. If run from a different directory, the symlinks will point to incorrect locations.
Consider either:
- Adding a check at the top to ensure the script runs from the repo root
- Computing the symlink paths dynamically based on the script's location
🏁 Script executed:
#!/bin/bash
# Verify the script execution assumption
# Check if the script is typically run from repo root
rg -n "scripts/apply-shared.sh" -g "*.md" -g "*.sh" -C 2Length of output: 0
🏁 Script executed:
#!/bin/bash
# Inspect the header of apply-shared.sh for working-directory checks
sed -n '1,50p' scripts/apply-shared.shLength of output: 1791
Resolve script paths to repository root before linking.
At the top of scripts/apply-shared.sh, compute the script’s directory and cd into the repo root (e.g.
script_dir=$(cd "$(dirname "$0")" && pwd)
cd "$script_dir/..") so that all ln -sf ../../packages/... calls reliably point to the correct targets.
🤖 Prompt for AI Agents
In scripts/apply-shared.sh around lines 21 to 34, the relative ln -sf calls
assume the current working directory is the repo root which can break when the
script is invoked from elsewhere; at the top of the script (before any linking)
determine the script directory and change into the repo root (script_dir=$(cd
"$(dirname "$0")" && pwd) then cd "$script_dir/..") so that subsequent ln -sf
../../packages/... calls resolve correctly; add this CD step immediately after
the shebang and any set -e/-u lines.
| echo "🔗 Creating configuration symlinks..." | ||
| run_cmd "cd '$DEMO_DIR' && ln -sf ../../packages/shakacode_demo_common/config/.rubocop.yml .rubocop.yml" | ||
| run_cmd "cd '$DEMO_DIR' && ln -sf ../../packages/shakacode_demo_common/config/.eslintrc.js .eslintrc.js" | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify symlink targets exist (config vs configs).
Targets use config/.eslintrc.js and .rubocop.yml; ensure these paths exist in packages/shakacode_demo_common (Node package lists “configs/”).
Run:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for f in "config/.rubocop.yml" "config/.eslintrc.js" "configs/.eslintrc.js"; do
test -f "packages/shakacode_demo_common/$f" && echo "Found: $f" || echo "Missing: $f"
doneLength of output: 87
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate .rubocop.yml and .eslintrc.js anywhere under the package
find packages/shakacode_demo_common -type f \( -name ".rubocop.yml" -o -name ".eslintrc.js" \) -printLength of output: 0
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# List all package directories
echo "Packages directory listing:"
ls -1 packages
# Find any config directories and relevant files
echo -e "\nConfig directories under packages:"
find packages -maxdepth 2 -type d -name "*config*"
echo -e "\nAny .rubocop.yml or .eslintrc.js in repo:"
find . -type f \( -name ".rubocop.yml" -o -name ".eslintrc.js" \) -printLength of output: 220
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Config directory files under packages/shakacode_demo_common/config:"
ls -1 packages/shakacode_demo_common/config || echo " (none)"
echo -e "\nConfigs directory files under packages/shakacode_demo_common/configs:"
ls -1 packages/shakacode_demo_common/configs || echo " (none)"Length of output: 199
Fix symlink targets to point at existing files
The demo script currently links to non‐existent paths under packages/shakacode_demo_common. Update as follows:
- ln -sf ../../packages/shakacode_demo_common/config/.rubocop.yml .rubocop.yml
+ ln -sf ../../packages/shakacode_demo_common/config/rubocop.yml .rubocop.yml
- ln -sf ../../packages/shakacode_demo_common/config/.eslintrc.js .eslintrc.js
+ ln -sf ../../packages/shakacode_demo_common/configs/eslint.config.js .eslintrc.jsThis ensures the symlinks reference the actual files (config/rubocop.yml and configs/eslint.config.js).
📝 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.
| echo "🔗 Creating configuration symlinks..." | |
| run_cmd "cd '$DEMO_DIR' && ln -sf ../../packages/shakacode_demo_common/config/.rubocop.yml .rubocop.yml" | |
| run_cmd "cd '$DEMO_DIR' && ln -sf ../../packages/shakacode_demo_common/config/.eslintrc.js .eslintrc.js" | |
| echo "🔗 Creating configuration symlinks..." | |
| run_cmd "cd '$DEMO_DIR' && ln -sf ../../packages/shakacode_demo_common/config/rubocop.yml .rubocop.yml" | |
| run_cmd "cd '$DEMO_DIR' && ln -sf ../../packages/shakacode_demo_common/configs/eslint.config.js .eslintrc.js" |
🤖 Prompt for AI Agents
In scripts/new-demo.sh around lines 191 to 194, the symlink targets point to
non-existent files under packages/shakacode_demo_common; update the ln -sf
commands to link to the actual existing files by changing the RuboCop target to
packages/shakacode_demo_common/config/rubocop.yml and the ESLint target to
packages/shakacode_demo_common/configs/eslint.config.js so the created
.rubocop.yml and .eslintrc.js in the demo dir reference real files.
| # Run JavaScript tests | ||
| if [ -f "package.json" ]; then | ||
| echo " Running JavaScript tests..." | ||
| npm test 2>/dev/null || true | ||
| npm run lint 2>/dev/null || true | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JS test/lint failures are ignored; not added to FAILED_DEMOS.
Current || true with stderr suppression hides failures and never marks the package as failed. Aggregate JS exits into FAILED_DEMOS and surface their output.
Apply this diff:
- if [ -f "package.json" ]; then
- echo " Running JavaScript tests..."
- npm test 2>/dev/null || true
- npm run lint 2>/dev/null || true
- fi
+ if [ -f "package.json" ]; then
+ echo " Running JavaScript tests..."
+ if ! npm test; then
+ FAILED_DEMOS="$FAILED_DEMOS shakacode_demo_common-js"
+ fi
+ if ! npm run lint; then
+ FAILED_DEMOS="$FAILED_DEMOS shakacode_demo_common-eslint"
+ fi
+ fi📝 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.
| # Run JavaScript tests | |
| if [ -f "package.json" ]; then | |
| echo " Running JavaScript tests..." | |
| npm test 2>/dev/null || true | |
| npm run lint 2>/dev/null || true | |
| fi | |
| # Run JavaScript tests | |
| if [ -f "package.json" ]; then | |
| echo " Running JavaScript tests..." | |
| if ! npm test; then | |
| FAILED_DEMOS="$FAILED_DEMOS shakacode_demo_common-js" | |
| fi | |
| if ! npm run lint; then | |
| FAILED_DEMOS="$FAILED_DEMOS shakacode_demo_common-eslint" | |
| fi | |
| fi |
🤖 Prompt for AI Agents
In scripts/test-all.sh around lines 28-33, tests and lint commands for JS use
"npm test 2>/dev/null || true" which suppresses stderr and always succeeds so
failures are never added to FAILED_DEMOS; replace those calls by running "npm
test" and "npm run lint" without discarding output, capture each command's exit
code (e.g., run and save $? or redirect output to a temp file and check its exit
status), and if the exit code is non-zero append the current demo path to
FAILED_DEMOS (and optionally echo the captured output to console); ensure you do
this for both test and lint runs so any failure aggregates into FAILED_DEMOS.
| # Run JavaScript tests | ||
| if [ -f "package.json" ]; then | ||
| echo " Running JavaScript tests..." | ||
| npm test 2>/dev/null || true | ||
| npm run lint 2>/dev/null || true | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue for demos: JS failures aren’t tracked.
Track JS test/lint failures per demo and avoid hiding stderr.
- if [ -f "package.json" ]; then
- echo " Running JavaScript tests..."
- npm test 2>/dev/null || true
- npm run lint 2>/dev/null || true
- fi
+ if [ -f "package.json" ]; then
+ echo " Running JavaScript tests..."
+ if ! npm test; then
+ FAILED_DEMOS="$FAILED_DEMOS ${demo_name}-js"
+ fi
+ if ! npm run lint; then
+ FAILED_DEMOS="$FAILED_DEMOS ${demo_name}-eslint"
+ fi
+ fi📝 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.
| # Run JavaScript tests | |
| if [ -f "package.json" ]; then | |
| echo " Running JavaScript tests..." | |
| npm test 2>/dev/null || true | |
| npm run lint 2>/dev/null || true | |
| fi | |
| # Run JavaScript tests | |
| if [ -f "package.json" ]; then | |
| echo " Running JavaScript tests..." | |
| if ! npm test; then | |
| FAILED_DEMOS="$FAILED_DEMOS ${demo_name}-js" | |
| fi | |
| if ! npm run lint; then | |
| FAILED_DEMOS="$FAILED_DEMOS ${demo_name}-eslint" | |
| fi | |
| fi |
🤖 Prompt for AI Agents
In scripts/test-all.sh around lines 62 to 67, the JS test/lint commands
currently hide stderr and always succeed due to redirection and "|| true";
change them to run per-demo without redirecting stderr, capture each command's
exit code, record failures per demo (e.g., increment a failure counter or append
demo name to a failures list) and continue to the next demo, and at the end exit
non-zero if any demo had test or lint failures so CI sees the errors.
| ./spec/demo_scripts/demo_creator_spec.rb[1:3:1] | passed | 0.00008 seconds | | ||
| ./spec/demo_scripts/demo_creator_spec.rb[1:3:2] | passed | 0.00169 seconds | | ||
| ./spec/demo_scripts/demo_creator_spec.rb[1:3:3] | passed | 0.00011 seconds | | ||
| ./spec/demo_scripts/pre_flight_checks_spec.rb[1:1:1:1] | failed | 0.04821 seconds | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Investigate the failing spec.
Line 24 shows a test failure in pre_flight_checks_spec.rb[1:1:1:1] with a runtime of 0.04821 seconds. This failure should be resolved before merging.
Run the following script to get details about the failing test:
🏁 Script executed:
#!/bin/bash
# Description: Retrieve the failing test details and recent runs
# Get the specific test context
rg -A 10 -B 5 "describe.*PreFlightChecks" spec/demo_scripts/pre_flight_checks_spec.rb
# Check if there are any recent test failure logs
fd --type f "rspec" tmp/ log/ --exec cat {} \; 2>/dev/null | head -100Length of output: 328
🏁 Script executed:
#!/bin/bash
# Display lines 1-50 of spec/examples.txt to locate the failing example and error message
sed -n '1,50p' spec/examples.txtLength of output: 2267
Resolve failing PreFlightChecks spec
spec/examples.txt line 24 reports failure in spec/demo_scripts/pre_flight_checks_spec.rb[1:1:1:1]; run the spec locally to inspect the error and fix this example before merging.
🤖 Prompt for AI Agents
In spec/examples.txt around line 24, the recorded example for
spec/demo_scripts/pre_flight_checks_spec.rb[1:1:1:1] is failing; run the spec
locally (rspec spec/demo_scripts/pre_flight_checks_spec.rb --format
documentation or the full example id) to capture the current failure output,
inspect the spec and related code to determine whether the test or the demo
script is incorrect, fix the underlying code or adjust the spec so it passes,
then update spec/examples.txt to reflect the corrected example output (including
status and timing) and re-run the full suite to ensure the example remains green
before committing.
Summary
Reorganized repository into a monorepo structure to support multiple React on Rails demo applications with shared tooling, comprehensive version management, and robust automation scripts.
Key Changes
🏗️ Monorepo Structure
packages/shakacode_demo_common/- Shared configuration and utilities gemdemos/- Directory for demo applications (to be populated)bin/- Ruby executables for demo management (new-demo,scaffold-demo,update-all-demos)scripts/- Legacy bash scripts (kept for compatibility)lib/demo_scripts/- Ruby modules for demo creation with full RSpec test coveragedocs/- Comprehensive documentation for contributors and version management🔒 Security Fixes (PR Review)
scaffold-demo.shtest-all.shthat prevented failure tracking📦 Package Renaming & Standardization
demo_common→shakacode_demo_common(follows Ruby convention: gem name matches directory)ReactOnRailsDemoCommon→DemoCommon→ShakacodeDemoCommonlib/demo_common/→lib/shakacode_demo_common/demo_common:install→shakacode_demo_common:install🛠️ Development Infrastructure
Ruby Scripts (Recommended):
bin/new-demo- Create basic demo with version controlbin/scaffold-demo- Create advanced demo with optionsbin/update-all-demos- Bulk update gem versions across demosShared Dependencies:
Gemfile.development_dependenciesfor inherited dev gemseval_gemfilepattern for consistencyCode Quality:
📚 Documentation Updates
VERSION_MANAGEMENT.md- Comprehensive guide for managing gem versionsCONTRIBUTING_SETUP.md- Development setup and hooksGemfile.development_dependenciespattern🎨 Code Formatting
npm run formatandnpm run format:check🔧 Script Improvements
.demo-versionsto.new-demo-versionsfor clarity⚙️ CI/CD Configuration
Version Management
Global Defaults (
.new-demo-versions)Creating Demos
Basic demo:
With custom versions:
Advanced scaffolding:
bin/scaffold-demo my-advanced-demo \ --react-on-rails-version '16.0.0.beta.1'With custom Rails/generator arguments:
Bulk Updates
Breaking Changes
Gem Name Change
Before:
After:
Module Rename
Before:
After:
Installation in Monorepo
Within monorepo:
From GitHub:
Test Plan
shakacode_demo_commonfollowing Ruby conventionsMigration Guide
For existing consumers:
Update Gemfile:
Update require statements:
Update module references:
Update generator commands:
Future Enhancements
bin/new-demo(planned)Related Documentation
🤖 Generated with Claude Code
Co-Authored-By: Claude [email protected]
Summary by CodeRabbit
New Features
CI
Documentation
Bug Fixes
Tests
Refactor (Breaking)