textmachine/frontend/scripts/githooks/install.mjs

58 lines
2.2 KiB
JavaScript

// Puts the dispatcher of the zone hooks into .git/hooks/pre-commit. Idempotent: its own one (by the
// marker) it overwrites with a fresh version, somebody else's it does not touch. Called from
// npm prepare — that is, every npm install/ci in frontend/ puts the protection in place itself, and
// a session has no separate step for it.
import { execSync } from 'node:child_process';
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
const MARKER = 'textmachine zone-hook dispatcher';
// The dispatcher is zone-neutral: every zone may put its own fragment into
// <zone>/scripts/githooks/pre-commit, and it is picked up with no edit to this file.
const dispatcher = `#!/bin/sh
# ${MARKER} v1 — generated by frontend/scripts/githooks/install.mjs; edits are overwritten.
status=0
for hook in */scripts/githooks/pre-commit; do
[ -x "$hook" ] || continue
"$hook" || status=1
done
exit $status
`;
/** @param {string} args */
function git(args) {
return execSync(`git ${args}`, { encoding: 'utf8' }).trim();
}
let gitDir;
try {
gitDir = git('rev-parse --git-common-dir');
} catch {
console.log('githooks: not a git repository — installing the hook was skipped');
process.exit(0);
}
let hooksPath = '';
try {
hooksPath = git('config core.hooksPath');
} catch {
// not set — the standard location, the path is below
}
if (hooksPath !== '') {
console.log(`githooks: core.hooksPath=${hooksPath} is set — I will not install into it.`);
console.log('Wire frontend/scripts/githooks/pre-commit into your own pre-commit by hand.');
process.exit(0);
}
const hooksDir = resolve(process.cwd(), gitDir, 'hooks');
const target = resolve(hooksDir, 'pre-commit');
if (existsSync(target) && !readFileSync(target, 'utf8').includes(MARKER)) {
console.log(`githooks: ${target} already exists and was written not by us — not overwriting.`);
console.log('Wire frontend/scripts/githooks/pre-commit into your own pre-commit by hand.');
process.exit(0);
}
mkdirSync(hooksDir, { recursive: true });
writeFileSync(target, dispatcher);
chmodSync(target, 0o755);
console.log(`githooks: the pre-commit dispatcher is installed → ${target}`);