From e23359b1bf22bcca58a06bd46d6af5cbdf1a703d Mon Sep 17 00:00:00 2001 From: nrs <38722970+nrslib@users.noreply.github.com> Date: Sun, 8 Feb 2026 07:17:17 +0900 Subject: [PATCH] takt: github-issue-130-tasuku-autopr (#140) --- src/__tests__/addTask.test.ts | 17 +++ src/__tests__/selectAndExecute-autoPr.test.ts | 104 ++++++++++++++++++ src/features/tasks/add/index.ts | 2 +- .../tasks/execute/selectAndExecute.ts | 2 +- 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/__tests__/selectAndExecute-autoPr.test.ts diff --git a/src/__tests__/addTask.test.ts b/src/__tests__/addTask.test.ts index bd05b25..96b1756 100644 --- a/src/__tests__/addTask.test.ts +++ b/src/__tests__/addTask.test.ts @@ -386,6 +386,23 @@ describe('addTask', () => { expect(mockResolveIssueTask).toHaveBeenCalledWith('#99'); }); + it('should call auto-PR confirm with default true', async () => { + // Given: worktree is confirmed so auto-PR prompt is reached + setupFullFlowMocks({ slug: 'auto-pr-default' }); + mockConfirm.mockResolvedValue(true); + mockPromptInput.mockResolvedValue(''); + + // When + await addTask(testDir); + + // Then: second confirm call (Auto-create PR?) has defaultYes=true + const autoPrCall = mockConfirm.mock.calls.find( + (call) => call[0] === 'Auto-create PR?', + ); + expect(autoPrCall).toBeDefined(); + expect(autoPrCall![1]).toBe(true); + }); + describe('create_issue action', () => { it('should call createIssue when create_issue action is selected', async () => { // Given: interactive mode returns create_issue action diff --git a/src/__tests__/selectAndExecute-autoPr.test.ts b/src/__tests__/selectAndExecute-autoPr.test.ts new file mode 100644 index 0000000..2cce3f2 --- /dev/null +++ b/src/__tests__/selectAndExecute-autoPr.test.ts @@ -0,0 +1,104 @@ +/** + * Tests for resolveAutoPr default behavior in selectAndExecuteTask + */ + +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +vi.mock('../shared/prompt/index.js', () => ({ + confirm: vi.fn(), +})); + +vi.mock('../infra/config/index.js', () => ({ + getCurrentPiece: vi.fn(), + listPieces: vi.fn(() => ['default']), + listPieceEntries: vi.fn(() => []), + isPiecePath: vi.fn(() => false), + loadAllPiecesWithSources: vi.fn(() => new Map()), + getPieceCategories: vi.fn(() => null), + buildCategorizedPieces: vi.fn(), + loadGlobalConfig: vi.fn(() => ({})), +})); + +vi.mock('../infra/task/index.js', () => ({ + createSharedClone: vi.fn(), + autoCommitAndPush: vi.fn(), + summarizeTaskName: vi.fn(), +})); + +vi.mock('../shared/ui/index.js', () => ({ + info: vi.fn(), + error: vi.fn(), + success: vi.fn(), +})); + +vi.mock('../shared/utils/index.js', async (importOriginal) => ({ + ...(await importOriginal>()), + createLogger: () => ({ + info: vi.fn(), + debug: vi.fn(), + error: vi.fn(), + }), +})); + +vi.mock('../infra/github/index.js', () => ({ + createPullRequest: vi.fn(), + buildPrBody: vi.fn(), + pushBranch: vi.fn(), +})); + +vi.mock('../features/tasks/execute/taskExecution.js', () => ({ + executeTask: vi.fn(), +})); + +vi.mock('../features/pieceSelection/index.js', () => ({ + warnMissingPieces: vi.fn(), + selectPieceFromCategorizedPieces: vi.fn(), + selectPieceFromEntries: vi.fn(), +})); + +import { confirm } from '../shared/prompt/index.js'; +import { createSharedClone, autoCommitAndPush, summarizeTaskName } from '../infra/task/index.js'; +import { selectAndExecuteTask } from '../features/tasks/execute/selectAndExecute.js'; + +const mockConfirm = vi.mocked(confirm); +const mockCreateSharedClone = vi.mocked(createSharedClone); +const mockAutoCommitAndPush = vi.mocked(autoCommitAndPush); +const mockSummarizeTaskName = vi.mocked(summarizeTaskName); + +beforeEach(() => { + vi.clearAllMocks(); +}); + +describe('resolveAutoPr default in selectAndExecuteTask', () => { + it('should call auto-PR confirm with default true when no CLI option or config', async () => { + // Given: worktree is enabled via override, no autoPr option, no global config autoPr + mockConfirm.mockResolvedValue(true); + mockSummarizeTaskName.mockResolvedValue('test-task'); + mockCreateSharedClone.mockReturnValue({ + path: '/project/../clone', + branch: 'takt/test-task', + }); + + const { executeTask } = await import( + '../features/tasks/execute/taskExecution.js' + ); + vi.mocked(executeTask).mockResolvedValue(true); + mockAutoCommitAndPush.mockReturnValue({ + success: false, + message: 'no changes', + }); + + // When + await selectAndExecuteTask('/project', 'test task', { + piece: 'default', + createWorktree: true, + }); + + // Then: the 'Create pull request?' confirm is called with default true + const autoPrCall = mockConfirm.mock.calls.find( + (call) => call[0] === 'Create pull request?', + ); + expect(autoPrCall).toBeDefined(); + expect(autoPrCall![1]).toBe(true); + }); +}); diff --git a/src/features/tasks/add/index.ts b/src/features/tasks/add/index.ts index cb0e6a7..3b92c2a 100644 --- a/src/features/tasks/add/index.ts +++ b/src/features/tasks/add/index.ts @@ -186,7 +186,7 @@ export async function addTask(cwd: string, task?: string): Promise { } // PR確認(worktreeが有効な場合のみ) - autoPr = await confirm('Auto-create PR?', false); + autoPr = await confirm('Auto-create PR?', true); } // YAMLファイル作成 diff --git a/src/features/tasks/execute/selectAndExecute.ts b/src/features/tasks/execute/selectAndExecute.ts index 03f97ac..715609b 100644 --- a/src/features/tasks/execute/selectAndExecute.ts +++ b/src/features/tasks/execute/selectAndExecute.ts @@ -141,7 +141,7 @@ async function resolveAutoPr(optionAutoPr: boolean | undefined): Promise