feat: add interactive multi-repo batch mode#121
Conversation
Add a command that scans a directory for git repositories, identifies those with staged changes, and processes each one in sequence — generating suggestions, committing, and reporting results. - finds all git repos in ./projects - Processes repos with staged changes in sequence - Supports --yes for unattended batch operation (auto-commit first suggestion) - Supports --recursive to search subdirectories for nested repos - Prints clear summary of results per repo (succeeded/skipped/failed) - Skips repos without staged changes with a notice - 13 unit tests covering repo discovery, change detection, and diff retrieval Closes #6 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Need the big picture first? Review this PR in Change Stack to see what changed before going file by file. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a new ChangesBatch Commit Command
Sequence DiagramsequenceDiagram
participant User
participant BatchCmd as batchCommand
participant Finder as findGitRepositories
participant Git as GitRepo
participant LLM as generateSuggestions
participant History as appendEntry
User->>BatchCmd: invoke batch [--recursive] [--yes]
BatchCmd->>Finder: discover repos
BatchCmd->>BatchCmd: load config & validate API key
loop each repo
BatchCmd->>Git: gitHasChanges
alt staged changes
BatchCmd->>Git: getGitDiff (staged)
BatchCmd->>LLM: generateSuggestions(diff, profile)
alt --yes
BatchCmd->>Git: gitCommit(first suggestion)
else interactive
BatchCmd->>User: prompt confirm & select suggestion
opt user confirms
BatchCmd->>Git: gitCommit(selected suggestion)
end
end
BatchCmd->>History: appendEntry(commit metadata)
else skip
BatchCmd->>User: print skipped notice
end
end
BatchCmd->>User: print aggregated summary
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/commands/batch.ts (1)
241-242: 💤 Low valueConsider hoisting
buildProfileoutside the repo loop.
buildProfile(config.historySize)reads from a global history file and is called identically for each repository. Moving it before the loop (alongside config and API key loading) avoids redundant file I/O on every iteration.♻️ Suggested refactor
// Verify API key once let apiKey: string; try { apiKey = assertApiKeyAvailable(config); } catch (err) { outro(pc.red(err instanceof Error ? err.message : 'Missing API key')); return; } + // Build style profile once (shared across all repos) + const profile = await buildProfile(config.historySize); + const results: BatchResult[] = []; for (const repoPath of repos) { // ... inside loop ... - // Build style profile and generate suggestions - const profile = await buildProfile(config.historySize);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/commands/batch.ts` around lines 241 - 242, buildProfile(config.historySize) is being invoked inside the per-repository loop causing redundant file I/O; move the await buildProfile(config.historySize) call to execute once before the repo iteration (alongside config and API key loading), store the returned profile in a variable, and then reference that variable inside the loop (instead of calling buildProfile again). Ensure you await the call before entering the loop and update any local references inside the loop to use the hoisted profile; this touches the buildProfile call and the repository iteration block in src/commands/batch.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/commands/batch.ts`:
- Around line 241-242: buildProfile(config.historySize) is being invoked inside
the per-repository loop causing redundant file I/O; move the await
buildProfile(config.historySize) call to execute once before the repo iteration
(alongside config and API key loading), store the returned profile in a
variable, and then reference that variable inside the loop (instead of calling
buildProfile again). Ensure you await the call before entering the loop and
update any local references inside the loop to use the hoisted profile; this
touches the buildProfile call and the repository iteration block in
src/commands/batch.ts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 86246d53-27d6-45d7-9fca-0214a1b53933
📒 Files selected for processing (3)
src/commands/batch.tssrc/index.tstests/batch.test.mjs
buildProfile(config.historySize) was called inside the per-repository loop, causing redundant file I/O (reading + parsing the full commit history file) once per repo. Move it before the loop so it executes once, and the cached profile is reused across all repos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== src/commands/batch.ts ==="
cat src/commands/batch.ts
echo ""
echo "=== src/index.ts (last 60 lines) ==="
tail -60 src/index.ts
echo ""
echo "=== tests/batch.test.mjs ==="
cat tests/batch.test.mjsLength of output: 22391
🐛 Issues1.
|
- check if rootDir itself is a git repo before scanning children - bump getGitDiff maxBuffer to 100 MB for large monorepo diffs - wrap readdirSync with try/catch to skip unreadable directories - relax gitCommit regex to match detached HEAD output - add optional body prompt in interactive batch mode (consistent UX) - export gitCommit and add unit tests (message, body, empty commit) - add tests for rootDir-as-repo edge case Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Tip For best results, initiate chat on the files or code changes.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/batch.test.mjs (1)
278-293: 💤 Low valueConsider relaxing the hash length assertion.
The assertion on line 288 checks for exactly 7 characters, but Git's abbreviated hash can be longer (7+) to ensure uniqueness. While this test will pass consistently in a fresh repo with few commits, a more robust assertion would verify the hash is valid hex rather than a specific length.
♻️ Optional: Make the assertion more flexible
- assert.equal(result.hash.length, 7); + assert.ok(result.hash.length >= 7); + assert.match(result.hash, /^[a-f0-9]+$/);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/batch.test.mjs` around lines 278 - 293, The test 'gitCommit creates a commit and returns hash and summary' asserts result.hash.length === 7 which is too strict; update the assertion on result.hash (from gitCommit) to allow variable-length abbreviated hashes by checking it is a hex string and at least 7 characters long (e.g., assert.ok(/^[0-9a-f]+$/.test(result.hash)) and assert.ok(result.hash.length >= 7)) and keep the summary assertion unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/batch.test.mjs`:
- Around line 278-293: The test 'gitCommit creates a commit and returns hash and
summary' asserts result.hash.length === 7 which is too strict; update the
assertion on result.hash (from gitCommit) to allow variable-length abbreviated
hashes by checking it is a hex string and at least 7 characters long (e.g.,
assert.ok(/^[0-9a-f]+$/.test(result.hash)) and assert.ok(result.hash.length >=
7)) and keep the summary assertion unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 77965044-7b6b-4344-8036-1855e5ae0078
📒 Files selected for processing (2)
src/commands/batch.tstests/batch.test.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
- src/commands/batch.ts
assert.equal(result.hash.length, 7) was brittle — Git abbreviated hashes can exceed 7 characters depending on repository size. Replace with a hex regex check and a minimum-length assertion (≥7), which matches Git's shortest-prefix behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
Adds a
commit-echo batch <directory>command that scans a directory for git repositories, identifies those with staged changes, and processes each one in sequence — generating suggestions, committing, and reporting results.Closes #6
Key features
commit-echo batch— scans current directory for git repos with staged changescommit-echo batch ./projects— scans a specific directorycommit-echo batch --recursive— searches subdirectories for nested reposcommit-echo batch --yes— unattended mode (auto-commits first suggestion per repo without prompts)Architecture
findGitRepositories,gitHasChanges,getGitDiff,gitCommit)generateSuggestions/buildProfile/appendEntryfrom the codebasecwdparameter instead ofprocess.chdir()--yes/--autoflags respect both local and global (program-level) optionsTesting
Commits
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests