fix(command): skip parent run() when a sub command has run - #254
Conversation
📝 WalkthroughWalkthroughThe PR fixes a bug where parent and subcommand ChangesSubcommand Execution Isolation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
test/main.test.ts (1)
145-182: ⚡ Quick winConsider adding test coverage for default subcommand path.
The implementation sets
ranSubCommand = truefor both explicit subcommands (line 65 in src/command.ts) and default subcommands (line 86). The current tests verify the fix for explicit subcommands and the no-subcommand case, but a test confirming that the parentrun()is skipped when a default subcommand executes would complete the coverage and guard against regressions in that symmetric code path.🧪 Suggested test case
+ it("does not run the parent's run() after a default sub command runs", async () => { + const mainRunMock = vi.fn(); + const defaultSubRunMock = vi.fn(); + + const command = defineCommand({ + run: mainRunMock, + default: "test", + subCommands: { + test: { + run: defaultSubRunMock, + }, + }, + }); + + await runMain(command, { rawArgs: [] }); + + expect(defaultSubRunMock).toHaveBeenCalledOnce(); + expect(mainRunMock).not.toHaveBeenCalled(); + });🤖 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 `@test/main.test.ts` around lines 145 - 182, Add a test that verifies the default subcommand path sets ranSubCommand and prevents the parent run from executing: create a test similar to the explicit-subcommand one but define subCommands with a "default" entry (use defineCommand with run: mainRunMock and subCommands: { default: { run: subRunMock } }), call runMain(command, { rawArgs: [] }) to trigger the default subcommand, and assert subRunMock was calledOnce and mainRunMock was not called to cover the code path where ranSubCommand is set for default subcommands.
🤖 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 `@test/main.test.ts`:
- Around line 145-182: Add a test that verifies the default subcommand path sets
ranSubCommand and prevents the parent run from executing: create a test similar
to the explicit-subcommand one but define subCommands with a "default" entry
(use defineCommand with run: mainRunMock and subCommands: { default: { run:
subRunMock } }), call runMain(command, { rawArgs: [] }) to trigger the default
subcommand, and assert subRunMock was calledOnce and mainRunMock was not called
to cover the code path where ranSubCommand is set for default subcommands.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f76b57fe-ade3-48ac-afcc-50eacbecdc8e
📒 Files selected for processing (2)
src/command.tstest/main.test.ts
Fixes #253
Problem
runCommanddispatches an explicit (or default) sub command and then falls through to the "Handle main command" block, so the parent'srun()executes right after the sub command's:The documented lifecycle is
setup()→ resolve subcommand orrun()→cleanup()(AGENTS.md), and theE_DEFAULT_CONFLICTguard already shows only one action is meant to execute per invocation. The fall-through has been there since the file was created; the existing sub-command test never caught it because its parent command has norun.Fix
Track whether a sub command was dispatched and skip the parent
run()in that case. Parentsetup()/cleanup()still wrap the sub command run, and a parent withrunand no matching sub command arg behaves as before.Tests
does not run the parent's run() after a sub command runsfails onmain(parent run was called) and passes with this change; a second case pins that the parent'srun()still executes when no sub command is given. Fullpnpm test: lint 0 warnings / 0 errors, 111 tests passed, types clean.Summary by CodeRabbit
Bug Fixes
Tests