parent
f8fc9a7c83
commit
1e8909d512
@ -127,6 +127,9 @@ takt --task "fix the auth bug" -w magi -b feat/fix-auth
|
|||||||
|
|
||||||
# Specify repository (for PR creation)
|
# Specify repository (for PR creation)
|
||||||
takt --task "fix the auth bug" --auto-pr --repo owner/repo
|
takt --task "fix the auth bug" --auto-pr --repo owner/repo
|
||||||
|
|
||||||
|
# Run workflow only — skip branch creation, commit, and push
|
||||||
|
takt --task "fix the auth bug" --skip-git
|
||||||
```
|
```
|
||||||
|
|
||||||
In pipeline mode, PRs are **not** created unless `--auto-pr` is explicitly specified.
|
In pipeline mode, PRs are **not** created unless `--auto-pr` is explicitly specified.
|
||||||
@ -154,6 +157,7 @@ In pipeline mode, PRs are **not** created unless `--auto-pr` is explicitly speci
|
|||||||
| `-w, --workflow <name>` | Workflow to use |
|
| `-w, --workflow <name>` | Workflow to use |
|
||||||
| `-b, --branch <name>` | Branch name (auto-generated if omitted) |
|
| `-b, --branch <name>` | Branch name (auto-generated if omitted) |
|
||||||
| `--auto-pr` | Create PR after execution (interactive: skip confirmation, pipeline: enable PR) |
|
| `--auto-pr` | Create PR after execution (interactive: skip confirmation, pipeline: enable PR) |
|
||||||
|
| `--skip-git` | Skip branch creation, commit, and push (pipeline mode, workflow-only) |
|
||||||
| `--repo <owner/repo>` | Repository for PR creation |
|
| `--repo <owner/repo>` | Repository for PR creation |
|
||||||
|
|
||||||
## Workflows
|
## Workflows
|
||||||
|
|||||||
@ -125,6 +125,9 @@ takt --task "バグを修正" -w magi -b feat/fix-bug
|
|||||||
|
|
||||||
# リポジトリ指定(PR作成時)
|
# リポジトリ指定(PR作成時)
|
||||||
takt --task "バグを修正" --auto-pr --repo owner/repo
|
takt --task "バグを修正" --auto-pr --repo owner/repo
|
||||||
|
|
||||||
|
# ワークフロー実行のみ(ブランチ作成・commit・pushをスキップ)
|
||||||
|
takt --task "バグを修正" --skip-git
|
||||||
```
|
```
|
||||||
|
|
||||||
パイプラインモードでは `--auto-pr` を指定しない限りPRは作成されません。
|
パイプラインモードでは `--auto-pr` を指定しない限りPRは作成されません。
|
||||||
@ -152,6 +155,7 @@ takt --task "バグを修正" --auto-pr --repo owner/repo
|
|||||||
| `-w, --workflow <name>` | ワークフロー指定 |
|
| `-w, --workflow <name>` | ワークフロー指定 |
|
||||||
| `-b, --branch <name>` | ブランチ名指定(省略時は自動生成) |
|
| `-b, --branch <name>` | ブランチ名指定(省略時は自動生成) |
|
||||||
| `--auto-pr` | PR作成(対話: 確認スキップ、パイプライン: PR有効化) |
|
| `--auto-pr` | PR作成(対話: 確認スキップ、パイプライン: PR有効化) |
|
||||||
|
| `--skip-git` | ブランチ作成・commit・pushをスキップ(パイプラインモード、ワークフロー実行のみ) |
|
||||||
| `--repo <owner/repo>` | リポジトリ指定(PR作成時) |
|
| `--repo <owner/repo>` | リポジトリ指定(PR作成時) |
|
||||||
|
|
||||||
## ワークフロー
|
## ワークフロー
|
||||||
|
|||||||
@ -345,4 +345,57 @@ describe('executePipeline', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('--skip-git', () => {
|
||||||
|
it('should skip branch creation, commit, push when skipGit is true', async () => {
|
||||||
|
mockExecuteTask.mockResolvedValueOnce(true);
|
||||||
|
|
||||||
|
const exitCode = await executePipeline({
|
||||||
|
task: 'Fix the bug',
|
||||||
|
workflow: 'default',
|
||||||
|
autoPr: false,
|
||||||
|
skipGit: true,
|
||||||
|
cwd: '/tmp/test',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
expect(mockExecuteTask).toHaveBeenCalledWith('Fix the bug', '/tmp/test', 'default');
|
||||||
|
|
||||||
|
// No git operations should have been called
|
||||||
|
const gitCalls = mockExecFileSync.mock.calls.filter(
|
||||||
|
(call: unknown[]) => call[0] === 'git',
|
||||||
|
);
|
||||||
|
expect(gitCalls).toHaveLength(0);
|
||||||
|
expect(mockPushBranch).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore --auto-pr when skipGit is true', async () => {
|
||||||
|
mockExecuteTask.mockResolvedValueOnce(true);
|
||||||
|
|
||||||
|
const exitCode = await executePipeline({
|
||||||
|
task: 'Fix the bug',
|
||||||
|
workflow: 'default',
|
||||||
|
autoPr: true,
|
||||||
|
skipGit: true,
|
||||||
|
cwd: '/tmp/test',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
expect(mockCreatePullRequest).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should still return workflow failure exit code when skipGit is true', async () => {
|
||||||
|
mockExecuteTask.mockResolvedValueOnce(false);
|
||||||
|
|
||||||
|
const exitCode = await executePipeline({
|
||||||
|
task: 'Fix the bug',
|
||||||
|
workflow: 'default',
|
||||||
|
autoPr: false,
|
||||||
|
skipGit: true,
|
||||||
|
cwd: '/tmp/test',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(exitCode).toBe(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -198,7 +198,8 @@ program
|
|||||||
.option('-b, --branch <name>', 'Branch name (auto-generated if omitted)')
|
.option('-b, --branch <name>', 'Branch name (auto-generated if omitted)')
|
||||||
.option('--auto-pr', 'Create PR after successful execution')
|
.option('--auto-pr', 'Create PR after successful execution')
|
||||||
.option('--repo <owner/repo>', 'Repository (defaults to current)')
|
.option('--repo <owner/repo>', 'Repository (defaults to current)')
|
||||||
.option('-t, --task <string>', 'Task content (triggers pipeline/non-interactive mode)');
|
.option('-t, --task <string>', 'Task content (triggers pipeline/non-interactive mode)')
|
||||||
|
.option('--skip-git', 'Skip branch creation, commit, and push (pipeline mode)');
|
||||||
|
|
||||||
// Common initialization for all commands
|
// Common initialization for all commands
|
||||||
program.hook('preAction', async () => {
|
program.hook('preAction', async () => {
|
||||||
@ -327,6 +328,7 @@ program
|
|||||||
branch: opts.branch as string | undefined,
|
branch: opts.branch as string | undefined,
|
||||||
autoPr: opts.autoPr === true,
|
autoPr: opts.autoPr === true,
|
||||||
repo: opts.repo as string | undefined,
|
repo: opts.repo as string | undefined,
|
||||||
|
skipGit: opts.skipGit === true,
|
||||||
cwd: resolvedCwd,
|
cwd: resolvedCwd,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,8 @@ export interface PipelineExecutionOptions {
|
|||||||
autoPr: boolean;
|
autoPr: boolean;
|
||||||
/** Repository in owner/repo format */
|
/** Repository in owner/repo format */
|
||||||
repo?: string;
|
repo?: string;
|
||||||
|
/** Skip branch creation, commit, and push (workflow-only execution) */
|
||||||
|
skipGit?: boolean;
|
||||||
/** Working directory */
|
/** Working directory */
|
||||||
cwd: string;
|
cwd: string;
|
||||||
}
|
}
|
||||||
@ -135,7 +137,7 @@ function buildPipelinePrBody(
|
|||||||
* Returns a process exit code (0 on success, 2-5 on specific failures).
|
* Returns a process exit code (0 on success, 2-5 on specific failures).
|
||||||
*/
|
*/
|
||||||
export async function executePipeline(options: PipelineExecutionOptions): Promise<number> {
|
export async function executePipeline(options: PipelineExecutionOptions): Promise<number> {
|
||||||
const { cwd, workflow, autoPr } = options;
|
const { cwd, workflow, autoPr, skipGit } = options;
|
||||||
const globalConfig = loadGlobalConfig();
|
const globalConfig = loadGlobalConfig();
|
||||||
const pipelineConfig = globalConfig.pipeline;
|
const pipelineConfig = globalConfig.pipeline;
|
||||||
let issue: GitHubIssue | undefined;
|
let issue: GitHubIssue | undefined;
|
||||||
@ -164,8 +166,10 @@ export async function executePipeline(options: PipelineExecutionOptions): Promis
|
|||||||
return EXIT_ISSUE_FETCH_FAILED;
|
return EXIT_ISSUE_FETCH_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Step 2: Create branch ---
|
// --- Step 2: Create branch (skip if --skip-git) ---
|
||||||
const branch = options.branch ?? generatePipelineBranchName(pipelineConfig, options.issueNumber);
|
let branch: string | undefined;
|
||||||
|
if (!skipGit) {
|
||||||
|
branch = options.branch ?? generatePipelineBranchName(pipelineConfig, options.issueNumber);
|
||||||
info(`Creating branch: ${branch}`);
|
info(`Creating branch: ${branch}`);
|
||||||
try {
|
try {
|
||||||
createBranch(cwd, branch);
|
createBranch(cwd, branch);
|
||||||
@ -174,10 +178,11 @@ export async function executePipeline(options: PipelineExecutionOptions): Promis
|
|||||||
error(`Failed to create branch: ${err instanceof Error ? err.message : String(err)}`);
|
error(`Failed to create branch: ${err instanceof Error ? err.message : String(err)}`);
|
||||||
return EXIT_GIT_OPERATION_FAILED;
|
return EXIT_GIT_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Step 3: Run workflow ---
|
// --- Step 3: Run workflow ---
|
||||||
info(`Running workflow: ${workflow}`);
|
info(`Running workflow: ${workflow}`);
|
||||||
log.info('Pipeline workflow execution starting', { workflow, branch, issueNumber: options.issueNumber });
|
log.info('Pipeline workflow execution starting', { workflow, branch, skipGit, issueNumber: options.issueNumber });
|
||||||
|
|
||||||
const taskSuccess = await executeTask(task, cwd, workflow);
|
const taskSuccess = await executeTask(task, cwd, workflow);
|
||||||
|
|
||||||
@ -187,7 +192,8 @@ export async function executePipeline(options: PipelineExecutionOptions): Promis
|
|||||||
}
|
}
|
||||||
success(`Workflow '${workflow}' completed`);
|
success(`Workflow '${workflow}' completed`);
|
||||||
|
|
||||||
// --- Step 4: Commit & push ---
|
// --- Step 4: Commit & push (skip if --skip-git) ---
|
||||||
|
if (!skipGit && branch) {
|
||||||
const commitMessage = buildCommitMessage(pipelineConfig, issue, options.task);
|
const commitMessage = buildCommitMessage(pipelineConfig, issue, options.task);
|
||||||
|
|
||||||
info('Committing changes...');
|
info('Committing changes...');
|
||||||
@ -206,9 +212,13 @@ export async function executePipeline(options: PipelineExecutionOptions): Promis
|
|||||||
error(`Git operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
error(`Git operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
||||||
return EXIT_GIT_OPERATION_FAILED;
|
return EXIT_GIT_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Step 5: Create PR (if --auto-pr) ---
|
// --- Step 5: Create PR (if --auto-pr) ---
|
||||||
if (autoPr) {
|
if (autoPr) {
|
||||||
|
if (skipGit) {
|
||||||
|
info('--auto-pr is ignored when --skip-git is specified (no push was performed)');
|
||||||
|
} else if (branch) {
|
||||||
info('Creating pull request...');
|
info('Creating pull request...');
|
||||||
const prTitle = issue ? issue.title : (options.task ?? 'Pipeline task');
|
const prTitle = issue ? issue.title : (options.task ?? 'Pipeline task');
|
||||||
const report = `Workflow \`${workflow}\` completed successfully.`;
|
const report = `Workflow \`${workflow}\` completed successfully.`;
|
||||||
@ -228,11 +238,12 @@ export async function executePipeline(options: PipelineExecutionOptions): Promis
|
|||||||
return EXIT_PR_CREATION_FAILED;
|
return EXIT_PR_CREATION_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Summary ---
|
// --- Summary ---
|
||||||
console.log();
|
console.log();
|
||||||
status('Issue', issue ? `#${issue.number} "${issue.title}"` : 'N/A');
|
status('Issue', issue ? `#${issue.number} "${issue.title}"` : 'N/A');
|
||||||
status('Branch', branch);
|
status('Branch', branch ?? '(current)');
|
||||||
status('Workflow', workflow);
|
status('Workflow', workflow);
|
||||||
status('Result', 'Success', 'green');
|
status('Result', 'Success', 'green');
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user