Skip to content

Commit

Permalink
tools: Read git output line-by-line in pre-push hook (#38860)
Browse files Browse the repository at this point in the history
PR #38734 increased the buffer size, but it's probably safer to update
the code to read the output line-by-line instead. So let's do that.
  • Loading branch information
anomiex authored Aug 19, 2024
1 parent 1806b17 commit 37bbe9b
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .husky/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
if test -c /dev/tty && sh -c ': < /dev/tty' >/dev/null 2>/dev/null; then
exec < /dev/tty
fi
node tools/js-tools/git-hooks/pre-push-hook.js
node tools/js-tools/git-hooks/pre-push-hook.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,65 @@
#!/usr/bin/env node

/* eslint-disable no-console */
const { spawnSync } = require( 'child_process' );
const chalk = require( 'chalk' );
const isJetpackDraftMode = require( './jetpack-draft' );
import { spawn, spawnSync } from 'child_process';
import { fileURLToPath } from 'url';
import chalk from 'chalk';
import isJetpackDraftMode from './jetpack-draft.js';

/**
* Exec a command and collect the lines.
*
* @param {string} cmd - Command.
* @param {string[]} args - Arguments.
* @param {object} options - Options.
* @returns {string[]} Lines of output.
*/
async function spawnAndReadStdout( cmd, args, options = {} ) {
const lines = [];

await new Promise( ( resolve, reject ) => {
let buffer = '';

const proc = spawn( cmd, args, {
...options,
stdio: [ 'ignore', 'pipe', 'inherit' ],
} );

proc.stdout.on( 'data', data => {
buffer += data.toString();
let i;
while ( ( i = buffer.indexOf( '\n' ) ) >= 0 ) {
lines.push( buffer.substring( 0, i ) );
buffer = buffer.substring( i + 1 );
}
} );

proc.on( 'close', code => {
if ( buffer !== '' ) {
lines.push( buffer );
}
if ( code !== 0 ) {
reject( new Error( `Command failed with code ${ code }` ) );
} else {
resolve();
}
} );

proc.on( 'error', err => {
reject( err );
} );
} );

return lines;
}

/**
* Checks for filename collsisions on case-insensitive file systems.
*
* This is probably impossible to get 100% right due to potential locale
* differences in filesystem case folding, but this should be most of the way there.
*/
function checkFilenameCollisions() {
async function checkFilenameCollisions() {
if ( process.exitCode !== 0 ) {
return;
}
Expand All @@ -20,15 +68,16 @@ function checkFilenameCollisions() {

const compare = Intl.Collator( 'und', { sensitivity: 'accent' } ).compare;

const files = spawnSync(
'git',
[ '-c', 'core.quotepath=off', 'ls-tree', '-rt', '--name-only', 'HEAD' ],
{ maxBuffer: 4096 * 1024 }
)
.stdout.toString()
.trim()
.split( '\n' )
.sort( compare );
const files = (
await spawnAndReadStdout( 'git', [
'-c',
'core.quotepath=off',
'ls-tree',
'-rt',
'--name-only',
'HEAD',
] )
).sort( compare );

const collisions = new Set();
let prev = null;
Expand Down Expand Up @@ -71,7 +120,7 @@ function pushAgain() {
/**
* Checks if changelog files are required.
*/
function checkChangelogFiles() {
async function checkChangelogFiles() {
if ( process.exitCode !== 0 ) {
return;
}
Expand All @@ -97,7 +146,7 @@ function checkChangelogFiles() {
[ '--maybe-merge', 'origin/trunk', 'HEAD' ],
{
stdio: 'inherit',
cwd: __dirname + '/../../../',
cwd: fileURLToPath( new URL( '../../../', import.meta.url ) ),
}
);

Expand Down Expand Up @@ -128,17 +177,14 @@ function checkChangelogFiles() {
// If the autochangelogger worked, commit the changelog files.
if ( autoChangelog.status === 0 ) {
const filesToCommit = [];
const changelogFiles = spawnSync( 'git', [
const changelogFiles = await spawnAndReadStdout( 'git', [
'-c',
'core.quotepath=off',
'diff',
'--name-only',
'--diff-filter=A',
'--cached',
] )
.stdout.toString()
.trim()
.split( '\n' );
] );

for ( const file of changelogFiles ) {
const match = file.match( /^projects\/([^/]+\/[^/]+)\/changelog\// );
Expand All @@ -161,5 +207,5 @@ function checkChangelogFiles() {
}

process.exitCode = 0;
checkFilenameCollisions();
checkChangelogFiles();
await checkFilenameCollisions();
await checkChangelogFiles();

0 comments on commit 37bbe9b

Please sign in to comment.