fix(hooks): use session repository for console warnings

This commit is contained in:
haelyra committed 2026-10-25 19:32:16 -04:00
1 parent 605e006137
commit 0a7a9a718e
3 files changed
+63 -9

No files matched your search

+16 -3
View File
@@ -28,6 +28,18 @@ const EXCLUDED_PATTERNS = [
];
const MAX_DIRECT_STDIN_BYTES = 16 * 1024 * 1024;
// This Stop hook inspects the session's working directory. Inherited GIT_*
// variables from another Git process can silently redirect discovery and diff
// commands to a different repository, so give every Git call the same clean env.
function sessionGitOptions() {
const env = { ...process.env };
for (const name of Object.keys(env)) {
if (name.toUpperCase().startsWith('GIT_')) delete env[name];
}
return { env };
}
let data = '';
let stdinBytes = 0;
let oversized = false;
@@ -62,15 +74,16 @@ function passThroughAndExit() {
process.stdin.on('end', () => {
try {
if (!isGitRepo()) {
const gitOptions = sessionGitOptions();
if (!isGitRepo(gitOptions)) {
passThroughAndExit();
return;
}
// git reports paths from the repository root, and the session can run in a
// subdirectory of it, so read each file from the root.
const root = runCommand('git rev-parse --show-toplevel').output;
const files = getGitModifiedFiles(['\\.tsx?$', '\\.jsx?$'])
const root = runCommand('git rev-parse --show-toplevel', gitOptions).output;
const files = getGitModifiedFiles(['\\.tsx?$', '\\.jsx?$'], gitOptions)
.filter(f => fs.existsSync(path.join(root, f)))
.filter(f => !EXCLUDED_PATTERNS.some(pattern => pattern.test(f)));
+8 -6
View File
@@ -537,23 +537,25 @@ function runCommand(cmd, options = {}) {
}
/**
* Check if current directory is a git repository
* Check if current directory is a git repository.
* @param {object} [options] - Options forwarded to runCommand, including env.
*/
function isGitRepo() {
return runCommand('git rev-parse --git-dir').success;
function isGitRepo(options = {}) {
return runCommand('git rev-parse --git-dir', options).success;
}
/**
* Get git modified files, optionally filtered by regex patterns
* @param {string[]} patterns - Array of regex pattern strings to filter files.
* Invalid patterns are silently skipped.
* @param {object} [options] - Options forwarded to every Git subprocess.
* @returns {string[]} Array of modified file paths
*/
function getGitModifiedFiles(patterns = []) {
if (!isGitRepo()) return [];
function getGitModifiedFiles(patterns = [], options = {}) {
if (!isGitRepo(options)) return [];
// Paths from the repository root even when diff.relative is set.
const result = runCommand('git -c diff.relative=false diff --name-only HEAD');
const result = runCommand('git -c diff.relative=false diff --name-only HEAD', options);
if (!result.success) return [];
let files = result.output.split('\n').filter(Boolean);
+39
View File
@@ -1230,6 +1230,45 @@ async function runTests() {
passed++;
else failed++;
if (
await asyncTest('uses the session repository despite inherited Git environment overrides', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-console-git-env-'));
try {
const makeRepo = (name, file) => {
const repo = path.join(root, name);
fs.mkdirSync(path.join(repo, 'src'), { recursive: true });
execFileSync('git', ['init', '-q'], { cwd: repo });
fs.writeFileSync(path.join(repo, 'src', file), 'export const value = 1;\n');
execFileSync('git', ['add', '-A'], { cwd: repo });
execFileSync('git', ['-c', 'user.email=t@t.local', '-c', 'user.name=t', '-c', 'commit.gpgsign=false', 'commit', '-q', '-m', 'seed'], { cwd: repo });
return repo;
};
const sessionRepo = makeRepo('session', 'local.ts');
const foreignRepo = makeRepo('foreign', 'foreign.ts');
fs.writeFileSync(path.join(foreignRepo, 'src', 'foreign.ts'), 'console.log("foreign");\n');
const env = {
GIT_DIR: path.join(foreignRepo, '.git'),
GIT_WORK_TREE: foreignRepo,
GIT_INDEX_FILE: path.join(foreignRepo, '.git', 'index')
};
const clean = await runScript(path.join(scriptsDir, 'check-console-log.js'), '{}', env, sessionRepo);
assert.strictEqual(clean.code, 0);
assert.ok(!clean.stderr.includes('console.log found'), `foreign repository leaked into hook: ${clean.stderr}`);
fs.writeFileSync(path.join(sessionRepo, 'src', 'local.ts'), 'console.log("local");\n');
const local = await runScript(path.join(scriptsDir, 'check-console-log.js'), '{}', env, sessionRepo);
assert.strictEqual(local.code, 0);
assert.ok(local.stderr.includes('console.log found in src/local.ts'), local.stderr);
assert.ok(!local.stderr.includes('foreign.ts'), local.stderr);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
})
)
passed++;
else failed++;
// session-end.js tests
console.log('\nsession-end.js:');