stageAndCommit の IT 追加: gitignored ファイルがコミットされないことを検証

git add -f .takt/reports/ リグレッション (c89ac4c) の再発防止テスト
This commit is contained in:
nrslib 2026-02-06 16:24:54 +09:00
parent 8c83cf60f9
commit 7c928e0385

View File

@ -0,0 +1,85 @@
/**
* Integration test for stageAndCommit
*
* Tests that gitignored files are NOT included in commits.
* Regression test for c89ac4c where `git add -f .takt/reports/` caused
* gitignored report files to be committed.
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdirSync, writeFileSync, rmSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { execFileSync } from 'node:child_process';
import { tmpdir } from 'node:os';
import { stageAndCommit } from '../infra/task/git.js';
describe('stageAndCommit', () => {
let testDir: string;
beforeEach(() => {
testDir = join(tmpdir(), `takt-test-${Date.now()}`);
mkdirSync(testDir, { recursive: true });
execFileSync('git', ['init'], { cwd: testDir });
execFileSync('git', ['config', 'user.name', 'Test User'], { cwd: testDir });
execFileSync('git', ['config', 'user.email', 'test@example.com'], { cwd: testDir });
// Initial commit
writeFileSync(join(testDir, 'README.md'), '# Test');
execFileSync('git', ['add', '.'], { cwd: testDir });
execFileSync('git', ['commit', '-m', 'Initial commit'], { cwd: testDir });
});
afterEach(() => {
if (existsSync(testDir)) {
rmSync(testDir, { recursive: true, force: true });
}
});
it('should not commit gitignored .takt/reports/ files', () => {
// Setup: .takt/ is gitignored
writeFileSync(join(testDir, '.gitignore'), '.takt/\n');
execFileSync('git', ['add', '.gitignore'], { cwd: testDir });
execFileSync('git', ['commit', '-m', 'Add gitignore'], { cwd: testDir });
// Create .takt/reports/ with a report file
mkdirSync(join(testDir, '.takt', 'reports', 'test-report'), { recursive: true });
writeFileSync(join(testDir, '.takt', 'reports', 'test-report', '00-plan.md'), '# Plan');
// Also create a tracked file change to ensure commit happens
writeFileSync(join(testDir, 'src.ts'), 'export const x = 1;');
const hash = stageAndCommit(testDir, 'test commit');
expect(hash).toBeDefined();
// Verify .takt/reports/ is NOT in the commit
const committedFiles = execFileSync('git', ['diff-tree', '--no-commit-id', '-r', '--name-only', 'HEAD'], {
cwd: testDir,
encoding: 'utf-8',
stdio: 'pipe',
}).trim();
expect(committedFiles).toContain('src.ts');
expect(committedFiles).not.toContain('.takt/reports/');
});
it('should commit normally when no gitignored files exist', () => {
writeFileSync(join(testDir, 'app.ts'), 'console.log("hello");');
const hash = stageAndCommit(testDir, 'add app');
expect(hash).toBeDefined();
const committedFiles = execFileSync('git', ['diff-tree', '--no-commit-id', '-r', '--name-only', 'HEAD'], {
cwd: testDir,
encoding: 'utf-8',
stdio: 'pipe',
}).trim();
expect(committedFiles).toBe('app.ts');
});
it('should return undefined when there are no changes', () => {
const hash = stageAndCommit(testDir, 'empty');
expect(hash).toBeUndefined();
});
});