From d43d9f81d0275b0f7bdfd50f90f21dc987a14a86 Mon Sep 17 00:00:00 2001 From: kdletters Date: Mon, 20 Apr 2026 09:07:09 +0000 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=BB=BB=E5=8A=A1=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E8=84=9A=E6=9C=AC=E6=B5=8B=E8=AF=95=E8=A6=86=E7=9B=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md | 7 ++ scripts/commit-task.mjs | 5 +- scripts/commit-task.test.ts | 87 +++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 scripts/commit-task.test.ts diff --git a/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md b/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md index 76a179c6..874b52b5 100644 --- a/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md +++ b/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md @@ -69,3 +69,10 @@ node scripts/commit-task.mjs \ 1. 用户明确表示任务完成,或直接要求提交时,优先使用这条工作流。 2. 若当前任务文件边界清晰,则直接提交。 3. 若边界不清晰,则先停下并说明风险,不强行提交。 + +## 7. 验证 + +当前已补: + +1. `scripts/commit-task.test.ts` +2. 覆盖“只提交指定文件,保留未指定改动在工作区”的核心行为 diff --git a/scripts/commit-task.mjs b/scripts/commit-task.mjs index c3d47881..a9600054 100644 --- a/scripts/commit-task.mjs +++ b/scripts/commit-task.mjs @@ -2,6 +2,8 @@ import { spawnSync } from 'node:child_process'; +const repoRoot = process.env.GENARRATIVE_COMMIT_REPO_ROOT?.trim() || '/home/Genarrative'; + function fail(message) { console.error(`[commit-task] ${message}`); process.exit(1); @@ -9,7 +11,7 @@ function fail(message) { function runGit(args, options = {}) { const result = spawnSync('git', args, { - cwd: '/home/Genarrative', + cwd: repoRoot, encoding: 'utf8', stdio: ['inherit', 'pipe', 'pipe'], ...options, @@ -53,4 +55,3 @@ if (!stagedOutput) { } runGit(['commit', '-m', message], { stdio: 'inherit' }); - diff --git a/scripts/commit-task.test.ts b/scripts/commit-task.test.ts new file mode 100644 index 00000000..a2a43715 --- /dev/null +++ b/scripts/commit-task.test.ts @@ -0,0 +1,87 @@ +import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, resolve } from 'node:path'; +import { spawnSync } from 'node:child_process'; + +import { afterEach, describe, expect, it } from 'vitest'; + +function run(command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv) { + return spawnSync(command, args, { + cwd, + encoding: 'utf8', + env: { + ...process.env, + ...env, + }, + }); +} + +function mustRun(command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv) { + const result = run(command, args, cwd, env); + if (result.status !== 0) { + throw new Error( + `${command} ${args.join(' ')} failed:\n${result.stdout}\n${result.stderr}`, + ); + } + return result; +} + +describe('commit-task script', () => { + const tempDirs: string[] = []; + + afterEach(() => { + while (tempDirs.length > 0) { + rmSync(tempDirs.pop()!, { recursive: true, force: true }); + } + }); + + it('commits only the specified files', () => { + const repoRoot = mkdtempSync(resolve(tmpdir(), 'genarrative-commit-task-')); + tempDirs.push(repoRoot); + + mustRun('git', ['init'], repoRoot); + mustRun('git', ['config', 'user.name', 'Codex Test'], repoRoot); + mustRun('git', ['config', 'user.email', 'codex@example.com'], repoRoot); + + mkdirSync(resolve(repoRoot, 'docs'), { recursive: true }); + mkdirSync(resolve(repoRoot, 'notes'), { recursive: true }); + writeFileSync(resolve(repoRoot, 'docs', 'task.md'), 'v1\n', 'utf8'); + writeFileSync(resolve(repoRoot, 'notes', 'other.md'), 'other v1\n', 'utf8'); + + mustRun('git', ['add', '.'], repoRoot); + mustRun('git', ['commit', '-m', 'init'], repoRoot); + + writeFileSync(resolve(repoRoot, 'docs', 'task.md'), 'v2\n', 'utf8'); + writeFileSync(resolve(repoRoot, 'notes', 'other.md'), 'other v2\n', 'utf8'); + + const scriptPath = resolve('/home/Genarrative/scripts/commit-task.mjs'); + const commitResult = mustRun( + 'node', + [scriptPath, '-m', '提交任务文件', 'docs/task.md'], + repoRoot, + { + GENARRATIVE_COMMIT_REPO_ROOT: repoRoot, + }, + ); + + expect(commitResult.stdout).toContain('提交任务文件'); + + const committedTaskContent = mustRun( + 'git', + ['show', 'HEAD:docs/task.md'], + repoRoot, + ).stdout; + expect(committedTaskContent).toBe('v2\n'); + + const committedOtherContent = mustRun( + 'git', + ['show', 'HEAD:notes/other.md'], + repoRoot, + ).stdout; + expect(committedOtherContent).toBe('other v1\n'); + + const statusResult = mustRun('git', ['status', '--short'], repoRoot); + expect(statusResult.stdout).toContain(' M notes/other.md'); + expect(statusResult.stdout).not.toContain('docs/task.md'); + }); +});