Skip to content

Conversation

@Seifeldin7
Copy link
Contributor

@Seifeldin7 Seifeldin7 commented Nov 19, 2025

Replace Husky + lint-staged with Lefthook for Git Hooks

Summary

This PR migrates the project's Git hooks from Husky + lint-staged to Lefthook, providing a more powerful, faster, and Ruby-native solution for managing pre-commit and pre-push hooks.

Motivation

  • Better Ruby integration: Lefthook is distributed as a gem, aligning with our Ruby-based project
  • Performance: Native parallel execution and faster hook processing
  • Enhanced features: Support for both file-level and full test suite validation
  • Cleaner architecture: Explicit hook scripts instead of inline configurations
  • Lower maintenance: One tool instead of two (Husky + lint-staged)

Changes

 Removed

  • .husky/ directory and pre-commit hook
  • husky and lint-staged npm dependencies
  • lint-staged configuration from package.json

 Added

Lefthook Configuration (lefthook.yml):

  • Pre-commit hooks with parallel execution
  • Pre-push hooks for comprehensive validation

Hook Scripts (bin/lefthook/):

  1. rubocop-lint - Auto-fix Ruby style issues on staged files
  2. js-lint - ESLint + Prettier + TypeScript type checking for JS/TS files
  3. prettier-format - Prettier formatting for JSON/YAML/Markdown files
  4. check-trailing-newlines - Auto-fix missing trailing newlines
  5. rspec-affected - Run RSpec tests for changed Ruby files
  6. jest-affected - Run Jest tests for changed JS/TS files

📝 Updated

  • CONTRIBUTING.md - Updated setup instructions
  • conductor-setup.sh - Changed from npx husky to bundle exec lefthook install
  • README.md - Added comprehensive Lefthook documentation
  • Gemfile.development_dependencies - Added lefthook gem

Feature Parity with lint-staged

All previous lint-staged functionality is preserved and enhanced:

File Type | Previous (lint-staged) | New (Lefthook) -- | -- | -- JS/JSX | ESLint --fix + Prettier | ✅ js-lint script TS/TSX | ESLint --fix + Prettier + Type checking | ✅ js-lint script JSON/YAML/MD | Prettier | ✅ prettier-format script Ruby | ❌ Not supported | ✅ rubocop-lint script

Plus new features:

  • Automatic RSpec tests for affected Ruby files
  • Automatic Jest tests for affected JS/TS files
  • Trailing newline validation and auto-fixing
  • Pre-push hooks for full validation before pushing

Pre-commit Hooks (Parallel Execution)

Fast validation on staged files only:

  • ✅ RuboCop auto-fix
  • ✅ ESLint auto-fix + Prettier formatting
  • ✅ TypeScript type checking
  • ✅ Trailing newline checks
  • ✅ RSpec tests for affected files
  • ✅ Jest tests for affected files

Pre-push Hooks (Comprehensive)

Full validation before pushing:

  • ✅ Complete RuboCop linting
  • ✅ Full RSpec test suite
  • ✅ Complete JavaScript linting
  • ✅ Full Jest test suite

Installation

bundle install
bundle exec lefthook install

Manual Hook Execution

# Run pre-commit checks
bundle exec lefthook run pre-commit

Run pre-push checks

bundle exec lefthook run pre-push

Bypassing Hooks (when necessary)

# Skip pre-commit
git commit --no-verify

Skip pre-push

git push --no-verify

Testing

  • ✅ Hooks install successfully
  • ✅ Pre-commit runs in parallel (~0.3s for clean files)
  • ✅ All auto-fixing capabilities work correctly
  • ✅ Graceful degradation when tools are unavailable

Migration Notes

This is a non-breaking change:

  • Hooks remain opt-in for contributors
  • CI/CD continues to be the source of truth for validation
  • All existing functionality is preserved
  • Installation is simple: bundle install && bundle exec lefthook install

Summary by CodeRabbit

  • Chores

    • Replaced Husky/lint-staged setup with Lefthook and removed Husky entries.
    • Added Lefthook to development tooling.
  • New Features

    • Added multiple pre-commit/pre-push helper hooks to auto-run linters, formatters, type checks, and affected tests.
  • Documentation

    • Updated contributor setup instructions to use Bundler + Lefthook and noted hooks auto-run linters/formatters/tests.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Warning

Rate limit exceeded

@Seifeldin7 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 11 minutes and 56 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 0cff0a7 and 6ea96a1.

📒 Files selected for processing (3)
  • bin/lefthook/js-lint (1 hunks)
  • bin/lefthook/prettier-format (1 hunks)
  • bin/lefthook/rubocop-lint (1 hunks)

Walkthrough

Replaces Husky + lint-staged with Lefthook: removes .husky/pre-commit, adds lefthook gem and lefthook.yml, introduces bin/lefthook/* hook scripts, updates contributor setup and package.json to use Lefthook-based hooks and workflows.

Changes

Cohort / File(s) Summary
Hook removal
\.husky/pre-commit``
Delete Husky pre-commit hook file that previously invoked lint-staged.
Lefthook config & install
\lefthook.yml`, `conductor-setup.sh`, `CONTRIBUTING.md``
Add lefthook.yml with parallel pre-commit/pre-push hooks; update setup and docs to install and use Lefthook (bundle exec lefthook install) and document automatic hook behavior.
Development dependency
\Gemfile.development_dependencies``
Add lefthook gem (~> 2.0.0) in the development group (require: false).
Remove Husky/lint-staged
\package.json``
Remove husky and lint-staged devDependencies and delete the top-level lint-staged config.
Hook scripts (new)
\bin/lefthook/*`<br>`bin/lefthook/rubocop-lint`, `bin/lefthook/js-lint`, `bin/lefthook/prettier-format`, `bin/lefthook/check-trailing-newlines`, `bin/lefthook/rspec-affected`, `bin/lefthook/jest-affected``
Add executable scripts to lint/format/check staged files, map source files to affected tests, run RuboCop/ESLint/Prettier/tsc/rspec/jest as appropriate, and surface failures via exit codes.
Removed script
\scripts/type-check-no-emit.js``
Remove Node wrapper that ran npx tsc --noEmit.
Minor style change
\spec/dummy/bin/shakapacker-config``
Change require quoting from double to single quotes (stylistic).

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Git
    participant Lefthook
    participant Script as bin/lefthook/*
    participant Tool as Linters/Tests

    Dev->>Git: git commit
    Git->>Lefthook: trigger pre-commit
    Lefthook->>Lefthook: read lefthook.yml

    par Parallel hooks
        Lefthook->>Script: rubocop-lint (rb files)
        Script->>Tool: bundle exec rubocop --autocorrect-all
        Tool-->>Script: result

        Lefthook->>Script: js-lint (js/ts files)
        Script->>Tool: eslint --fix / prettier --write / tsc checks
        Tool-->>Script: result

        Lefthook->>Script: prettier-format (staged)
        Script->>Tool: yarn prettier --write
        Tool-->>Script: result

        Lefthook->>Script: rspec-affected / jest-affected
        Script->>Tool: bundle exec rspec / yarn test (affected files)
        Tool-->>Script: result

        Lefthook->>Script: check-trailing-newlines
        Script-->>Script: append missing newlines
    end

    Lefthook->>Git: aggregated exit code
    alt all pass
        Git->>Dev: commit proceeds
    else any fail
        Git->>Dev: commit blocked (show failures)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect each new hook script for edge cases (file mapping, whitespace handling, correct shebangs and executable flags).
  • Verify lefthook.yml glob patterns and that pre-push full-run commands are correct.
  • Confirm Gemfile group placement and updated installer behavior in conductor-setup.sh.
  • Ensure package.json removals don't break other npm scripts or CI steps.

Possibly related issues

Possibly related PRs

Suggested reviewers

  • AbanoubGhadban

Poem

🐰 I hopped along the commit tree,
Husky bowed out, Lefthook set me free.
Scripts hum in parallel, tidy and bright,
Newlines fixed and tests take flight.
A rabbit’s cheer for hooks done right! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Add lefthook' is vague and generic, using minimal descriptive language that doesn't clearly convey the scope of the migration from Husky to Lefthook. Consider a more descriptive title like 'Migrate git hooks from Husky to Lefthook' to better summarize the main change.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

❤️ Share

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

@claude
Copy link

claude bot commented Nov 19, 2025

Code Review: Lefthook Migration

Overall Assessment

This is a well-executed migration from Husky + lint-staged to Lefthook. The implementation is clean, comprehensive, and includes excellent documentation. The PR demonstrates good engineering practices with proper cleanup, feature parity, and enhanced capabilities.

✅ Strengths

1. Clean Migration Strategy

  • Complete removal of old dependencies (Husky, lint-staged)
  • Proper cleanup of configuration from package.json
  • No orphaned files or configurations left behind

2. Well-Structured Hook Scripts

  • All scripts properly handle edge cases (empty file lists, missing files)
  • Graceful degradation with appropriate exit codes
  • Good separation of concerns with individual script files
  • Executable permissions correctly set (chmod +x)

3. Enhanced Functionality

  • New capabilities not available before:
    • RuboCop linting on Ruby files (previously missing)
    • Automatic test running for affected files (both RSpec and Jest)
    • Trailing newline validation and auto-fixing
    • Pre-push hooks for comprehensive validation
  • Maintains full feature parity with lint-staged for JS/TS files

4. Excellent Documentation

  • Clear setup instructions in CONTRIBUTING.md
  • Updated conductor-setup.sh script
  • Well-commented lefthook.yml configuration
  • Comprehensive PR description

5. Performance Benefits

  • Parallel execution enabled for all hooks
  • Faster hook processing with native Go implementation

🐛 Issues Found

1. Critical: Unquoted Variables in Shell Scripts (Security & Correctness)

Multiple scripts have unquoted variable expansions that will break with filenames containing spaces or special characters:

bin/lefthook/rubocop-lint:14

bundle exec rubocop --autocorrect-all $@

bin/lefthook/js-lint:35, 41

yarn eslint --fix $format_files || has_errors=1
yarn prettier --write $format_files || has_errors=1

bin/lefthook/prettier-format:14

yarn prettier --write $@

bin/lefthook/rspec-affected:40

bundle exec rspec $spec_files

bin/lefthook/jest-affected:64

yarn test --findRelatedTests $test_files

Fix: Quote all variable expansions or use arrays for accumulating filenames.

2. Issue: check-trailing-newlines Has Side Effects

bin/lefthook/check-trailing-newlines:25

This script modifies files but exits with code 1, which will:

  1. Block the commit
  2. Require manual git add of the changes

Implications:

  • This is actually good UX (forces review of auto-fixes)
  • However, it is inconsistent with RuboCop and ESLint which auto-fix and continue
  • Consider documenting this behavior or aligning with other auto-fixers

3. Potential Issue: TypeScript Type Check Script Dependency

bin/lefthook/js-lint:47

This assumes scripts/type-check-no-emit.js exists. If it does not exist, the script will fail silently.

Recommendation: Add existence check before running.

4. Minor: Inconsistent Error Handling Pattern

Some scripts check exit codes immediately, while others accumulate errors. The accumulated error pattern is better for running multiple checks, but mixing patterns reduces consistency.

⚠️ Considerations

1. Pre-push Hooks May Be Too Aggressive

Running the full test suite on every push (yarn test, bundle exec rspec) could be slow for large projects and frustrate developers. Consider:

  • Making pre-push hooks optional/skippable
  • Only running tests for changed files on push
  • Documenting how to bypass: git push --no-verify

2. Missing Edge Cases

  • rspec-affected only handles lib/* files. What about:

    • Files in app/, config/, or other directories?
    • Gemspec or Rakefile changes?
    • Consider adding support or documenting limitations
  • jest-affected looks for test files by pattern, but could be enhanced

3. Parallel Execution Concerns

With parallel: true in lefthook.yml:

  • All pre-commit hooks run simultaneously
  • If multiple hooks modify the same file (e.g., RuboCop and trailing newlines), race conditions could occur
  • In practice, this is probably fine since they operate on different file types

📋 Test Coverage

Missing:

  • No tests for the shell scripts themselves
  • Consider adding integration tests that verify hooks work correctly
  • At minimum, test with filenames containing spaces/special characters

🔒 Security Assessment

✅ No security issues found, but:

  • All scripts use set -e properly (fail fast)
  • No eval or dynamic command execution
  • No external input injection vulnerabilities
  • Fix the quoting issues to prevent potential command injection with malicious filenames

📝 Documentation

Excellent documentation provided:

  • ✅ CONTRIBUTING.md updated with clear instructions
  • ✅ lefthook.yml is well-commented
  • ✅ Comprehensive PR description
  • ✅ conductor-setup.sh updated

Could be improved:

  • Add a comment in each hook script explaining its purpose
  • Document the pre-push hook behavior (slow, full test suite)
  • Add troubleshooting section for common issues

🎯 Recommendations

Must Fix (Before Merge):

  1. Quote all variable expansions in shell scripts to handle filenames with spaces
  2. Add existence check for scripts/type-check-no-emit.js

Should Consider (Before or After Merge):

  1. Decide on trailing newline behavior: Auto-fix and continue, or require manual staging?
  2. Document or adjust pre-push hooks: Consider making them less aggressive
  3. Expand rspec-affected: Support more directories than just lib/
  4. Add shell script tests: At least basic smoke tests

Nice to Have:

  1. Standardize error handling patterns across scripts
  2. Add troubleshooting documentation
  3. Consider using shell script linter (shellcheck) in CI

✅ Approval Recommendation

Approve with minor fixes. This is a high-quality PR that improves the project's development workflow. The critical issues (variable quoting) should be addressed before merge, but they're straightforward fixes.

The migration is well-thought-out and the enhanced capabilities (Ruby linting, automatic test running, trailing newline checks) are valuable additions to the development workflow.


Great work on this migration! 🎉 The attention to detail and comprehensive documentation make this a solid improvement to the project.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CONTRIBUTING.md (1)

34-52: Align remaining setup instructions with Lefthook (remove Husky reference)

The new “Git Hooks (Optional)” section correctly documents Lefthook (bundle exec lefthook install), but the later dev‑env setup still says:

bundle install
yarn install
yarn prepare:husky  # Set up pre-commit hooks for linting

This is now stale and will mislead contributors.

Consider updating that block to reference Lefthook instead (or to point back to the “Git Hooks (Optional)” section), e.g.:

-   yarn prepare:husky  # Set up pre-commit hooks for linting
+   bundle exec lefthook install  # (Optional) Set up git hooks for linting/tests

Also applies to: 179-184

🧹 Nitpick comments (1)
bin/lefthook/js-lint (1)

4-4: Consider adjusting error handling approach.

The script uses set -e but then captures errors with || has_errors=1 throughout. While this works, it's potentially confusing since set -e is effectively neutralized by the error capture pattern. Consider either removing set -e or using set +e before error-captured commands for clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ee4bc6 and 2697ed9.

⛔ Files ignored due to path filters (2)
  • Gemfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (12)
  • .husky/pre-commit (0 hunks)
  • CONTRIBUTING.md (2 hunks)
  • Gemfile.development_dependencies (1 hunks)
  • bin/lefthook/check-trailing-newlines (1 hunks)
  • bin/lefthook/jest-affected (1 hunks)
  • bin/lefthook/js-lint (1 hunks)
  • bin/lefthook/prettier-format (1 hunks)
  • bin/lefthook/rspec-affected (1 hunks)
  • bin/lefthook/rubocop-lint (1 hunks)
  • conductor-setup.sh (1 hunks)
  • lefthook.yml (1 hunks)
  • package.json (0 hunks)
💤 Files with no reviewable changes (2)
  • package.json
  • .husky/pre-commit
⏰ 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). (20)
  • GitHub Check: Generator specs (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.0, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.7.1.x)
  • GitHub Check: Testing (ubuntu-latest, 3.4, gemfiles/Gemfile-rails.7.2.x)
  • GitHub Check: Testing (ubuntu-latest, 3.3, gemfiles/Gemfile-rails.8.0.x)
  • GitHub Check: Testing (ubuntu-latest, 3.2, gemfiles/Gemfile-rails.7.2.x)
  • GitHub Check: Testing (ubuntu-latest, 3.4, gemfiles/Gemfile-rails.7.1.x)
  • GitHub Check: Testing (ubuntu-latest, 3.2, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Testing (ubuntu-latest, 3.2, gemfiles/Gemfile-rails.8.0.x)
  • GitHub Check: Testing (ubuntu-latest, 3.3, gemfiles/Gemfile-rails.7.2.x)
  • GitHub Check: Testing (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.6.1.x)
  • GitHub Check: Testing (ubuntu-latest, 3.0, gemfiles/Gemfile-rails.6.1.x)
  • GitHub Check: Testing (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Testing (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.7.1.x)
  • GitHub Check: Testing (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.7.1.x)
  • GitHub Check: test
  • GitHub Check: Testing (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Testing (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.6.1.x)
  • GitHub Check: Testing (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.6.0.x)
  • GitHub Check: claude-review
🔇 Additional comments (4)
Gemfile.development_dependencies (1)

17-19: LGTM: Lefthook wired in as a dev‑only dependency

Using a dedicated :development group with require: false is a clean way to add Lefthook without impacting runtime or test environments.

bin/lefthook/check-trailing-newlines (1)

1-39: LGTM: trailing newline fixer is simple and effective

The script correctly skips non-existent/empty files, auto-adds missing trailing newlines, and exits non‑zero to force re‑staging when it makes changes. This is a good fit for a pre‑commit hook.

lefthook.yml (1)

27-37: LGTM!

The pre-push configuration appropriately runs full repository checks without glob filtering, ensuring comprehensive validation before pushing changes.

bin/lefthook/js-lint (1)

44-48: No issues found—type checking behavior is intentional and well-documented.

The script deliberately ignores file arguments passed by lint-staged and runs full project type checking via tsc --noEmit. This is by design: as the script's own comments explain, passing individual file paths would cause TypeScript to ignore tsconfig.json and fail type checking. The current implementation is correct and follows best practices for TypeScript type checking in a lint-staged workflow.

Likely an incorrect or invalid review comment.

Comment on lines 13 to 28
# Separate TypeScript files from JavaScript files
ts_files=""
js_files=""
format_files=""

for file in "$@"; do
# Add all files to format_files for prettier
format_files="$format_files $file"

# Separate TS/TSX from JS/JSX for type checking
if [[ "$file" == *.ts || "$file" == *.tsx ]]; then
ts_files="$ts_files $file"
elif [[ "$file" == *.js || "$file" == *.jsx ]]; then
js_files="$js_files $file"
fi
done
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use bash arrays instead of string concatenation for file lists.

Building file lists via string concatenation (ts_files="$ts_files $file") is fragile and will break when filenames contain spaces or special characters. Bash arrays provide proper handling and quoting.

Apply this refactor to use arrays:

 # Separate TypeScript files from JavaScript files
-ts_files=""
-js_files=""
-format_files=""
+ts_files=()
+js_files=()
+format_files=()
 
 for file in "$@"; do
   # Add all files to format_files for prettier
-  format_files="$format_files $file"
+  format_files+=("$file")
 
   # Separate TS/TSX from JS/JSX for type checking
   if [[ "$file" == *.ts || "$file" == *.tsx ]]; then
-    ts_files="$ts_files $file"
+    ts_files+=("$file")
   elif [[ "$file" == *.js || "$file" == *.jsx ]]; then
-    js_files="$js_files $file"
+    js_files+=("$file")
   fi
 done

Then update the command invocations to use array expansion:

 # Run ESLint with --fix on JS/TS files
-if [ -n "$js_files" ] || [ -n "$ts_files" ]; then
+if [ ${#js_files[@]} -gt 0 ] || [ ${#ts_files[@]} -gt 0 ]; then
   echo "Running ESLint --fix..."
-  yarn eslint --fix $format_files || has_errors=1
+  yarn eslint --fix "${format_files[@]}" || has_errors=1
 fi
 
 # Run Prettier on all files
-if [ -n "$format_files" ]; then
+if [ ${#format_files[@]} -gt 0 ]; then
   echo "Running Prettier..."
-  yarn prettier --write $format_files || has_errors=1
+  yarn prettier --write "${format_files[@]}" || has_errors=1
 fi
 
 # Run TypeScript type checking on TS/TSX files
-if [ -n "$ts_files" ]; then
+if [ ${#ts_files[@]} -gt 0 ]; then
   echo "Running TypeScript type checking..."
   node scripts/type-check-no-emit.js || has_errors=1
 fi

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
bin/lefthook/prettier-format (1)

14-14: Quote $@ to handle filenames with spaces.

While the set -e issue from the previous review has been addressed, $@ should still be quoted as "$@" to properly handle filenames containing spaces or special characters.

Apply this diff:

-if ! yarn prettier --write $@; then
+if ! yarn prettier --write "$@"; then
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2697ed9 and e358649.

📒 Files selected for processing (7)
  • CONTRIBUTING.md (3 hunks)
  • bin/lefthook/jest-affected (1 hunks)
  • bin/lefthook/js-lint (1 hunks)
  • bin/lefthook/prettier-format (1 hunks)
  • bin/lefthook/rspec-affected (1 hunks)
  • lefthook.yml (1 hunks)
  • spec/dummy/bin/shakapacker-config (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • spec/dummy/bin/shakapacker-config
🚧 Files skipped from review as they are similar to previous changes (4)
  • bin/lefthook/js-lint
  • lefthook.yml
  • bin/lefthook/jest-affected
  • CONTRIBUTING.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Testing (ubuntu-latest, 3.2, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Testing (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.7.2.x)
  • GitHub Check: Testing (ubuntu-latest, 3.0, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Testing (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Testing (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.6.0.x)
  • GitHub Check: Testing (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.6.1.x)
  • GitHub Check: test
  • GitHub Check: Generator specs (ubuntu-latest, 3.4, gemfiles/Gemfile-rails.8.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.3, gemfiles/Gemfile-rails.7.1.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.3, gemfiles/Gemfile-rails.8.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.2, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.3, gemfiles/Gemfile-rails.7.2.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.2, gemfiles/Gemfile-rails.7.2.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.2, gemfiles/Gemfile-rails.8.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.0, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.7.2.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.3, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 2.7, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: Generator specs (ubuntu-latest, 3.1, gemfiles/Gemfile-rails.7.0.x)
  • GitHub Check: claude-review

Comment on lines +12 to +44
spec_files=""
for file in "$@"; do
# Skip if file is already a spec file
if [[ "$file" == *"_spec.rb" ]]; then
if [ -f "$file" ]; then
spec_files="$spec_files $file"
fi
continue
fi

# Convert lib/shakapacker/foo.rb to spec/shakapacker/foo_spec.rb
if [[ "$file" == lib/* ]]; then
spec_file="${file/lib\//spec/}"
spec_file="${spec_file/.rb/_spec.rb}"
if [ -f "$spec_file" ]; then
spec_files="$spec_files $spec_file"
fi
fi
done

if [ -z "$spec_files" ]; then
echo "No corresponding spec files found for staged files"
exit 0
fi

echo "Running RSpec for affected files..."
echo "Spec files: $spec_files"

if ! bundle exec rspec $spec_files; then
echo ""
echo "Tests failed. Please fix the issues before committing."
exit 1
fi
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use array instead of space-separated string for spec files.

While the set -e issue from the previous review has been addressed, the script still uses string concatenation with spaces to build spec_files (lines 17, 27). This approach breaks when spec file paths contain spaces or special characters. At line 40, the unquoted $spec_files will cause incorrect word-splitting.

Apply this diff to use a bash array:

 # Convert source files to their corresponding spec files
-spec_files=""
+spec_files=()
 for file in "$@"; do
   # Skip if file is already a spec file
   if [[ "$file" == *"_spec.rb" ]]; then
     if [ -f "$file" ]; then
-      spec_files="$spec_files $file"
+      spec_files+=("$file")
     fi
     continue
   fi
 
   # Convert lib/shakapacker/foo.rb to spec/shakapacker/foo_spec.rb
   if [[ "$file" == lib/* ]]; then
     spec_file="${file/lib\//spec/}"
     spec_file="${spec_file/.rb/_spec.rb}"
     if [ -f "$spec_file" ]; then
-      spec_files="$spec_files $spec_file"
+      spec_files+=("$spec_file")
     fi
   fi
 done
 
-if [ -z "$spec_files" ]; then
+if [ ${#spec_files[@]} -eq 0 ]; then
   echo "No corresponding spec files found for staged files"
   exit 0
 fi
 
 echo "Running RSpec for affected files..."
-echo "Spec files: $spec_files"
+echo "Spec files: ${spec_files[*]}"
 
-if ! bundle exec rspec $spec_files; then
+if ! bundle exec rspec "${spec_files[@]}"; then
   echo ""
   echo "Tests failed. Please fix the issues before committing."
   exit 1
 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.

Suggested change
spec_files=""
for file in "$@"; do
# Skip if file is already a spec file
if [[ "$file" == *"_spec.rb" ]]; then
if [ -f "$file" ]; then
spec_files="$spec_files $file"
fi
continue
fi
# Convert lib/shakapacker/foo.rb to spec/shakapacker/foo_spec.rb
if [[ "$file" == lib/* ]]; then
spec_file="${file/lib\//spec/}"
spec_file="${spec_file/.rb/_spec.rb}"
if [ -f "$spec_file" ]; then
spec_files="$spec_files $spec_file"
fi
fi
done
if [ -z "$spec_files" ]; then
echo "No corresponding spec files found for staged files"
exit 0
fi
echo "Running RSpec for affected files..."
echo "Spec files: $spec_files"
if ! bundle exec rspec $spec_files; then
echo ""
echo "Tests failed. Please fix the issues before committing."
exit 1
fi
spec_files=()
for file in "$@"; do
# Skip if file is already a spec file
if [[ "$file" == *"_spec.rb" ]]; then
if [ -f "$file" ]; then
spec_files+=("$file")
fi
continue
fi
# Convert lib/shakapacker/foo.rb to spec/shakapacker/foo_spec.rb
if [[ "$file" == lib/* ]]; then
spec_file="${file/lib\//spec/}"
spec_file="${spec_file/.rb/_spec.rb}"
if [ -f "$spec_file" ]; then
spec_files+=("$spec_file")
fi
fi
done
if [ ${#spec_files[@]} -eq 0 ]; then
echo "No corresponding spec files found for staged files"
exit 0
fi
echo "Running RSpec for affected files..."
echo "Spec files: ${spec_files[*]}"
if ! bundle exec rspec "${spec_files[@]}"; then
echo ""
echo "Tests failed. Please fix the issues before committing."
exit 1
fi
🤖 Prompt for AI Agents
In bin/lefthook/rspec-affected around lines 12 to 44, the script builds
spec_files as a space-separated string which breaks on paths with spaces and is
later unquoted when invoked; change spec_files to a bash array (initialize
spec_files=()), append entries with spec_files+=("$file") where the script
currently does string concatenation (lines ~17 and ~27), check emptiness with [
${#spec_files[@]} -eq 0 ] (instead of -z), and invoke RSpec with properly quoted
array expansion: bundle exec rspec "${spec_files[@]}"; also update any echo of
the list to handle the array (e.g., echo "Spec files: ${spec_files[*]}").

@claude
Copy link

claude bot commented Nov 19, 2025

Pull Request Review: Lefthook Migration

Overall Assessment

This is a well-executed migration from Husky + lint-staged to Lefthook. The implementation is thorough, well-documented, and provides excellent feature parity plus enhancements. The code quality is high with good error handling and user feedback.

Strengths

1. Excellent Documentation

  • Clear PR description with comprehensive feature comparison
  • Well-documented shell scripts with descriptive comments
  • Updated CONTRIBUTING.md and README.md with usage instructions

2. Feature Enhancement

  • Adds pre-push hooks for comprehensive validation (major improvement!)
  • Adds automatic RSpec/Jest test running for affected files
  • Adds trailing newline validation (per project requirements)
  • Better Ruby integration via gem distribution

3. Clean Architecture

  • Modular hook scripts in bin/lefthook/ directory
  • Clear separation of concerns (lint, format, test)
  • Parallel execution for better performance

4. Good Error Handling

  • All scripts properly check for empty inputs
  • Graceful degradation (exit 0) when no files to process
  • Clear error messages guiding users on next steps

Issues Found

1. CRITICAL: Missing set -e in js-lint script (bin/lefthook/js-lint:4)

Problem: Unlike the other scripts, js-lint does not have set -e at the top, which means it will not exit on command failures. It relies on manual error tracking with has_errors, but this is less robust.

Impact: Could mask errors if commands fail unexpectedly.

Fix: Either add set -e and refactor to use explicit error handling similar to other scripts, OR intentionally omit it and document why this script uses a different error handling approach.

2. Potential Issue: Unquoted Variable Expansion (Multiple files)

All scripts use unquoted variable expansions which can cause issues with filenames containing spaces:

  • bin/lefthook/rubocop-lint:14 uses $@ instead of "$@"
  • bin/lefthook/js-lint:33 uses $format_files instead of "$format_files"
  • bin/lefthook/rspec-affected:40 uses $spec_files instead of "$spec_files"
  • bin/lefthook/jest-affected:64 uses $test_files instead of "$test_files"

Problem: File paths with spaces will be split into multiple arguments.

Impact: Scripts will fail on files with spaces in their names.

Fix: Quote all variable expansions throughout all scripts.

3. Bug: Variable naming inconsistency (bin/lefthook/js-lint:31-33)

The condition checks $js_files and $ts_files but the command uses $format_files which includes ALL files:

if [ -n "$js_files" ] || [ -n "$ts_files" ]; then
  echo "Running ESLint --fix..."
  yarn eslint --fix $format_files || has_errors=1
fi

Clarification needed: Should ESLint run only on js/ts files or all files? The current logic is confusing.


Performance Considerations

1. Pre-commit hooks might be too aggressive

Running BOTH linting/formatting AND tests on pre-commit could slow down development workflow significantly.

Suggestion: Consider making the test hooks (rspec-affected jest-affected) optional or configurable. Many teams prefer running tests only on pre-push to keep commits fast.

Alternative: Add Lefthook environment variable to skip tests:

rspec-affected:
  run: bin/lefthook/rspec-affected {staged_files}
  skip:
    - env: LEFTHOOK_SKIP_TESTS

2. Pre-push runs full test suite

The pre-push hook runs the complete test suite which could be slow.

Question: Is this intentional? Consider documenting the expected time and how to skip with --no-verify for emergency pushes.


Code Quality & Best Practices

Good practices found:

  1. Proper use of bundle exec (per project requirements)
  2. All new files have trailing newlines (per project requirements)
  3. Modular design with single responsibility per script

Suggestions:

  1. Add file existence check for scripts/type-check-no-emit.js before running (bin/lefthook/js-lint:45)
  2. Consider using array-based approach for failed_files in check-trailing-newlines instead of string concatenation with escape sequences

Test Coverage Questions

  1. Have you tested the hooks with files with spaces in their names?
  2. Have you tested with empty commits (no staged files)?
  3. Have you tested the rspec-affected script with files outside the lib/ directory?
  4. Have you verified pre-push hooks work correctly when pushing multiple commits?

Recommendations

Must Fix (Before Merge):

  1. Fix missing set -e or clarify error handling approach in js-lint
  2. Quote all variable expansions to handle spaces in filenames
  3. Clarify the $format_files vs $js_files/$ts_files inconsistency

Should Fix:

  1. Add file existence check for scripts/type-check-no-emit.js
  2. Test with filenames containing spaces
  3. Consider making test hooks configurable/optional

Nice to Have:

  1. Improve trailing newline script robustness
  2. Add troubleshooting documentation
  3. Consider allowing 2.x updates for lefthook gem (~> 2.0 instead of ~> 2.0.0)

Final Verdict

Recommendation: Approve with minor changes

This is a high-quality PR that significantly improves the projects git hooks infrastructure. The migration is well-planned and thorough. The critical issues (quoting variables fixing set -e) are straightforward to address. Once those are fixed this is ready to merge.

Great work on the comprehensive documentation and test coverage enhancements!

@claude
Copy link

claude bot commented Nov 19, 2025

Code Review: Lefthook Migration

I've reviewed PR #842. Overall, this is a solid improvement to the project's tooling infrastructure, but there are some important issues to address.


Critical Issues

1. Missing CHANGELOG Entry
According to CLAUDE.md, user-visible changes should be documented. This migration affects developer workflow significantly.

Action Required: Add a CHANGELOG entry with PR link and author.

2. Shell Script Security: Unquoted Variables
Multiple scripts have unquoted variable expansions causing potential word splitting issues:

  • bin/lefthook/js-lint lines 25, 31: Use "$js_ts_files" instead of $js_ts_files
  • bin/lefthook/prettier-format line 14: Use "$@" instead of $@
  • bin/lefthook/rubocop-lint line 14: Use "$@" instead of $@
  • bin/lefthook/rspec-affected line 40: Use "$spec_files" instead of $spec_files
  • bin/lefthook/jest-affected line 64: Use "$test_files" instead of $test_files

Impact: Files with spaces in names will break these scripts.


High Priority Issues

3. Incorrect Exit Code Handling in rubocop-lint
Location: bin/lefthook/rubocop-lint:14-15

The script has set -e enabled but tries to capture exit codes manually. The if check at line 17 will never execute because set -e causes immediate exit on error.

Fix: Either remove set -e OR use || true pattern.

4. Pre-Push Hooks May Be Too Aggressive
Running full test suites on every push can take minutes and frustrate developers. CI already runs these. Consider making pre-push hooks opt-in or documenting --no-verify.


Medium Priority Issues

5. check-trailing-newlines Auto-Fix Workflow
Auto-fixes but exits 1, requiring manual git add. This creates awkward two-step workflow.

6. rspec-affected Limited Scope
Only handles lib/ files. Won't catch config, Rakefile, gemspec changes.

7. jest-affected Simplified Detection
Manually searches test files instead of using Jest's --findRelatedTests directly on source files.


Code Quality Notes

  • Inconsistent error handling across scripts
  • Consider adding shellcheck to CI
  • typescript-check glob is misleading (checks entire project)

Positive Highlights

  1. Excellent script organization
  2. Good error messages
  3. Comprehensive coverage
  4. Parallel execution
  5. Proper permissions
  6. Graceful degradation

Testing Checklist

Have these been tested?

  • Files with spaces in names
  • Empty commits
  • Large commits (100+ files)
  • Missing tool dependencies

Summary

Please address:

  1. CRITICAL: Add CHANGELOG entry
  2. CRITICAL: Quote all shell variables
  3. HIGH: Fix rubocop-lint exit handling
  4. CONSIDER: Document aggressive pre-push hooks

The migration strategy is sound and hook organization is excellent. With these fixes, this will be a solid enhancement!

@claude
Copy link

claude bot commented Nov 19, 2025

PR Review: Add Lefthook

Thanks for this comprehensive migration from Husky + lint-staged to Lefthook! Overall, this is a well-structured PR that modernizes the git hook setup. Here's my detailed feedback:

✅ Strengths

  1. Excellent Documentation: The PR description is thorough and the README updates provide clear usage instructions
  2. Feature Parity: Successfully maintains all previous lint-staged functionality
  3. Enhanced Capabilities: Adds valuable features like affected file testing and pre-push validation
  4. Clean Architecture: Shell scripts are well-organized in bin/lefthook/
  5. Good Error Handling: Scripts provide helpful error messages and auto-fix capabilities

🐛 Critical Issues

1. Shell Quoting Vulnerability (Security)

Multiple scripts have unquoted variable expansions that could break with filenames containing spaces:

bin/lefthook/js-lint:25,31,42

yarn eslint --fix $js_ts_files  # Should be: "$js_ts_files"
yarn prettier --write $js_ts_files  # Should be: "$js_ts_files"
git add $js_ts_files  # Should be: "$js_ts_files"

bin/lefthook/rspec-affected:40

bundle exec rspec $spec_files  # Should be: "$spec_files"

bin/lefthook/jest-affected:64

yarn test --findRelatedTests $test_files  # Should be: "$test_files"

This could cause failures or unexpected behavior with files containing spaces or special characters.

2. Inconsistent Script Error Handling

bin/lefthook/js-lint is missing set -e at the top (lines 1-3), unlike other scripts. This means it won't exit immediately on errors in some cases, which could lead to incomplete validation.

3. Pre-Push Hooks May Be Too Heavy

The pre-push hooks run the full test suite on every push (lefthook.yml:36,40). This could make pushes very slow, especially for small changes. Consider:

  • Making pre-push hooks optional or configurable
  • Only running full tests on CI
  • Using LEFTHOOK=0 environment variable for quick pushes

4. TypeScript Type Check Runs on All Files

lefthook.yml:20-22 runs type-checking on the entire codebase even if only one TS file changed. The old lint-staged approach was smarter. Consider using the glob filtering or removing this from pre-commit.

⚠️ Moderate Issues

5. Trailing Newline Check Has Confusing UX

bin/lefthook/check-trailing-newlines:29-36 auto-fixes files but then exits with status 1 and tells users to manually stage the changes. Either auto-stage the fixes with git add and exit 0, or don't auto-fix.

6. spec/dummy/bin/shakapacker-config Style Change

The diff shows an unintentional formatting change from double quotes to single quotes. This is an extraneous diff that should be avoided per CLAUDE.md guidelines.

💡 Suggestions

  1. CHANGELOG Entry: Per CLAUDE.md, this is a user-visible change and should have a CHANGELOG entry. Consider using the /update-changelog command.
  2. Test Coverage: Consider adding tests for the shell scripts (file path transformation logic, edge cases, etc.)
  3. Performance Metrics: Consider adding timing output to help developers understand hook performance

🔒 Security

Besides the quoting issue mentioned above, the scripts look secure. They properly use bundle exec and don't eval user input.


Summary

This is a solid improvement to the project's developer workflow. The main blockers are:

  1. Shell quoting vulnerabilities (must fix)
  2. Missing set -e in js-lint (must fix)
  3. Pre-push hooks being too heavy (should discuss)

Once these are addressed, this will be a great addition to the project!

@claude
Copy link

claude bot commented Nov 20, 2025

Code Review: Lefthook Migration

I've reviewed this PR that migrates from Husky + lint-staged to Lefthook. Overall, this is a well-structured migration with good improvements. Here are my findings:

✅ Strengths

  1. Well-documented: Excellent PR description with clear motivation and feature parity comparison
  2. Comprehensive migration: All scripts are properly executable and follow bash best practices
  3. Enhanced functionality: Adds Ruby linting and automatic test running that weren't present before
  4. Proper dependency management: Correctly added lefthook to Gemfile.development_dependencies
  5. Good setup documentation: Updated CONTRIBUTING.md and conductor-setup.sh appropriately

🐛 Potential Issues

Critical: Missing trailing newlines in new files

According to CLAUDE.md, "ALWAYS end all files with a trailing newline character." Several new bash scripts appear to be missing this based on the diff:

  • bin/lefthook/check-trailing-newlines
  • bin/lefthook/jest-affected
  • bin/lefthook/js-lint
  • bin/lefthook/prettier-format
  • bin/lefthook/rspec-affected
  • bin/lefthook/rubocop-lint
  • lefthook.yml

Please verify all new files end with a newline character.

Code Quality Issues

1. Quote consistency in spec/dummy/bin/shakapacker-config:

-const { run } = require("shakapacker/configExporter")
+const { run } = require('shakapacker/configExporter')

This change is unrelated to the Lefthook migration and should likely be in a separate commit or PR. If it's intentional, it should be mentioned in the PR description.

2. In bin/lefthook/js-lint - missing set -e:
Unlike the other scripts, this one doesn't have set -e at the top, which means it won't exit on errors. This could lead to silent failures.

3. In bin/lefthook/js-lint - error handling issue:

has_errors=0
yarn eslint --fix $js_ts_files || has_errors=1
yarn prettier --write $js_ts_files || has_errors=1

Both commands will run even if the first fails. This is intentional with || has_errors=1, but may mask which tool actually failed. Consider adding echo statements to clarify which tool failed.

4. Variable quoting in loops:
In several scripts like check-trailing-newlines, jest-affected, etc., the iteration uses:

for file in "$@"; do

This is correct. However, when building the file lists, you're not quoting:

test_files="$test_files $file"  # Good
yarn test --findRelatedTests $test_files  # Should be quoted: "$test_files"

Files with spaces in names could cause issues. Consider using arrays or proper quoting.

5. In bin/lefthook/jest-affected - npm script check is fragile:

if \! grep -q '"test"' package.json; then

This could match "test" anywhere in package.json, not just in scripts. Consider using jq for more robust JSON parsing:

if \! jq -e '.scripts.test' package.json > /dev/null 2>&1; then

6. In bin/lefthook/rspec-affected - path transformation may be incomplete:
The script only handles files in lib/, but what about files in other directories that might have specs? Consider documenting this limitation or handling additional paths.

📊 Performance Considerations

  1. Good: Pre-commit hooks run in parallel, which is a significant improvement
  2. Concern: Pre-push runs full test suite which could be slow. Consider documenting expected runtime or making this opt-in/out
  3. Good: The affected file testing approach in pre-commit is smart and should keep commits fast

🔒 Security Considerations

  1. ✅ All scripts properly validate input (if [ -z "$1" ])
  2. ✅ No obvious command injection vulnerabilities
  3. ⚠️ Scripts re-add files to git automatically (git add). While this is the intended behavior for auto-fixes, it could be surprising to users. Consider documenting this clearly in the setup instructions.

🧪 Test Coverage

  • ⚠️ No tests for the new bash scripts: Consider adding integration tests that verify these hooks work correctly
  • ⚠️ No verification of lefthook configuration: Consider running bundle exec lefthook run pre-commit in CI to verify the configuration is valid

📝 Documentation

  1. ✅ CONTRIBUTING.md updated appropriately
  2. ✅ conductor-setup.sh updated
  3. ⚠️ README.md mentioned in PR but not visible in diff - verify it was actually updated
  4. Missing: No CHANGELOG.md entry. According to CLAUDE.md, this change should have a changelog entry as it's a user-visible change to the development workflow.

💡 Suggestions

  1. Add changelog entry following the format in CLAUDE.md
  2. Add trailing newlines to all new files
  3. Consider adding a .lefthook-local.yml example for developers who want to customize hooks
  4. Add CI verification that runs lefthook run pre-commit to catch config issues
  5. Document the auto-staging behavior more prominently
  6. Consider making pre-push hooks skippable with an environment variable for faster iterations during development

🎯 Overall Assessment

This is a solid improvement to the project's development workflow. The migration is well-thought-out and the new functionality (Ruby linting, automatic test running) is valuable. The main issues are:

  1. Missing trailing newlines (critical per project guidelines)
  2. Missing changelog entry
  3. Minor bash script robustness improvements needed

Once these are addressed, this will be an excellent addition to the project.

Recommendation: Request changes for the critical items (trailing newlines, changelog), approve after fixes.

@claude
Copy link

claude bot commented Nov 20, 2025

Code Review - PR #842: Add Lefthook

This is a well-structured migration from Husky + lint-staged to Lefthook. Overall excellent work!

Strengths

  • Clean separation of concerns with individual hook scripts
  • Well-organized lefthook.yml configuration with parallel execution
  • Maintains feature parity while adding new capabilities
  • Good error handling and clear error messages
  • Comprehensive documentation updates

Critical Issues

1. Missing Trailing Newlines
All new scripts in bin/lefthook/ are missing trailing newlines, which violates project linting rules. Each file needs a newline at the end.

2. Potential Bug in check-trailing-newlines
Using backslash-n in a string may not create actual newlines in all shells. Consider using actual newlines or printf for portability.

3. Unquoted Variable Expansion
Multiple places use unquoted variable expansion (e.g., js_ts_files). Variables should be quoted to handle filenames with spaces.

4. TypeScript Type Checking Issue
The typescript-check command runs on the entire project whenever any TS file is staged. The glob pattern is misleading since yarn type-check doesn't accept file arguments.

5. Style Inconsistency
The quote style change in spec/dummy/bin/shakapacker-config (double to single quotes) is unrelated to Lefthook migration.

Recommendations

  1. Add shellcheck validation for bash scripts
  2. Test all hooks manually before merging
  3. Consider using arrays for file lists instead of space-separated strings
  4. Document pre-push hook performance implications

Testing Needed

  1. Test pre-commit hooks with various file types
  2. Verify auto-fixes work correctly
  3. Test pre-push hooks
  4. Test bypassing hooks with --no-verify
  5. Verify installation script works

Security & Performance

  • No security concerns identified
  • Parallel execution should provide good performance
  • Pre-push full test suite may be slow but acceptable

Action Items

  1. Add trailing newlines to all bin/lefthook/* scripts
  2. Fix variable quoting in shell scripts
  3. Test hooks manually
  4. Run bundle exec lefthook install and verify

Great work on this migration! Lefthook is a solid choice for this project.

@justin808 justin808 added the p2 Medium: enhancements, docs, quality improvements label Feb 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p2 Medium: enhancements, docs, quality improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants