@camaradesuk/git-worktree-tools 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -27
- package/dist/cli/cleanpr.js +74 -53
- package/dist/cli/cleanpr.js.map +1 -1
- package/dist/cli/cleanpr.test.js +2 -0
- package/dist/cli/cleanpr.test.js.map +1 -1
- package/dist/cli/lswt.js +32 -56
- package/dist/cli/lswt.js.map +1 -1
- package/dist/cli/lswt.test.js +17 -27
- package/dist/cli/lswt.test.js.map +1 -1
- package/dist/cli/newpr.d.ts +13 -1
- package/dist/cli/newpr.d.ts.map +1 -1
- package/dist/cli/newpr.js +350 -151
- package/dist/cli/newpr.js.map +1 -1
- package/dist/cli/newpr.test.js +314 -5
- package/dist/cli/newpr.test.js.map +1 -1
- package/dist/cli/prs.d.ts +3 -10
- package/dist/cli/prs.d.ts.map +1 -1
- package/dist/cli/prs.js +6 -168
- package/dist/cli/prs.js.map +1 -1
- package/dist/cli/prs.test.js +55 -0
- package/dist/cli/prs.test.js.map +1 -1
- package/dist/cli/wt/clean.d.ts +6 -2
- package/dist/cli/wt/clean.d.ts.map +1 -1
- package/dist/cli/wt/clean.js +401 -20
- package/dist/cli/wt/clean.js.map +1 -1
- package/dist/cli/wt/clean.test.d.ts +8 -0
- package/dist/cli/wt/clean.test.d.ts.map +1 -0
- package/dist/cli/wt/clean.test.js +624 -0
- package/dist/cli/wt/clean.test.js.map +1 -0
- package/dist/cli/wt/completion.d.ts +3 -0
- package/dist/cli/wt/completion.d.ts.map +1 -1
- package/dist/cli/wt/completion.js +80 -9
- package/dist/cli/wt/completion.js.map +1 -1
- package/dist/cli/wt/completion.test.js +102 -0
- package/dist/cli/wt/completion.test.js.map +1 -1
- package/dist/cli/wt/config.d.ts +3 -1
- package/dist/cli/wt/config.d.ts.map +1 -1
- package/dist/cli/wt/config.js +323 -32
- package/dist/cli/wt/config.js.map +1 -1
- package/dist/cli/wt/config.test.d.ts +2 -0
- package/dist/cli/wt/config.test.d.ts.map +1 -1
- package/dist/cli/wt/config.test.js +206 -26
- package/dist/cli/wt/config.test.js.map +1 -1
- package/dist/cli/wt/interactive-menu.d.ts +2 -0
- package/dist/cli/wt/interactive-menu.d.ts.map +1 -1
- package/dist/cli/wt/interactive-menu.js +346 -73
- package/dist/cli/wt/interactive-menu.js.map +1 -1
- package/dist/cli/wt/interactive-menu.test.d.ts +4 -2
- package/dist/cli/wt/interactive-menu.test.d.ts.map +1 -1
- package/dist/cli/wt/interactive-menu.test.js +383 -323
- package/dist/cli/wt/interactive-menu.test.js.map +1 -1
- package/dist/cli/wt/link.d.ts +3 -1
- package/dist/cli/wt/link.d.ts.map +1 -1
- package/dist/cli/wt/link.js +125 -38
- package/dist/cli/wt/link.js.map +1 -1
- package/dist/cli/wt/list.d.ts +4 -1
- package/dist/cli/wt/list.d.ts.map +1 -1
- package/dist/cli/wt/list.js +85 -16
- package/dist/cli/wt/list.js.map +1 -1
- package/dist/cli/wt/list.test.d.ts +10 -0
- package/dist/cli/wt/list.test.d.ts.map +1 -0
- package/dist/cli/wt/list.test.js +157 -0
- package/dist/cli/wt/list.test.js.map +1 -0
- package/dist/cli/wt/new.d.ts +8 -2
- package/dist/cli/wt/new.d.ts.map +1 -1
- package/dist/cli/wt/new.js +91 -46
- package/dist/cli/wt/new.js.map +1 -1
- package/dist/cli/wt/prs.d.ts +2 -1
- package/dist/cli/wt/prs.d.ts.map +1 -1
- package/dist/cli/wt/prs.js +3 -164
- package/dist/cli/wt/prs.js.map +1 -1
- package/dist/cli/wt/run-command.d.ts +4 -2
- package/dist/cli/wt/run-command.d.ts.map +1 -1
- package/dist/cli/wt/run-command.js +6 -4
- package/dist/cli/wt/run-command.js.map +1 -1
- package/dist/cli/wt/state.d.ts +3 -1
- package/dist/cli/wt/state.d.ts.map +1 -1
- package/dist/cli/wt/state.js +74 -10
- package/dist/cli/wt/state.js.map +1 -1
- package/dist/cli/wt/state.test.d.ts +9 -0
- package/dist/cli/wt/state.test.d.ts.map +1 -0
- package/dist/cli/wt/state.test.js +127 -0
- package/dist/cli/wt/state.test.js.map +1 -0
- package/dist/cli/wt/wt.test.d.ts +2 -2
- package/dist/cli/wt/wt.test.js +430 -212
- package/dist/cli/wt/wt.test.js.map +1 -1
- package/dist/cli/wt.d.ts.map +1 -1
- package/dist/cli/wt.js +50 -36
- package/dist/cli/wt.js.map +1 -1
- package/dist/cli/wt.unit.test.js +16 -38
- package/dist/cli/wt.unit.test.js.map +1 -1
- package/dist/cli/wtconfig.d.ts +1 -0
- package/dist/cli/wtconfig.d.ts.map +1 -1
- package/dist/cli/wtconfig.js +213 -21
- package/dist/cli/wtconfig.js.map +1 -1
- package/dist/cli/wtconfig.test.js +3 -0
- package/dist/cli/wtconfig.test.js.map +1 -1
- package/dist/cli/wtlink.js +116 -73
- package/dist/cli/wtlink.js.map +1 -1
- package/dist/cli/wtstate.js +21 -2
- package/dist/cli/wtstate.js.map +1 -1
- package/dist/e2e/wt/interactive-menu.e2e.test.js +17 -17
- package/dist/e2e/wt/interactive-menu.e2e.test.js.map +1 -1
- package/dist/lib/ai/types.d.ts +12 -0
- package/dist/lib/ai/types.d.ts.map +1 -1
- package/dist/lib/ai/types.js.map +1 -1
- package/dist/lib/cleanpr/args.d.ts.map +1 -1
- package/dist/lib/cleanpr/args.js +20 -0
- package/dist/lib/cleanpr/args.js.map +1 -1
- package/dist/lib/cleanpr/types.d.ts +6 -0
- package/dist/lib/cleanpr/types.d.ts.map +1 -1
- package/dist/lib/cleanpr/worktree-info.d.ts.map +1 -1
- package/dist/lib/cleanpr/worktree-info.js +1 -6
- package/dist/lib/cleanpr/worktree-info.js.map +1 -1
- package/dist/lib/cleanpr/worktree-info.test.js +10 -13
- package/dist/lib/cleanpr/worktree-info.test.js.map +1 -1
- package/dist/lib/colors.d.ts +5 -0
- package/dist/lib/colors.d.ts.map +1 -1
- package/dist/lib/colors.js +13 -6
- package/dist/lib/colors.js.map +1 -1
- package/dist/lib/config-editor.d.ts.map +1 -1
- package/dist/lib/config-editor.js.map +1 -1
- package/dist/lib/config-migration/detector.d.ts +25 -0
- package/dist/lib/config-migration/detector.d.ts.map +1 -0
- package/dist/lib/config-migration/detector.js +372 -0
- package/dist/lib/config-migration/detector.js.map +1 -0
- package/dist/lib/config-migration/detector.test.d.ts +5 -0
- package/dist/lib/config-migration/detector.test.d.ts.map +1 -0
- package/dist/lib/config-migration/detector.test.js +201 -0
- package/dist/lib/config-migration/detector.test.js.map +1 -0
- package/dist/lib/config-migration/index.d.ts +29 -0
- package/dist/lib/config-migration/index.d.ts.map +1 -0
- package/dist/lib/config-migration/index.js +33 -0
- package/dist/lib/config-migration/index.js.map +1 -0
- package/dist/lib/config-migration/reporter.d.ts +53 -0
- package/dist/lib/config-migration/reporter.d.ts.map +1 -0
- package/dist/lib/config-migration/reporter.js +257 -0
- package/dist/lib/config-migration/reporter.js.map +1 -0
- package/dist/lib/config-migration/reporter.test.d.ts +5 -0
- package/dist/lib/config-migration/reporter.test.d.ts.map +1 -0
- package/dist/lib/config-migration/reporter.test.js +305 -0
- package/dist/lib/config-migration/reporter.test.js.map +1 -0
- package/dist/lib/config-migration/runner.d.ts +46 -0
- package/dist/lib/config-migration/runner.d.ts.map +1 -0
- package/dist/lib/config-migration/runner.js +364 -0
- package/dist/lib/config-migration/runner.js.map +1 -0
- package/dist/lib/config-migration/runner.test.d.ts +5 -0
- package/dist/lib/config-migration/runner.test.d.ts.map +1 -0
- package/dist/lib/config-migration/runner.test.js +235 -0
- package/dist/lib/config-migration/runner.test.js.map +1 -0
- package/dist/lib/config-migration/types.d.ts +120 -0
- package/dist/lib/config-migration/types.d.ts.map +1 -0
- package/dist/lib/config-migration/types.js +70 -0
- package/dist/lib/config-migration/types.js.map +1 -0
- package/dist/lib/config-validation.d.ts.map +1 -1
- package/dist/lib/config-validation.js +6 -0
- package/dist/lib/config-validation.js.map +1 -1
- package/dist/lib/config-validation.test.js +25 -0
- package/dist/lib/config-validation.test.js.map +1 -1
- package/dist/lib/config.d.ts +31 -7
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +2 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.js +3 -15
- package/dist/lib/config.test.js.map +1 -1
- package/dist/lib/constants.d.ts +12 -4
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +24 -5
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/constants.test.js +88 -29
- package/dist/lib/constants.test.js.map +1 -1
- package/dist/lib/deprecation.d.ts +18 -0
- package/dist/lib/deprecation.d.ts.map +1 -0
- package/dist/lib/deprecation.js +28 -0
- package/dist/lib/deprecation.js.map +1 -0
- package/dist/lib/deprecation.test.d.ts +2 -0
- package/dist/lib/deprecation.test.d.ts.map +1 -0
- package/dist/lib/deprecation.test.js +71 -0
- package/dist/lib/deprecation.test.js.map +1 -0
- package/dist/lib/hooks/confirmation.d.ts +49 -0
- package/dist/lib/hooks/confirmation.d.ts.map +1 -0
- package/dist/lib/hooks/confirmation.js +147 -0
- package/dist/lib/hooks/confirmation.js.map +1 -0
- package/dist/lib/hooks/confirmation.test.d.ts +7 -0
- package/dist/lib/hooks/confirmation.test.d.ts.map +1 -0
- package/dist/lib/hooks/confirmation.test.js +300 -0
- package/dist/lib/hooks/confirmation.test.js.map +1 -0
- package/dist/lib/hooks/executor.d.ts +16 -1
- package/dist/lib/hooks/executor.d.ts.map +1 -1
- package/dist/lib/hooks/executor.js +53 -4
- package/dist/lib/hooks/executor.js.map +1 -1
- package/dist/lib/hooks/index.d.ts +4 -2
- package/dist/lib/hooks/index.d.ts.map +1 -1
- package/dist/lib/hooks/index.js +3 -2
- package/dist/lib/hooks/index.js.map +1 -1
- package/dist/lib/hooks/types.d.ts +16 -0
- package/dist/lib/hooks/types.d.ts.map +1 -1
- package/dist/lib/hooks/types.js +12 -0
- package/dist/lib/hooks/types.js.map +1 -1
- package/dist/lib/logger.d.ts +40 -155
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +349 -420
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/logger.test.d.ts +10 -1
- package/dist/lib/logger.test.d.ts.map +1 -1
- package/dist/lib/logger.test.js +658 -258
- package/dist/lib/logger.test.js.map +1 -1
- package/dist/lib/lswt/action-executors.d.ts +2 -0
- package/dist/lib/lswt/action-executors.d.ts.map +1 -1
- package/dist/lib/lswt/action-executors.js +4 -3
- package/dist/lib/lswt/action-executors.js.map +1 -1
- package/dist/lib/lswt/action-executors.test.js +7 -0
- package/dist/lib/lswt/action-executors.test.js.map +1 -1
- package/dist/lib/lswt/args.d.ts.map +1 -1
- package/dist/lib/lswt/args.js +15 -1
- package/dist/lib/lswt/args.js.map +1 -1
- package/dist/lib/lswt/environment.d.ts +21 -2
- package/dist/lib/lswt/environment.d.ts.map +1 -1
- package/dist/lib/lswt/environment.js +73 -32
- package/dist/lib/lswt/environment.js.map +1 -1
- package/dist/lib/lswt/environment.test.js +79 -1
- package/dist/lib/lswt/environment.test.js.map +1 -1
- package/dist/lib/lswt/index.d.ts +1 -0
- package/dist/lib/lswt/index.d.ts.map +1 -1
- package/dist/lib/lswt/index.js +2 -0
- package/dist/lib/lswt/index.js.map +1 -1
- package/dist/lib/lswt/table.d.ts +15 -0
- package/dist/lib/lswt/table.d.ts.map +1 -0
- package/dist/lib/lswt/table.js +61 -0
- package/dist/lib/lswt/table.js.map +1 -0
- package/dist/lib/lswt/table.test.d.ts +5 -0
- package/dist/lib/lswt/table.test.d.ts.map +1 -0
- package/dist/lib/lswt/table.test.js +262 -0
- package/dist/lib/lswt/table.test.js.map +1 -0
- package/dist/lib/lswt/types.d.ts +4 -0
- package/dist/lib/lswt/types.d.ts.map +1 -1
- package/dist/lib/lswt/worktree-info.d.ts.map +1 -1
- package/dist/lib/lswt/worktree-info.js +1 -6
- package/dist/lib/lswt/worktree-info.js.map +1 -1
- package/dist/lib/lswt/worktree-info.test.js +5 -17
- package/dist/lib/lswt/worktree-info.test.js.map +1 -1
- package/dist/lib/newpr/args.d.ts.map +1 -1
- package/dist/lib/newpr/args.js +36 -1
- package/dist/lib/newpr/args.js.map +1 -1
- package/dist/lib/newpr/hook-runner.d.ts +11 -0
- package/dist/lib/newpr/hook-runner.d.ts.map +1 -1
- package/dist/lib/newpr/hook-runner.js +49 -1
- package/dist/lib/newpr/hook-runner.js.map +1 -1
- package/dist/lib/newpr/hook-runner.test.js +121 -0
- package/dist/lib/newpr/hook-runner.test.js.map +1 -1
- package/dist/lib/newpr/plan-generator.d.ts +121 -0
- package/dist/lib/newpr/plan-generator.d.ts.map +1 -0
- package/dist/lib/newpr/plan-generator.js +185 -0
- package/dist/lib/newpr/plan-generator.js.map +1 -0
- package/dist/lib/newpr/plan-generator.test.d.ts +7 -0
- package/dist/lib/newpr/plan-generator.test.d.ts.map +1 -0
- package/dist/lib/newpr/plan-generator.test.js +387 -0
- package/dist/lib/newpr/plan-generator.test.js.map +1 -0
- package/dist/lib/newpr/types.d.ts +12 -0
- package/dist/lib/newpr/types.d.ts.map +1 -1
- package/dist/lib/prs/actions.d.ts +5 -1
- package/dist/lib/prs/actions.d.ts.map +1 -1
- package/dist/lib/prs/actions.js +12 -10
- package/dist/lib/prs/actions.js.map +1 -1
- package/dist/lib/prs/actions.test.js +48 -5
- package/dist/lib/prs/actions.test.js.map +1 -1
- package/dist/lib/prs/command.d.ts +21 -0
- package/dist/lib/prs/command.d.ts.map +1 -0
- package/dist/lib/prs/command.js +175 -0
- package/dist/lib/prs/command.js.map +1 -0
- package/dist/lib/prs/command.test.d.ts +11 -0
- package/dist/lib/prs/command.test.d.ts.map +1 -0
- package/dist/lib/prs/command.test.js +409 -0
- package/dist/lib/prs/command.test.js.map +1 -0
- package/dist/lib/prs/interactive.d.ts.map +1 -1
- package/dist/lib/prs/interactive.js +15 -2
- package/dist/lib/prs/interactive.js.map +1 -1
- package/dist/lib/prs/interactive.test.js +153 -0
- package/dist/lib/prs/interactive.test.js.map +1 -1
- package/dist/lib/prs/types.d.ts +15 -0
- package/dist/lib/prs/types.d.ts.map +1 -1
- package/dist/lib/ui/error.d.ts +31 -0
- package/dist/lib/ui/error.d.ts.map +1 -0
- package/dist/lib/ui/error.js +47 -0
- package/dist/lib/ui/error.js.map +1 -0
- package/dist/lib/ui/error.test.d.ts +2 -0
- package/dist/lib/ui/error.test.d.ts.map +1 -0
- package/dist/lib/ui/error.test.js +143 -0
- package/dist/lib/ui/error.test.js.map +1 -0
- package/dist/lib/ui/index.d.ts +15 -0
- package/dist/lib/ui/index.d.ts.map +1 -0
- package/dist/lib/ui/index.js +19 -0
- package/dist/lib/ui/index.js.map +1 -0
- package/dist/lib/ui/output.d.ts +18 -0
- package/dist/lib/ui/output.d.ts.map +1 -0
- package/dist/lib/ui/output.js +31 -0
- package/dist/lib/ui/output.js.map +1 -0
- package/dist/lib/ui/output.test.d.ts +2 -0
- package/dist/lib/ui/output.test.d.ts.map +1 -0
- package/dist/lib/ui/output.test.js +59 -0
- package/dist/lib/ui/output.test.js.map +1 -0
- package/dist/lib/ui/spinner.d.ts +10 -0
- package/dist/lib/ui/spinner.d.ts.map +1 -0
- package/dist/lib/ui/spinner.js +10 -0
- package/dist/lib/ui/spinner.js.map +1 -0
- package/dist/lib/ui/status.d.ts +65 -0
- package/dist/lib/ui/status.d.ts.map +1 -0
- package/dist/lib/ui/status.js +100 -0
- package/dist/lib/ui/status.js.map +1 -0
- package/dist/lib/ui/status.test.d.ts +2 -0
- package/dist/lib/ui/status.test.d.ts.map +1 -0
- package/dist/lib/ui/status.test.js +158 -0
- package/dist/lib/ui/status.test.js.map +1 -0
- package/dist/lib/ui/table.d.ts +39 -0
- package/dist/lib/ui/table.d.ts.map +1 -0
- package/dist/lib/ui/table.js +45 -0
- package/dist/lib/ui/table.js.map +1 -0
- package/dist/lib/ui/table.test.d.ts +2 -0
- package/dist/lib/ui/table.test.d.ts.map +1 -0
- package/dist/lib/ui/table.test.js +115 -0
- package/dist/lib/ui/table.test.js.map +1 -0
- package/dist/lib/ui/theme.d.ts +34 -0
- package/dist/lib/ui/theme.d.ts.map +1 -0
- package/dist/lib/ui/theme.js +37 -0
- package/dist/lib/ui/theme.js.map +1 -0
- package/dist/lib/ui/theme.test.d.ts +2 -0
- package/dist/lib/ui/theme.test.d.ts.map +1 -0
- package/dist/lib/ui/theme.test.js +76 -0
- package/dist/lib/ui/theme.test.js.map +1 -0
- package/dist/lib/wtconfig/environment.d.ts +18 -1
- package/dist/lib/wtconfig/environment.d.ts.map +1 -1
- package/dist/lib/wtconfig/environment.js +60 -24
- package/dist/lib/wtconfig/environment.js.map +1 -1
- package/dist/lib/wtconfig/environment.test.js +45 -1
- package/dist/lib/wtconfig/environment.test.js.map +1 -1
- package/dist/lib/wtlink/config-manifest.test.js +26 -0
- package/dist/lib/wtlink/config-manifest.test.js.map +1 -1
- package/dist/lib/wtlink/link-configs.js +7 -7
- package/dist/lib/wtlink/link-configs.js.map +1 -1
- package/dist/lib/wtlink/validate-manifest.d.ts.map +1 -1
- package/dist/lib/wtlink/validate-manifest.js +5 -5
- package/dist/lib/wtlink/validate-manifest.js.map +1 -1
- package/dist/lib/wtstate/args.d.ts.map +1 -1
- package/dist/lib/wtstate/args.js +2 -0
- package/dist/lib/wtstate/args.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +264 -44
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/server.test.js +111 -0
- package/dist/mcp/server.test.js.map +1 -1
- package/package.json +3 -1
- package/schemas/worktreerc.schema.json +23 -0
package/dist/cli/wt/wt.test.js
CHANGED
|
@@ -1,12 +1,180 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for wt unified command handlers
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* All commands are migrated to direct library calls (list, state, clean, new, link)
|
|
5
|
+
* and tested by mocking the library modules they call.
|
|
6
6
|
*/
|
|
7
7
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
8
8
|
import { spawnSync } from 'child_process';
|
|
9
9
|
import yargs from 'yargs';
|
|
10
|
+
vi.mock('child_process', () => ({
|
|
11
|
+
spawnSync: vi.fn(() => ({ status: 0 })),
|
|
12
|
+
execSync: vi.fn(),
|
|
13
|
+
}));
|
|
14
|
+
// Mock newpr.ts for new command (direct library call)
|
|
15
|
+
vi.mock('../newpr.js', () => ({
|
|
16
|
+
runNewprHandler: vi.fn().mockResolvedValue(undefined),
|
|
17
|
+
}));
|
|
18
|
+
// Mock library dependencies for list command (direct library calls)
|
|
19
|
+
vi.mock('../../lib/lswt/index.js', () => ({
|
|
20
|
+
gatherWorktreeInfo: vi.fn().mockResolvedValue([]),
|
|
21
|
+
createDefaultDeps: vi.fn().mockReturnValue({}),
|
|
22
|
+
formatJsonOutput: vi.fn().mockReturnValue('[]'),
|
|
23
|
+
runInteractiveMode: vi.fn().mockResolvedValue(undefined),
|
|
24
|
+
printWorktreeTable: vi.fn(),
|
|
25
|
+
parseArgs: vi.fn(),
|
|
26
|
+
getHelpText: vi.fn(),
|
|
27
|
+
formatTypeLabel: vi.fn(),
|
|
28
|
+
getDisplayPath: vi.fn(),
|
|
29
|
+
sortWorktrees: vi.fn(),
|
|
30
|
+
extractPrNumber: vi.fn(),
|
|
31
|
+
isMainWorktree: vi.fn(),
|
|
32
|
+
}));
|
|
33
|
+
// Mock library dependencies for state command (direct library calls)
|
|
34
|
+
vi.mock('../../lib/wtstate/index.js', () => ({
|
|
35
|
+
analyzeState: vi.fn().mockReturnValue({
|
|
36
|
+
scenario: 'main_clean_same',
|
|
37
|
+
scenarioDescription: 'On main branch, same as origin/main, no changes',
|
|
38
|
+
currentBranch: 'main',
|
|
39
|
+
baseBranch: 'main',
|
|
40
|
+
worktreeType: 'main_worktree',
|
|
41
|
+
hasChanges: false,
|
|
42
|
+
hasStagedChanges: false,
|
|
43
|
+
hasUnstagedChanges: false,
|
|
44
|
+
localCommits: [],
|
|
45
|
+
stagedFiles: [],
|
|
46
|
+
unstagedFiles: [],
|
|
47
|
+
availableActions: [],
|
|
48
|
+
recommendedAction: null,
|
|
49
|
+
}),
|
|
50
|
+
formatText: vi.fn().mockReturnValue('State: main_clean_same'),
|
|
51
|
+
parseArgs: vi.fn(),
|
|
52
|
+
getHelpText: vi.fn(),
|
|
53
|
+
getDefaultOptions: vi.fn(),
|
|
54
|
+
}));
|
|
55
|
+
// Mock library dependencies for clean command (direct library calls)
|
|
56
|
+
vi.mock('../../lib/cleanpr/index.js', () => ({
|
|
57
|
+
gatherPrWorktreeInfo: vi.fn().mockResolvedValue([]),
|
|
58
|
+
createDefaultDeps: vi.fn().mockReturnValue({}),
|
|
59
|
+
groupWorktreesByState: vi.fn().mockReturnValue({ merged: [], closed: [], open: [], unknown: [] }),
|
|
60
|
+
getCleanableWorktrees: vi.fn().mockReturnValue([]),
|
|
61
|
+
findWorktreeByPrNumber: vi.fn().mockReturnValue(null),
|
|
62
|
+
cleanWorktree: vi.fn().mockReturnValue({
|
|
63
|
+
success: true,
|
|
64
|
+
prNumber: 42,
|
|
65
|
+
message: 'Cleaned',
|
|
66
|
+
localBranchDeleted: true,
|
|
67
|
+
remoteBranchDeleted: false,
|
|
68
|
+
}),
|
|
69
|
+
summarizeResults: vi.fn().mockReturnValue({ cleaned: 0, total: 0, failed: 0 }),
|
|
70
|
+
}));
|
|
71
|
+
// Mock config module for clean command
|
|
72
|
+
vi.mock('../../lib/config.js', () => ({
|
|
73
|
+
loadConfig: vi.fn().mockReturnValue({ worktreePattern: '{repo}.pr{number}', baseBranch: 'main' }),
|
|
74
|
+
loadConfigWithValidation: vi.fn().mockReturnValue({ config: {}, validation: null }),
|
|
75
|
+
getDefaultConfig: vi.fn().mockReturnValue({}),
|
|
76
|
+
getConfigPath: vi.fn().mockReturnValue(null),
|
|
77
|
+
}));
|
|
78
|
+
// Mock logger for clean command
|
|
79
|
+
vi.mock('../../lib/logger.js', () => ({
|
|
80
|
+
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
81
|
+
}));
|
|
82
|
+
// Mock prompts module for clean command
|
|
83
|
+
vi.mock('../../lib/prompts.js', () => ({
|
|
84
|
+
withSpinner: vi.fn((_msg, fn) => fn()),
|
|
85
|
+
promptChoice: vi.fn(),
|
|
86
|
+
promptConfirm: vi.fn(),
|
|
87
|
+
}));
|
|
88
|
+
// Mock colors module for clean command
|
|
89
|
+
vi.mock('../../lib/colors.js', () => ({
|
|
90
|
+
error: vi.fn((s) => s),
|
|
91
|
+
dim: vi.fn((s) => s),
|
|
92
|
+
success: vi.fn((s) => s),
|
|
93
|
+
info: vi.fn((s) => s),
|
|
94
|
+
cyan: vi.fn((s) => s),
|
|
95
|
+
yellow: vi.fn((s) => s),
|
|
96
|
+
red: vi.fn((s) => s),
|
|
97
|
+
green: vi.fn((s) => s),
|
|
98
|
+
bold: vi.fn((s) => s),
|
|
99
|
+
warning: vi.fn((s) => s),
|
|
100
|
+
}));
|
|
101
|
+
// Mock config-editor for config command
|
|
102
|
+
vi.mock('../../lib/config-editor.js', () => ({
|
|
103
|
+
runConfigEditor: vi.fn().mockResolvedValue({ saved: false }),
|
|
104
|
+
quickEditConfig: vi.fn().mockResolvedValue({ saved: false }),
|
|
105
|
+
}));
|
|
106
|
+
// Mock config-validation for config command
|
|
107
|
+
vi.mock('../../lib/config-validation.js', () => ({
|
|
108
|
+
formatValidationErrors: vi.fn().mockReturnValue('formatted errors'),
|
|
109
|
+
}));
|
|
110
|
+
// Mock global-config for config command
|
|
111
|
+
vi.mock('../../lib/global-config.js', () => ({
|
|
112
|
+
getSchemaUrl: vi.fn().mockReturnValue('https://example.com/schema.json'),
|
|
113
|
+
}));
|
|
114
|
+
// Mock library dependencies for link command (direct library calls)
|
|
115
|
+
vi.mock('../../lib/wtlink/manage-manifest.js', () => ({
|
|
116
|
+
run: vi.fn().mockResolvedValue(undefined),
|
|
117
|
+
}));
|
|
118
|
+
vi.mock('../../lib/wtlink/link-configs.js', () => ({
|
|
119
|
+
run: vi.fn().mockResolvedValue(undefined),
|
|
120
|
+
}));
|
|
121
|
+
vi.mock('../../lib/wtlink/validate-manifest.js', () => ({
|
|
122
|
+
run: vi.fn(),
|
|
123
|
+
}));
|
|
124
|
+
vi.mock('../../lib/wtlink/main-menu.js', () => ({
|
|
125
|
+
showMainMenu: vi.fn().mockResolvedValue(undefined),
|
|
126
|
+
}));
|
|
127
|
+
vi.mock('../../lib/wtlink/config-manifest.js', () => ({
|
|
128
|
+
hasLegacyManifest: vi.fn().mockReturnValue(false),
|
|
129
|
+
}));
|
|
130
|
+
vi.mock('../../lib/config-migration/index.js', () => ({
|
|
131
|
+
detectMigrationIssues: vi.fn().mockReturnValue({ issues: [] }),
|
|
132
|
+
runMigration: vi.fn().mockResolvedValue({ success: true, errors: [] }),
|
|
133
|
+
formatMigrationReport: vi.fn().mockReturnValue(''),
|
|
134
|
+
}));
|
|
135
|
+
vi.mock('../../lib/errors.js', () => ({
|
|
136
|
+
ManifestError: class ManifestError extends Error {
|
|
137
|
+
issues;
|
|
138
|
+
constructor(message, issues) {
|
|
139
|
+
super(message);
|
|
140
|
+
this.name = 'ManifestError';
|
|
141
|
+
this.issues = issues;
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
}));
|
|
145
|
+
// Mock git module for list/state/clean/link handlers
|
|
146
|
+
vi.mock('../../lib/git.js', () => ({
|
|
147
|
+
getRepoRoot: vi.fn().mockReturnValue('/fake/repo'),
|
|
148
|
+
getMainWorktreeRoot: vi.fn().mockReturnValue('/fake/repo'),
|
|
149
|
+
removeWorktree: vi.fn(),
|
|
150
|
+
pruneWorktrees: vi.fn(),
|
|
151
|
+
}));
|
|
152
|
+
// Mock github module for list/clean handlers
|
|
153
|
+
vi.mock('../../lib/github.js', () => ({
|
|
154
|
+
isGhInstalled: vi.fn().mockReturnValue(true),
|
|
155
|
+
}));
|
|
156
|
+
// Mock UI module for all handlers
|
|
157
|
+
vi.mock('../../lib/ui/index.js', () => ({
|
|
158
|
+
setJsonMode: vi.fn(),
|
|
159
|
+
isJsonMode: vi.fn().mockReturnValue(false),
|
|
160
|
+
printStatus: vi.fn(),
|
|
161
|
+
printDim: vi.fn(),
|
|
162
|
+
printError: vi.fn(),
|
|
163
|
+
printHeader: vi.fn(),
|
|
164
|
+
printNextSteps: vi.fn(),
|
|
165
|
+
changeIndicator: vi.fn().mockReturnValue(''),
|
|
166
|
+
errorToDisplay: vi.fn().mockReturnValue({ title: 'error' }),
|
|
167
|
+
}));
|
|
168
|
+
// Mock json-output module (partial mock to preserve exports for all command handlers)
|
|
169
|
+
vi.mock('../../lib/json-output.js', async (importOriginal) => {
|
|
170
|
+
const actual = await importOriginal();
|
|
171
|
+
return {
|
|
172
|
+
...actual,
|
|
173
|
+
createSuccessResult: vi.fn().mockReturnValue({ success: true }),
|
|
174
|
+
createErrorResult: vi.fn().mockReturnValue({ success: false }),
|
|
175
|
+
formatJsonResult: vi.fn().mockReturnValue('{}'),
|
|
176
|
+
};
|
|
177
|
+
});
|
|
10
178
|
// Import all commands statically so coverage is tracked
|
|
11
179
|
import { newCommand } from './new.js';
|
|
12
180
|
import { listCommand } from './list.js';
|
|
@@ -14,15 +182,24 @@ import { cleanCommand } from './clean.js';
|
|
|
14
182
|
import { stateCommand } from './state.js';
|
|
15
183
|
import { configCommand } from './config.js';
|
|
16
184
|
import { linkCommand } from './link.js';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
185
|
+
// Import mocked modules for assertions
|
|
186
|
+
import { gatherWorktreeInfo, printWorktreeTable, formatJsonOutput } from '../../lib/lswt/index.js';
|
|
187
|
+
import { analyzeState, formatText } from '../../lib/wtstate/index.js';
|
|
188
|
+
import { gatherPrWorktreeInfo, getCleanableWorktrees } from '../../lib/cleanpr/index.js';
|
|
189
|
+
import { setJsonMode, printError } from '../../lib/ui/index.js';
|
|
190
|
+
import { createSuccessResult, formatJsonResult } from '../../lib/json-output.js';
|
|
191
|
+
import { runNewprHandler } from '../newpr.js';
|
|
192
|
+
import { run as manageRun } from '../../lib/wtlink/manage-manifest.js';
|
|
193
|
+
import { run as linkRun } from '../../lib/wtlink/link-configs.js';
|
|
194
|
+
import { run as validateRun } from '../../lib/wtlink/validate-manifest.js';
|
|
195
|
+
import { showMainMenu } from '../../lib/wtlink/main-menu.js';
|
|
196
|
+
import * as git from '../../lib/git.js';
|
|
197
|
+
import * as github from '../../lib/github.js';
|
|
20
198
|
// Mock process.exit to prevent test from exiting
|
|
21
199
|
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
22
200
|
// Helper to invoke builder for coverage
|
|
23
|
-
function invokeBuilder(
|
|
24
201
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
-
command, args) {
|
|
202
|
+
function invokeBuilder(command, args) {
|
|
26
203
|
const parser = yargs(args);
|
|
27
204
|
if (typeof command.builder === 'function') {
|
|
28
205
|
command.builder(parser);
|
|
@@ -42,154 +219,195 @@ describe('wt subcommand handlers', () => {
|
|
|
42
219
|
});
|
|
43
220
|
it('builder registers all expected options', () => {
|
|
44
221
|
invokeBuilder(newCommand, []);
|
|
45
|
-
expect(true).toBe(true);
|
|
46
|
-
// Verify builder returns a yargs instance with registered options
|
|
47
|
-
// The builder function is invoked for coverage
|
|
222
|
+
expect(true).toBe(true);
|
|
48
223
|
});
|
|
49
|
-
it('
|
|
50
|
-
newCommand.handler({
|
|
224
|
+
it('calls runNewprHandler with description', async () => {
|
|
225
|
+
await newCommand.handler({
|
|
51
226
|
description: 'Add dark mode',
|
|
52
227
|
json: false,
|
|
53
228
|
'non-interactive': false,
|
|
54
|
-
|
|
229
|
+
draft: false,
|
|
55
230
|
});
|
|
56
|
-
expect(
|
|
57
|
-
|
|
231
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
232
|
+
mode: 'new',
|
|
233
|
+
description: 'Add dark mode',
|
|
234
|
+
}));
|
|
58
235
|
});
|
|
59
|
-
it('
|
|
60
|
-
newCommand.handler({
|
|
236
|
+
it('calls runNewprHandler with pr mode for --pr flag', async () => {
|
|
237
|
+
await newCommand.handler({
|
|
61
238
|
pr: 42,
|
|
62
239
|
json: false,
|
|
63
240
|
'non-interactive': false,
|
|
64
|
-
|
|
241
|
+
draft: false,
|
|
65
242
|
});
|
|
66
|
-
expect(
|
|
243
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
244
|
+
mode: 'pr',
|
|
245
|
+
prNumber: 42,
|
|
246
|
+
}));
|
|
67
247
|
});
|
|
68
|
-
it('
|
|
69
|
-
newCommand.handler({
|
|
248
|
+
it('maps --ready flag to draft=false and draftExplicitlySet=true', async () => {
|
|
249
|
+
await newCommand.handler({
|
|
70
250
|
ready: true,
|
|
71
251
|
json: false,
|
|
72
252
|
'non-interactive': false,
|
|
73
|
-
|
|
253
|
+
draft: false,
|
|
74
254
|
install: false,
|
|
75
255
|
code: false,
|
|
76
256
|
'no-wtlink': false,
|
|
77
257
|
'no-hooks': false,
|
|
78
258
|
});
|
|
79
|
-
expect(
|
|
259
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
260
|
+
draft: false,
|
|
261
|
+
draftExplicitlySet: true,
|
|
262
|
+
}));
|
|
80
263
|
});
|
|
81
|
-
it('
|
|
82
|
-
newCommand.handler({
|
|
264
|
+
it('maps --base flag to baseBranch option', async () => {
|
|
265
|
+
await newCommand.handler({
|
|
83
266
|
base: 'develop',
|
|
84
267
|
json: false,
|
|
85
268
|
'non-interactive': false,
|
|
86
|
-
|
|
269
|
+
draft: false,
|
|
87
270
|
install: false,
|
|
88
271
|
code: false,
|
|
89
272
|
ready: false,
|
|
90
273
|
'no-wtlink': false,
|
|
91
274
|
'no-hooks': false,
|
|
92
275
|
});
|
|
93
|
-
expect(
|
|
276
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ baseBranch: 'develop' }));
|
|
94
277
|
});
|
|
95
|
-
it('
|
|
96
|
-
newCommand.handler({
|
|
278
|
+
it('maps --branch flag to branch mode', async () => {
|
|
279
|
+
await newCommand.handler({
|
|
97
280
|
branch: 'feat/my-feature',
|
|
98
281
|
json: false,
|
|
99
282
|
'non-interactive': false,
|
|
100
|
-
|
|
283
|
+
draft: false,
|
|
101
284
|
install: false,
|
|
102
285
|
code: false,
|
|
103
286
|
ready: false,
|
|
104
287
|
'no-wtlink': false,
|
|
105
288
|
'no-hooks': false,
|
|
106
289
|
});
|
|
107
|
-
expect(
|
|
290
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
291
|
+
mode: 'branch',
|
|
292
|
+
branchName: 'feat/my-feature',
|
|
293
|
+
}));
|
|
108
294
|
});
|
|
109
|
-
it('
|
|
110
|
-
newCommand.handler({
|
|
295
|
+
it('maps --install flag to installDeps option', async () => {
|
|
296
|
+
await newCommand.handler({
|
|
111
297
|
install: true,
|
|
112
298
|
json: false,
|
|
113
299
|
'non-interactive': false,
|
|
114
|
-
|
|
300
|
+
draft: false,
|
|
115
301
|
code: false,
|
|
116
302
|
ready: false,
|
|
117
303
|
'no-wtlink': false,
|
|
118
304
|
'no-hooks': false,
|
|
119
305
|
});
|
|
120
|
-
expect(
|
|
306
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ installDeps: true }));
|
|
121
307
|
});
|
|
122
|
-
it('
|
|
123
|
-
newCommand.handler({
|
|
308
|
+
it('maps --code flag to openEditor option', async () => {
|
|
309
|
+
await newCommand.handler({
|
|
124
310
|
code: true,
|
|
125
311
|
json: false,
|
|
126
312
|
'non-interactive': false,
|
|
127
|
-
|
|
313
|
+
draft: false,
|
|
128
314
|
install: false,
|
|
129
315
|
ready: false,
|
|
130
316
|
'no-wtlink': false,
|
|
131
317
|
'no-hooks': false,
|
|
132
318
|
});
|
|
133
|
-
expect(
|
|
319
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ openEditor: true }));
|
|
134
320
|
});
|
|
135
|
-
it('
|
|
136
|
-
newCommand.handler({
|
|
321
|
+
it('maps --no-wtlink flag to runWtlink=false option', async () => {
|
|
322
|
+
await newCommand.handler({
|
|
137
323
|
'no-wtlink': true,
|
|
138
324
|
json: false,
|
|
139
325
|
'non-interactive': false,
|
|
140
|
-
|
|
326
|
+
draft: false,
|
|
141
327
|
install: false,
|
|
142
328
|
code: false,
|
|
143
329
|
ready: false,
|
|
144
330
|
'no-hooks': false,
|
|
145
331
|
});
|
|
146
|
-
expect(
|
|
332
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ runWtlink: false }));
|
|
147
333
|
});
|
|
148
|
-
it('
|
|
149
|
-
newCommand.handler({
|
|
334
|
+
it('maps --no-hooks flag to noHooks option', async () => {
|
|
335
|
+
await newCommand.handler({
|
|
150
336
|
'no-hooks': true,
|
|
151
337
|
json: false,
|
|
152
338
|
'non-interactive': false,
|
|
153
|
-
|
|
339
|
+
draft: false,
|
|
154
340
|
install: false,
|
|
155
341
|
code: false,
|
|
156
342
|
ready: false,
|
|
157
343
|
'no-wtlink': false,
|
|
158
344
|
});
|
|
159
|
-
expect(
|
|
345
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ noHooks: true }));
|
|
160
346
|
});
|
|
161
|
-
it('
|
|
162
|
-
newCommand.handler({
|
|
347
|
+
it('maps --json flag to json option', async () => {
|
|
348
|
+
await newCommand.handler({
|
|
163
349
|
json: true,
|
|
164
350
|
'non-interactive': false,
|
|
165
|
-
|
|
351
|
+
draft: false,
|
|
166
352
|
});
|
|
167
|
-
expect(
|
|
353
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ json: true }));
|
|
354
|
+
expect(setJsonMode).toHaveBeenCalledWith(true);
|
|
168
355
|
});
|
|
169
|
-
it('
|
|
170
|
-
newCommand.handler({
|
|
356
|
+
it('maps --non-interactive flag to nonInteractive option', async () => {
|
|
357
|
+
await newCommand.handler({
|
|
171
358
|
json: false,
|
|
172
359
|
'non-interactive': true,
|
|
173
|
-
|
|
360
|
+
draft: false,
|
|
174
361
|
});
|
|
175
|
-
expect(
|
|
362
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ nonInteractive: true }));
|
|
176
363
|
});
|
|
177
|
-
it('
|
|
178
|
-
newCommand.handler({
|
|
364
|
+
it('maps --action flag to action option', async () => {
|
|
365
|
+
await newCommand.handler({
|
|
179
366
|
action: 'commit_all',
|
|
180
367
|
json: false,
|
|
181
368
|
'non-interactive': false,
|
|
182
|
-
|
|
369
|
+
draft: false,
|
|
370
|
+
});
|
|
371
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ action: 'commit_all' }));
|
|
372
|
+
});
|
|
373
|
+
it('maps --draft flag to draft=true and draftExplicitlySet=true', async () => {
|
|
374
|
+
await newCommand.handler({
|
|
375
|
+
json: false,
|
|
376
|
+
'non-interactive': false,
|
|
377
|
+
draft: true,
|
|
378
|
+
});
|
|
379
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
380
|
+
draft: true,
|
|
381
|
+
draftExplicitlySet: true,
|
|
382
|
+
}));
|
|
383
|
+
});
|
|
384
|
+
it('maps --plan flag to generatePlan option', async () => {
|
|
385
|
+
await newCommand.handler({
|
|
386
|
+
json: false,
|
|
387
|
+
'non-interactive': false,
|
|
388
|
+
draft: false,
|
|
389
|
+
plan: true,
|
|
390
|
+
});
|
|
391
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ generatePlan: true }));
|
|
392
|
+
});
|
|
393
|
+
it('maps --confirm-hooks flag to confirmHooks option', async () => {
|
|
394
|
+
await newCommand.handler({
|
|
395
|
+
json: false,
|
|
396
|
+
'non-interactive': false,
|
|
397
|
+
draft: false,
|
|
398
|
+
'confirm-hooks': true,
|
|
183
399
|
});
|
|
184
|
-
expect(
|
|
400
|
+
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({ confirmHooks: true }));
|
|
185
401
|
});
|
|
186
|
-
it('
|
|
187
|
-
|
|
402
|
+
it('does not spawn a child process', async () => {
|
|
403
|
+
vi.mocked(spawnSync).mockClear();
|
|
404
|
+
await newCommand.handler({
|
|
405
|
+
description: 'Test',
|
|
188
406
|
json: false,
|
|
189
407
|
'non-interactive': false,
|
|
190
|
-
|
|
408
|
+
draft: false,
|
|
191
409
|
});
|
|
192
|
-
expect(spawnSync).
|
|
410
|
+
expect(spawnSync).not.toHaveBeenCalled();
|
|
193
411
|
});
|
|
194
412
|
});
|
|
195
413
|
describe('listCommand', () => {
|
|
@@ -199,53 +417,39 @@ describe('wt subcommand handlers', () => {
|
|
|
199
417
|
});
|
|
200
418
|
it('builder registers all expected options', () => {
|
|
201
419
|
invokeBuilder(listCommand, []);
|
|
202
|
-
expect(true).toBe(true);
|
|
420
|
+
expect(true).toBe(true);
|
|
203
421
|
});
|
|
204
|
-
it('
|
|
205
|
-
listCommand.handler({
|
|
206
|
-
|
|
207
|
-
json: false,
|
|
208
|
-
'no-interactive': false,
|
|
209
|
-
status: false,
|
|
210
|
-
});
|
|
211
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['--verbose']), expect.any(Object));
|
|
422
|
+
it('calls gatherWorktreeInfo with verbose option', async () => {
|
|
423
|
+
await listCommand.handler({ verbose: true, json: false, status: false });
|
|
424
|
+
expect(gatherWorktreeInfo).toHaveBeenCalledWith('/fake/repo', expect.objectContaining({ verbose: true }), expect.any(Object));
|
|
212
425
|
});
|
|
213
|
-
it('
|
|
214
|
-
listCommand.handler({
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
'no-interactive': false,
|
|
218
|
-
status: false,
|
|
219
|
-
});
|
|
220
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['--json']), expect.any(Object));
|
|
426
|
+
it('calls setJsonMode and formatJsonOutput for --json', async () => {
|
|
427
|
+
await listCommand.handler({ json: true, verbose: false, status: false });
|
|
428
|
+
expect(setJsonMode).toHaveBeenCalledWith(true);
|
|
429
|
+
expect(formatJsonOutput).toHaveBeenCalled();
|
|
221
430
|
});
|
|
222
|
-
it('
|
|
223
|
-
listCommand.handler({
|
|
224
|
-
'no-interactive': true,
|
|
431
|
+
it('calls printWorktreeTable for non-interactive non-json output', async () => {
|
|
432
|
+
await listCommand.handler({
|
|
225
433
|
json: false,
|
|
226
434
|
verbose: false,
|
|
227
435
|
status: false,
|
|
436
|
+
interactive: false,
|
|
228
437
|
});
|
|
229
|
-
expect(
|
|
438
|
+
expect(printWorktreeTable).toHaveBeenCalled();
|
|
230
439
|
});
|
|
231
|
-
it('passes
|
|
232
|
-
listCommand.handler({
|
|
233
|
-
|
|
234
|
-
json: false,
|
|
235
|
-
verbose: false,
|
|
236
|
-
status: false,
|
|
237
|
-
'no-interactive': false,
|
|
238
|
-
});
|
|
239
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['--interactive']), expect.any(Object));
|
|
440
|
+
it('passes status option to gatherWorktreeInfo', async () => {
|
|
441
|
+
await listCommand.handler({ status: true, json: false, verbose: false });
|
|
442
|
+
expect(gatherWorktreeInfo).toHaveBeenCalledWith('/fake/repo', expect.objectContaining({ showStatus: true }), expect.any(Object));
|
|
240
443
|
});
|
|
241
|
-
it('
|
|
242
|
-
|
|
243
|
-
|
|
444
|
+
it('does not spawn a child process', async () => {
|
|
445
|
+
vi.mocked(spawnSync).mockClear();
|
|
446
|
+
await listCommand.handler({
|
|
244
447
|
json: false,
|
|
245
448
|
verbose: false,
|
|
246
|
-
|
|
449
|
+
status: false,
|
|
450
|
+
interactive: false,
|
|
247
451
|
});
|
|
248
|
-
expect(spawnSync).
|
|
452
|
+
expect(spawnSync).not.toHaveBeenCalled();
|
|
249
453
|
});
|
|
250
454
|
});
|
|
251
455
|
describe('cleanCommand', () => {
|
|
@@ -255,64 +459,58 @@ describe('wt subcommand handlers', () => {
|
|
|
255
459
|
});
|
|
256
460
|
it('builder registers all expected options', () => {
|
|
257
461
|
invokeBuilder(cleanCommand, []);
|
|
258
|
-
expect(true).toBe(true);
|
|
462
|
+
expect(true).toBe(true);
|
|
259
463
|
});
|
|
260
|
-
it('
|
|
261
|
-
cleanCommand.handler({
|
|
262
|
-
|
|
263
|
-
all: false,
|
|
464
|
+
it('calls gatherPrWorktreeInfo for --all mode', async () => {
|
|
465
|
+
await cleanCommand.handler({
|
|
466
|
+
all: true,
|
|
264
467
|
'dry-run': false,
|
|
265
468
|
force: false,
|
|
266
469
|
json: false,
|
|
267
470
|
});
|
|
268
|
-
expect(
|
|
471
|
+
expect(gatherPrWorktreeInfo).toHaveBeenCalledWith('/fake/repo', '{repo}.pr{number}', expect.any(Object));
|
|
472
|
+
expect(getCleanableWorktrees).toHaveBeenCalled();
|
|
269
473
|
});
|
|
270
|
-
it('
|
|
271
|
-
cleanCommand.handler({
|
|
474
|
+
it('calls setJsonMode when --json is passed', async () => {
|
|
475
|
+
await cleanCommand.handler({
|
|
272
476
|
all: true,
|
|
273
477
|
'dry-run': false,
|
|
274
478
|
force: false,
|
|
275
|
-
json:
|
|
479
|
+
json: true,
|
|
276
480
|
});
|
|
277
|
-
expect(
|
|
481
|
+
expect(setJsonMode).toHaveBeenCalledWith(true);
|
|
278
482
|
});
|
|
279
|
-
it('
|
|
280
|
-
|
|
281
|
-
|
|
483
|
+
it('handles gh not installed error', async () => {
|
|
484
|
+
vi.mocked(github.isGhInstalled).mockReturnValueOnce(false);
|
|
485
|
+
await cleanCommand.handler({
|
|
282
486
|
all: false,
|
|
487
|
+
'dry-run': false,
|
|
283
488
|
force: false,
|
|
284
489
|
json: false,
|
|
285
490
|
});
|
|
286
|
-
expect(
|
|
491
|
+
expect(printError).toHaveBeenCalledWith(expect.objectContaining({ title: expect.stringContaining('GitHub CLI') }));
|
|
492
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
287
493
|
});
|
|
288
|
-
it('
|
|
289
|
-
|
|
290
|
-
|
|
494
|
+
it('handles not in git repo error', async () => {
|
|
495
|
+
vi.mocked(git.getRepoRoot).mockReturnValueOnce(null);
|
|
496
|
+
await cleanCommand.handler({
|
|
291
497
|
all: false,
|
|
292
498
|
'dry-run': false,
|
|
499
|
+
force: false,
|
|
293
500
|
json: false,
|
|
294
501
|
});
|
|
295
|
-
expect(
|
|
502
|
+
expect(printError).toHaveBeenCalledWith(expect.objectContaining({ title: expect.stringContaining('git repository') }));
|
|
503
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
296
504
|
});
|
|
297
|
-
it('
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
all:
|
|
505
|
+
it('does not spawn a child process', async () => {
|
|
506
|
+
vi.mocked(spawnSync).mockClear();
|
|
507
|
+
await cleanCommand.handler({
|
|
508
|
+
all: true,
|
|
301
509
|
'dry-run': false,
|
|
302
510
|
force: false,
|
|
303
|
-
remote: false,
|
|
304
|
-
});
|
|
305
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['--json']), expect.any(Object));
|
|
306
|
-
});
|
|
307
|
-
it('passes --remote flag to cleanpr', () => {
|
|
308
|
-
cleanCommand.handler({
|
|
309
|
-
remote: true,
|
|
310
511
|
json: false,
|
|
311
|
-
all: false,
|
|
312
|
-
'dry-run': false,
|
|
313
|
-
force: false,
|
|
314
512
|
});
|
|
315
|
-
expect(spawnSync).
|
|
513
|
+
expect(spawnSync).not.toHaveBeenCalled();
|
|
316
514
|
});
|
|
317
515
|
});
|
|
318
516
|
describe('stateCommand', () => {
|
|
@@ -322,21 +520,31 @@ describe('wt subcommand handlers', () => {
|
|
|
322
520
|
});
|
|
323
521
|
it('builder registers all expected options', () => {
|
|
324
522
|
invokeBuilder(stateCommand, []);
|
|
325
|
-
expect(true).toBe(true);
|
|
523
|
+
expect(true).toBe(true);
|
|
326
524
|
});
|
|
327
|
-
it('
|
|
328
|
-
stateCommand.handler({
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['--json']), expect.any(Object));
|
|
525
|
+
it('calls analyzeState and formatJsonResult for --json', async () => {
|
|
526
|
+
await stateCommand.handler({ json: true, verbose: false });
|
|
527
|
+
expect(analyzeState).toHaveBeenCalledWith(expect.objectContaining({ json: true, verbose: false }));
|
|
528
|
+
expect(createSuccessResult).toHaveBeenCalledWith('wtstate', expect.any(Object));
|
|
529
|
+
expect(formatJsonResult).toHaveBeenCalled();
|
|
333
530
|
});
|
|
334
|
-
it('
|
|
335
|
-
stateCommand.handler({
|
|
336
|
-
|
|
531
|
+
it('calls analyzeState and formatText for text output', async () => {
|
|
532
|
+
await stateCommand.handler({ verbose: true, json: false });
|
|
533
|
+
expect(analyzeState).toHaveBeenCalledWith(expect.objectContaining({ verbose: true, json: false }));
|
|
534
|
+
expect(formatText).toHaveBeenCalled();
|
|
535
|
+
});
|
|
536
|
+
it('passes base-branch option to analyzeState', async () => {
|
|
537
|
+
await stateCommand.handler({
|
|
538
|
+
verbose: false,
|
|
337
539
|
json: false,
|
|
540
|
+
'base-branch': 'develop',
|
|
338
541
|
});
|
|
339
|
-
expect(
|
|
542
|
+
expect(analyzeState).toHaveBeenCalledWith(expect.objectContaining({ baseBranch: 'develop' }));
|
|
543
|
+
});
|
|
544
|
+
it('does not spawn a child process', async () => {
|
|
545
|
+
vi.mocked(spawnSync).mockClear();
|
|
546
|
+
await stateCommand.handler({ json: false, verbose: false });
|
|
547
|
+
expect(spawnSync).not.toHaveBeenCalled();
|
|
340
548
|
});
|
|
341
549
|
});
|
|
342
550
|
describe('configCommand', () => {
|
|
@@ -346,32 +554,10 @@ describe('wt subcommand handlers', () => {
|
|
|
346
554
|
});
|
|
347
555
|
it('builder registers positional args', () => {
|
|
348
556
|
invokeBuilder(configCommand, []);
|
|
349
|
-
expect(true).toBe(true);
|
|
350
|
-
});
|
|
351
|
-
it('passes subcommand to wtconfig', () => {
|
|
352
|
-
configCommand.handler({
|
|
353
|
-
subcommand: 'show',
|
|
354
|
-
args: [],
|
|
355
|
-
});
|
|
356
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['show']), expect.any(Object));
|
|
357
|
-
});
|
|
358
|
-
it('passes subcommand and args to wtconfig', () => {
|
|
359
|
-
configCommand.handler({
|
|
360
|
-
subcommand: 'set',
|
|
361
|
-
args: ['baseBranch', 'develop'],
|
|
362
|
-
});
|
|
363
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['set', 'baseBranch', 'develop']), expect.any(Object));
|
|
557
|
+
expect(true).toBe(true);
|
|
364
558
|
});
|
|
365
559
|
it('handles no subcommand (defaults to interactive)', async () => {
|
|
366
|
-
|
|
367
|
-
// Since we're not in a git repo in tests, it will error out
|
|
368
|
-
// We just verify the handler runs without throwing
|
|
369
|
-
const handler = configCommand.handler({
|
|
370
|
-
subcommand: undefined,
|
|
371
|
-
args: [],
|
|
372
|
-
});
|
|
373
|
-
// Handler is now async; it will call process.exit
|
|
374
|
-
// We just check it returns a promise
|
|
560
|
+
const handler = configCommand.handler({ subcommand: undefined, args: [] });
|
|
375
561
|
expect(handler).toBeInstanceOf(Promise);
|
|
376
562
|
});
|
|
377
563
|
});
|
|
@@ -382,10 +568,10 @@ describe('wt subcommand handlers', () => {
|
|
|
382
568
|
});
|
|
383
569
|
it('builder registers all expected options', () => {
|
|
384
570
|
invokeBuilder(linkCommand, []);
|
|
385
|
-
expect(true).toBe(true);
|
|
571
|
+
expect(true).toBe(true);
|
|
386
572
|
});
|
|
387
|
-
it('
|
|
388
|
-
linkCommand.handler({
|
|
573
|
+
it('calls link.run with source and destination for link subcommand', async () => {
|
|
574
|
+
await linkCommand.handler({
|
|
389
575
|
subcommand: 'link',
|
|
390
576
|
args: ['source', 'dest'],
|
|
391
577
|
'dry-run': false,
|
|
@@ -394,65 +580,66 @@ describe('wt subcommand handlers', () => {
|
|
|
394
580
|
json: false,
|
|
395
581
|
verbose: false,
|
|
396
582
|
});
|
|
397
|
-
expect(
|
|
583
|
+
expect(linkRun).toHaveBeenCalledWith(expect.objectContaining({
|
|
584
|
+
source: 'source',
|
|
585
|
+
destination: 'dest',
|
|
586
|
+
dryRun: false,
|
|
587
|
+
yes: false,
|
|
588
|
+
}));
|
|
398
589
|
});
|
|
399
|
-
it('passes --dry-run
|
|
400
|
-
linkCommand.handler({
|
|
401
|
-
'
|
|
590
|
+
it('passes --dry-run to link.run', async () => {
|
|
591
|
+
await linkCommand.handler({
|
|
592
|
+
subcommand: 'link',
|
|
402
593
|
args: [],
|
|
594
|
+
'dry-run': true,
|
|
403
595
|
yes: false,
|
|
404
596
|
'non-interactive': false,
|
|
405
597
|
json: false,
|
|
406
598
|
verbose: false,
|
|
407
599
|
});
|
|
408
|
-
expect(
|
|
600
|
+
expect(linkRun).toHaveBeenCalledWith(expect.objectContaining({ dryRun: true }));
|
|
409
601
|
});
|
|
410
|
-
it('passes --yes
|
|
411
|
-
linkCommand.handler({
|
|
412
|
-
|
|
602
|
+
it('passes --yes to link.run', async () => {
|
|
603
|
+
await linkCommand.handler({
|
|
604
|
+
subcommand: 'link',
|
|
413
605
|
args: [],
|
|
414
606
|
'dry-run': false,
|
|
607
|
+
yes: true,
|
|
415
608
|
'non-interactive': false,
|
|
416
609
|
json: false,
|
|
417
610
|
verbose: false,
|
|
418
611
|
});
|
|
419
|
-
expect(
|
|
420
|
-
});
|
|
421
|
-
it('passes --non-interactive flag to wtlink', () => {
|
|
422
|
-
linkCommand.handler({
|
|
423
|
-
'non-interactive': true,
|
|
424
|
-
args: [],
|
|
425
|
-
'dry-run': false,
|
|
426
|
-
yes: false,
|
|
427
|
-
json: false,
|
|
428
|
-
verbose: false,
|
|
429
|
-
});
|
|
430
|
-
expect(spawnSync).toHaveBeenCalledWith(process.execPath, expect.arrayContaining(['--non-interactive']), expect.any(Object));
|
|
612
|
+
expect(linkRun).toHaveBeenCalledWith(expect.objectContaining({ yes: true }));
|
|
431
613
|
});
|
|
432
|
-
it('
|
|
433
|
-
linkCommand.handler({
|
|
434
|
-
|
|
614
|
+
it('calls setJsonMode when --json is passed', async () => {
|
|
615
|
+
await linkCommand.handler({
|
|
616
|
+
subcommand: 'link',
|
|
435
617
|
args: [],
|
|
436
618
|
'dry-run': false,
|
|
437
619
|
yes: false,
|
|
438
620
|
'non-interactive': false,
|
|
621
|
+
json: true,
|
|
439
622
|
verbose: false,
|
|
440
623
|
});
|
|
441
|
-
expect(
|
|
624
|
+
expect(setJsonMode).toHaveBeenCalledWith(true);
|
|
442
625
|
});
|
|
443
|
-
it('
|
|
444
|
-
linkCommand.handler({
|
|
445
|
-
|
|
626
|
+
it('calls manage.run with verbose option for manage subcommand', async () => {
|
|
627
|
+
await linkCommand.handler({
|
|
628
|
+
subcommand: 'manage',
|
|
446
629
|
args: [],
|
|
447
630
|
'dry-run': false,
|
|
448
631
|
yes: false,
|
|
449
632
|
'non-interactive': false,
|
|
450
633
|
json: false,
|
|
634
|
+
verbose: true,
|
|
635
|
+
clean: false,
|
|
636
|
+
backup: false,
|
|
451
637
|
});
|
|
452
|
-
expect(
|
|
638
|
+
expect(manageRun).toHaveBeenCalledWith(expect.objectContaining({ verbose: true }));
|
|
453
639
|
});
|
|
454
|
-
it('passes --manifest-file
|
|
455
|
-
linkCommand.handler({
|
|
640
|
+
it('passes --manifest-file to manage.run', async () => {
|
|
641
|
+
await linkCommand.handler({
|
|
642
|
+
subcommand: 'manage',
|
|
456
643
|
'manifest-file': '.custom-manifest',
|
|
457
644
|
args: [],
|
|
458
645
|
'dry-run': false,
|
|
@@ -460,11 +647,13 @@ describe('wt subcommand handlers', () => {
|
|
|
460
647
|
'non-interactive': false,
|
|
461
648
|
json: false,
|
|
462
649
|
verbose: false,
|
|
650
|
+
clean: false,
|
|
651
|
+
backup: false,
|
|
463
652
|
});
|
|
464
|
-
expect(
|
|
653
|
+
expect(manageRun).toHaveBeenCalledWith(expect.objectContaining({ manifestFile: '.custom-manifest' }));
|
|
465
654
|
});
|
|
466
|
-
it('
|
|
467
|
-
linkCommand.handler({
|
|
655
|
+
it('shows interactive menu when no subcommand provided', async () => {
|
|
656
|
+
await linkCommand.handler({
|
|
468
657
|
args: [],
|
|
469
658
|
'dry-run': false,
|
|
470
659
|
yes: false,
|
|
@@ -474,10 +663,11 @@ describe('wt subcommand handlers', () => {
|
|
|
474
663
|
clean: false,
|
|
475
664
|
backup: false,
|
|
476
665
|
});
|
|
477
|
-
expect(
|
|
666
|
+
expect(showMainMenu).toHaveBeenCalled();
|
|
478
667
|
});
|
|
479
|
-
it('passes --clean
|
|
480
|
-
linkCommand.handler({
|
|
668
|
+
it('passes --clean to manage.run', async () => {
|
|
669
|
+
await linkCommand.handler({
|
|
670
|
+
subcommand: 'manage',
|
|
481
671
|
clean: true,
|
|
482
672
|
args: [],
|
|
483
673
|
'dry-run': false,
|
|
@@ -487,10 +677,11 @@ describe('wt subcommand handlers', () => {
|
|
|
487
677
|
verbose: false,
|
|
488
678
|
backup: false,
|
|
489
679
|
});
|
|
490
|
-
expect(
|
|
680
|
+
expect(manageRun).toHaveBeenCalledWith(expect.objectContaining({ clean: true }));
|
|
491
681
|
});
|
|
492
|
-
it('passes --backup
|
|
493
|
-
linkCommand.handler({
|
|
682
|
+
it('passes --backup to manage.run', async () => {
|
|
683
|
+
await linkCommand.handler({
|
|
684
|
+
subcommand: 'manage',
|
|
494
685
|
backup: true,
|
|
495
686
|
args: [],
|
|
496
687
|
'dry-run': false,
|
|
@@ -500,10 +691,11 @@ describe('wt subcommand handlers', () => {
|
|
|
500
691
|
verbose: false,
|
|
501
692
|
clean: false,
|
|
502
693
|
});
|
|
503
|
-
expect(
|
|
694
|
+
expect(manageRun).toHaveBeenCalledWith(expect.objectContaining({ backup: true }));
|
|
504
695
|
});
|
|
505
|
-
it('passes --type
|
|
506
|
-
linkCommand.handler({
|
|
696
|
+
it('passes --type to link.run', async () => {
|
|
697
|
+
await linkCommand.handler({
|
|
698
|
+
subcommand: 'link',
|
|
507
699
|
type: 'symbolic',
|
|
508
700
|
args: [],
|
|
509
701
|
'dry-run': false,
|
|
@@ -514,7 +706,33 @@ describe('wt subcommand handlers', () => {
|
|
|
514
706
|
clean: false,
|
|
515
707
|
backup: false,
|
|
516
708
|
});
|
|
517
|
-
expect(
|
|
709
|
+
expect(linkRun).toHaveBeenCalledWith(expect.objectContaining({ type: 'symbolic' }));
|
|
710
|
+
});
|
|
711
|
+
it('calls validate.run for validate subcommand', async () => {
|
|
712
|
+
await linkCommand.handler({
|
|
713
|
+
subcommand: 'validate',
|
|
714
|
+
args: [],
|
|
715
|
+
'dry-run': false,
|
|
716
|
+
yes: false,
|
|
717
|
+
'non-interactive': false,
|
|
718
|
+
json: false,
|
|
719
|
+
verbose: false,
|
|
720
|
+
});
|
|
721
|
+
expect(validateRun).toHaveBeenCalled();
|
|
722
|
+
});
|
|
723
|
+
it('does not spawn a child process', async () => {
|
|
724
|
+
vi.mocked(spawnSync).mockClear();
|
|
725
|
+
await linkCommand.handler({
|
|
726
|
+
args: [],
|
|
727
|
+
'dry-run': false,
|
|
728
|
+
yes: false,
|
|
729
|
+
'non-interactive': false,
|
|
730
|
+
json: false,
|
|
731
|
+
verbose: false,
|
|
732
|
+
clean: false,
|
|
733
|
+
backup: false,
|
|
734
|
+
});
|
|
735
|
+
expect(spawnSync).not.toHaveBeenCalled();
|
|
518
736
|
});
|
|
519
737
|
});
|
|
520
738
|
});
|