fix: run pre-bash linters through windows wrappers

This commit is contained in:
Affaan Mustafa 2026-04-29 18:50:46 -04:00 committed by Affaan Mustafa
parent ae02b26cf9
commit b5bdd9352f
2 changed files with 61 additions and 22 deletions

View File

@ -188,6 +188,54 @@ function validateCommitMessage(command) {
return { message, issues }; return { message, issues };
} }
function getPathEnv() {
const pathKey = Object.keys(process.env).find(key => key.toLowerCase() === 'path') || 'PATH';
return process.env[pathKey] || '';
}
function isPathLike(command) {
return command.includes(path.sep) || (process.platform === 'win32' && /[\\/]/.test(command));
}
function getExecutableCandidates(command) {
if (process.platform !== 'win32' || path.extname(command)) {
return [command];
}
const pathExt = process.env.PATHEXT || '.COM;.EXE;.BAT;.CMD';
return [command, ...pathExt.split(';').filter(Boolean).map(ext => `${command}${ext.toLowerCase()}`)];
}
function resolveCommand(command) {
if (isPathLike(command)) {
return getExecutableCandidates(command).find(candidate => fs.existsSync(candidate)) || null;
}
for (const dir of getPathEnv().split(path.delimiter).filter(Boolean)) {
for (const candidate of getExecutableCandidates(path.join(dir, command))) {
if (fs.existsSync(candidate)) {
return candidate;
}
}
}
return null;
}
function runLinterCommand(command, args) {
const useShell = process.platform === 'win32' && /\.(?:cmd|bat)$/i.test(command);
return spawnSync(command, args, {
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 30000,
shell: useShell
});
}
function commandOutput(result) {
return result.stdout || result.stderr || result.error?.message || '';
}
/** /**
* Run linter on staged files * Run linter on staged files
* @param {string[]} files * @param {string[]} files
@ -209,14 +257,10 @@ function runLinter(files) {
const eslintBin = process.platform === 'win32' ? 'eslint.cmd' : 'eslint'; const eslintBin = process.platform === 'win32' ? 'eslint.cmd' : 'eslint';
const eslintPath = path.join(process.cwd(), 'node_modules', '.bin', eslintBin); const eslintPath = path.join(process.cwd(), 'node_modules', '.bin', eslintBin);
if (fs.existsSync(eslintPath)) { if (fs.existsSync(eslintPath)) {
const result = spawnSync(eslintPath, ['--format', 'compact', ...jsFiles], { const result = runLinterCommand(eslintPath, ['--format', 'compact', ...jsFiles]);
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 30000
});
results.eslint = { results.eslint = {
success: result.status === 0, success: result.status === 0,
output: result.stdout || result.stderr output: commandOutput(result)
}; };
} }
} }
@ -224,17 +268,14 @@ function runLinter(files) {
// Run Pylint if available // Run Pylint if available
if (pyFiles.length > 0) { if (pyFiles.length > 0) {
try { try {
const result = spawnSync('pylint', ['--output-format=text', ...pyFiles], { const pylintPath = resolveCommand('pylint');
encoding: 'utf8', if (!pylintPath) {
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 30000
});
if (result.error && result.error.code === 'ENOENT') {
results.pylint = null; results.pylint = null;
} else { } else {
const result = runLinterCommand(pylintPath, ['--output-format=text', ...pyFiles]);
results.pylint = { results.pylint = {
success: result.status === 0, success: result.status === 0,
output: result.stdout || result.stderr output: commandOutput(result)
}; };
} }
} catch { } catch {
@ -245,17 +286,14 @@ function runLinter(files) {
// Run golint if available // Run golint if available
if (goFiles.length > 0) { if (goFiles.length > 0) {
try { try {
const result = spawnSync('golint', goFiles, { const golintPath = resolveCommand('golint');
encoding: 'utf8', if (!golintPath) {
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 30000
});
if (result.error && result.error.code === 'ENOENT') {
results.golint = null; results.golint = null;
} else { } else {
const result = runLinterCommand(golintPath, goFiles);
results.golint = { results.golint = {
success: !result.stdout || result.stdout.trim() === '', success: !result.stdout || result.stdout.trim() === '',
output: result.stdout output: commandOutput(result)
}; };
} }
} catch { } catch {

View File

@ -274,11 +274,12 @@ if (test('stdin entry point truncates oversized input and preserves pass-through
filler: 'x'.repeat(1024 * 1024 + 1024) filler: 'x'.repeat(1024 * 1024 + 1024)
} }
}); });
const result = spawnSync('node', [path.join(__dirname, '..', '..', 'scripts', 'hooks', 'pre-bash-commit-quality.js')], { const result = spawnSync(process.execPath, [path.join(__dirname, '..', '..', 'scripts', 'hooks', 'pre-bash-commit-quality.js')], {
input: oversized, input: oversized,
encoding: 'utf8', encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe'], stdio: ['pipe', 'pipe', 'pipe'],
timeout: 10000 timeout: 10000,
maxBuffer: 2 * 1024 * 1024
}); });
assert.strictEqual(result.status, 0); assert.strictEqual(result.status, 0);