mirror of https://github.com/garrytan/gstack.git
fix(browse): skip .gitignore append when git already ignores .gstack/ (#2385)
Fixes #2385. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a3259400a3
commit
670af8bfbc
|
|
@ -78,6 +78,17 @@ export function resolveConfig(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isIgnoredByGit(projectDir: string, relPath: string): boolean {
|
||||||
|
try {
|
||||||
|
const proc = Bun.spawnSync(['git', 'check-ignore', '-q', '--', relPath], {
|
||||||
|
cwd: projectDir, stdout: 'pipe', stderr: 'pipe',
|
||||||
|
});
|
||||||
|
return proc.exitCode === 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the .gstack/ state directory if it doesn't exist.
|
* Create the .gstack/ state directory if it doesn't exist.
|
||||||
* Throws with a clear message on permission errors.
|
* Throws with a clear message on permission errors.
|
||||||
|
|
@ -96,6 +107,9 @@ export function ensureStateDir(config: BrowseConfig): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure .gstack/ is in the project's .gitignore
|
// Ensure .gstack/ is in the project's .gitignore
|
||||||
|
// First, check if git already ignores .gstack/ (via global excludes, .git/info/exclude, or parent .gitignore)
|
||||||
|
if (isIgnoredByGit(config.projectDir, '.gstack/')) return;
|
||||||
|
|
||||||
const gitignorePath = path.join(config.projectDir, '.gitignore');
|
const gitignorePath = path.join(config.projectDir, '.gitignore');
|
||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,41 @@ describe('config', () => {
|
||||||
expect(fs.existsSync(path.join(tmpDir, '.gitignore'))).toBe(false);
|
expect(fs.existsSync(path.join(tmpDir, '.gitignore'))).toBe(false);
|
||||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('leaves .gitignore alone when git already ignores .gstack/ globally', () => {
|
||||||
|
const { spawnSync } = require('child_process');
|
||||||
|
const tmpDir = path.join(os.tmpdir(), `browse-gitignore-global-${Date.now()}`);
|
||||||
|
fs.mkdirSync(tmpDir, { recursive: true });
|
||||||
|
|
||||||
|
// Set up a real git repo
|
||||||
|
spawnSync('git', ['init', '-q'], { cwd: tmpDir });
|
||||||
|
spawnSync('git', ['config', 'user.email', 'test@test.com'], { cwd: tmpDir });
|
||||||
|
spawnSync('git', ['config', 'user.name', 'Test'], { cwd: tmpDir });
|
||||||
|
|
||||||
|
// Write a global excludes file that ignores .gstack/
|
||||||
|
const excludesFile = path.join(tmpDir, 'global-gitignore');
|
||||||
|
fs.writeFileSync(excludesFile, '.gstack/\n');
|
||||||
|
spawnSync('git', ['config', 'core.excludesFile', excludesFile], { cwd: tmpDir });
|
||||||
|
|
||||||
|
// .gitignore exists but does NOT contain .gstack/
|
||||||
|
fs.writeFileSync(path.join(tmpDir, '.gitignore'), 'node_modules/\n');
|
||||||
|
spawnSync('git', ['add', '.gitignore'], { cwd: tmpDir });
|
||||||
|
spawnSync('git', ['commit', '-qm', 'init'], { cwd: tmpDir });
|
||||||
|
|
||||||
|
// Verify git knows .gstack/ is ignored
|
||||||
|
const check = spawnSync('git', ['check-ignore', '-q', '.gstack/'], { cwd: tmpDir });
|
||||||
|
expect(check.status).toBe(0);
|
||||||
|
|
||||||
|
const config = resolveConfig({ BROWSE_STATE_FILE: path.join(tmpDir, '.gstack', 'browse.json') });
|
||||||
|
ensureStateDir(config);
|
||||||
|
|
||||||
|
// .gitignore must NOT have been modified
|
||||||
|
const content = fs.readFileSync(path.join(tmpDir, '.gitignore'), 'utf-8');
|
||||||
|
expect(content).toBe('node_modules/\n');
|
||||||
|
expect(fs.existsSync(path.join(tmpDir, '.gstack'))).toBe(true);
|
||||||
|
|
||||||
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getRemoteSlug', () => {
|
describe('getRemoteSlug', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue