diff --git a/scripts/git-hooks.test.mjs b/scripts/git-hooks.test.mjs index 17d37b228..7a51eeb4f 100644 --- a/scripts/git-hooks.test.mjs +++ b/scripts/git-hooks.test.mjs @@ -145,7 +145,7 @@ test('pre-commit hook fixes staged imports and formatting without swallowing uns 'const original = { value: 1 };\nconst keep = 2;\n', ); assert.equal( - readFileSync(partialPath, 'utf8'), + readFileSync(partialPath, 'utf8').replaceAll('\r\n', '\n'), 'const original = { value: 1 };\nconst keep={unstaged:true}\n', ); assert.equal( @@ -160,53 +160,73 @@ test('pre-commit hook fixes staged imports and formatting without swallowing uns test('pre-push runs repository parity only for master updates', () => { const tempDir = mkdtempSync(join(tmpdir(), 'genarrative-pre-push-')); try { - const binDir = join(tempDir, 'bin'); - mkdirSync(binDir); - const npmLog = join(tempDir, 'npm.log'); - const fakeNpm = join(binDir, 'npm'); - const fakeGit = join(binDir, 'git'); - writeFileSync( - fakeNpm, - `#!/usr/bin/env bash\nprintf '%s\\n' "$*" >> "${npmLog}"\n`, + const npmLog = join(tempDir, 'repo', 'npm.log'); + const tempRepo = join(tempDir, 'repo'); + mkdirSync(tempRepo); + git(tempRepo, 'init', '--quiet'); + git(tempRepo, 'config', 'user.email', 'git-hooks-test@example.invalid'); + git(tempRepo, 'config', 'user.name', 'Git Hooks Test'); + writeFileSync(join(tempRepo, 'tracked.txt'), 'baseline\n'); + git(tempRepo, 'add', 'tracked.txt'); + git( + tempRepo, + '-c', + 'commit.gpgsign=false', + 'commit', + '--quiet', + '-m', + 'baseline', ); - chmodSync(fakeNpm, 0o755); + const localSha = git(tempRepo, 'rev-parse', 'HEAD').trim(); writeFileSync( - fakeGit, - '#!/usr/bin/env bash\n' + - 'if [[ "$1" == "rev-parse" && "$2" == "HEAD" ]]; then\n' + - ' printf "%s\\n" "1111111111111111111111111111111111111111"\n' + - ' exit 0\n' + - 'fi\n' + - 'if [[ "$1" == "diff" ]]; then exit 0; fi\n' + - 'exit 1\n', + join(tempRepo, 'git'), + `#!/usr/bin/env bash +if [[ "$1" == 'rev-parse' && "$2" == 'HEAD' ]]; then + printf '%s\\n' '${localSha}' + exit 0 +fi +if [[ "$1" == 'diff' ]]; then exit 0; fi +exit 1 +`, ); - chmodSync(fakeGit, 0o755); - const env = { - ...process.env, - PATH: `${binDir}${delimiter}${process.env.PATH ?? ''}`, + chmodSync(join(tempRepo, 'git'), 0o755); + writeFileSync( + join(tempRepo, 'pre-push-master.sh'), + readFileSync(join(repoRoot, 'scripts', 'pre-push-master.sh'), 'utf8'), + ); + writeFileSync( + join(tempRepo, 'npm'), + '#!/usr/bin/env bash\nprintf \'%s\\n\' "$*" >> npm.log\n', + ); + chmodSync(join(tempRepo, 'npm'), 0o755); + const spawnHook = (input) => { + writeFileSync(join(tempRepo, 'push.input'), input); + return spawnSync( + 'bash', + [ + '-c', + 'PATH="$PWD:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; export PATH; source ./pre-push-master.sh origin example.invalid < push.input', + ], + { + cwd: tempRepo, + encoding: 'utf8', + env: process.env, + }, + ); }; - const hook = join(repoRoot, 'scripts', 'pre-push-master.sh'); - const featurePush = spawnSync('bash', [hook, 'origin', 'example.invalid'], { - cwd: repoRoot, - encoding: 'utf8', - env, - input: - 'refs/heads/feature 1111111111111111111111111111111111111111 refs/heads/feature 2222222222222222222222222222222222222222\n', - }); + const featurePush = spawnHook( + 'refs/heads/feature 1111111111111111111111111111111111111111 refs/heads/feature 2222222222222222222222222222222222222222\n', + ); assert.equal(featurePush.status, 0, featurePush.stderr); assert.equal(readFileOrEmpty(npmLog), ''); - const masterPush = spawnSync('bash', [hook, 'origin', 'example.invalid'], { - cwd: repoRoot, - encoding: 'utf8', - env, - input: - 'refs/heads/master 1111111111111111111111111111111111111111 refs/heads/master 2222222222222222222222222222222222222222\n', - }); + const masterPush = spawnHook( + `refs/heads/master ${localSha} refs/heads/master 2222222222222222222222222222222222222222\n`, + ); assert.equal(masterPush.status, 0, masterPush.stderr); assert.equal( readFileSync(npmLog, 'utf8'), - 'run check:repository-ci -- 2222222222222222222222222222222222222222 1111111111111111111111111111111111111111\n', + `run check:repository-ci -- 2222222222222222222222222222222222222222 ${localSha}\n`, ); } finally { rmSync(tempDir, { force: true, recursive: true }); @@ -254,6 +274,14 @@ function readFileOrEmpty(path) { } } +function toBashPath(path) { + const windowsDrive = /^([A-Za-z]):[\\/](.*)$/u.exec(path); + if (windowsDrive) { + return `/mnt/${windowsDrive[1].toLowerCase()}/${windowsDrive[2].replaceAll('\\', '/')}`; + } + return path; +} + function git(cwd, ...args) { return execFileSync('git', args, { cwd, encoding: 'utf8' }); }