Skip to content

Commit 5d826bb

Browse files
committed
chore: fold in fixes from open PRs (#127, #148, #112)
Addresses long-standing open PRs whose intent fits the cross-spawn / hook-hardening cleanup: * #127 - install.js: "backuped" -> "backed up". * #148 - magit workaround: emit `unset GIT_LITERAL_PATHSPECS` in the generated `.git/hooks/pre-commit` wrapper, and also at the top of the package's `hook` script for defense-in-depth, so hooks invoked from emacs/magit behave the same as on the command line. * #112 - resilience for missing pre-commit package: when a user switches to a branch without `node_modules`, the generated wrapper now exits 0 instead of failing the commit, and the `hook` script detects an unresolvable `pre-commit` package and skips with a friendly warning instead of throwing a Node module-not-found stack. Made-with: Cursor
1 parent c610f14 commit 5d826bb

2 files changed

Lines changed: 47 additions & 5 deletions

File tree

hook

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
#!/usr/bin/env bash
22

3+
#
4+
# Defense-in-depth for magit (the .git/hooks wrapper unsets it too); ensures
5+
# hooks invoked from emacs/magit behave the same as on the CLI.
6+
# https://magit.vc/manual/magit/My-Git-hooks-work-on-the-command_002dline-but-not-inside-Magit.html
7+
#
8+
unset GIT_LITERAL_PATHSPECS
9+
310
HAS_NODE=`which node 2> /dev/null || which nodejs 2> /dev/null || which iojs 2> /dev/null`
411

512
#
@@ -46,14 +53,32 @@ if [[ -n "$REPO_ROOT" ]]; then
4653
cd "$REPO_ROOT" || exit 1
4754
fi
4855

56+
#
57+
# Resolve the entry point of the `pre-commit` package via Node so we work for
58+
# Yarn Plug'n'Play, hoisted, and nested layouts. If the package cannot be
59+
# resolved (e.g. the user switched to a branch with no `node_modules`, or
60+
# uninstalled `pre-commit`) skip the hook with exit 0 instead of failing the
61+
# commit -- a missing dev dependency must not block work.
62+
#
63+
RESOLVED=
64+
RESOLVE_RC=1
65+
if [[ -n "$BINARY" ]]; then
66+
RESOLVED="$("$BINARY" -e "try { console.log(require.resolve('pre-commit')); } catch (e) { process.exit(2); }" 2>/dev/null)"
67+
RESOLVE_RC=$?
68+
fi
69+
4970
#
5071
# Add --dry-run cli flag support so we can execute this hook without side effects
5172
# and see if it works in the current environment
5273
#
5374
if [[ $* == *--dry-run* ]]; then
54-
if [[ -z "$BINARY" ]]; then
75+
if [[ -z "$BINARY" ]] || [[ "$RESOLVE_RC" -ne 0 ]] || [[ -z "$RESOLVED" ]]; then
5576
exit 1
5677
fi
5778
else
58-
exec "$BINARY" "$("$BINARY" -e "console.log(require.resolve('pre-commit'))")"
79+
if [[ "$RESOLVE_RC" -ne 0 ]] || [[ -z "$RESOLVED" ]]; then
80+
echo "pre-commit: 'pre-commit' package is not installed; skipping hooks (run \`npm install\` to re-enable)." >&2
81+
exit 0
82+
fi
83+
exec "$BINARY" "$RESOLVED"
5984
fi

install.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ if (exists(precommit) && !fs.lstatSync(precommit).isSymbolicLink()) {
8989
console.log('pre-commit:');
9090
console.log('pre-commit: Detected an existing git pre-commit hook');
9191
fs.writeFileSync(precommit +'.old', fs.readFileSync(precommit));
92-
console.log('pre-commit: Old pre-commit hook backuped to pre-commit.old');
92+
console.log('pre-commit: Old pre-commit hook backed up to pre-commit.old');
9393
console.log('pre-commit:');
9494
}
9595

@@ -109,8 +109,25 @@ if (os.platform() === 'win32') {
109109
hookLauncher = hookLauncher.replace(/\\/g, '/');
110110
}
111111

112-
var precommitContent = '#!/usr/bin/env bash' + os.EOL
113-
+ 'exec bash ' + shellSingleQuote(hookLauncher) + ' "$@"' + os.EOL;
112+
//
113+
// Generated wrapper:
114+
// * Unsets GIT_LITERAL_PATHSPECS so hooks invoked from magit/emacs behave the
115+
// same as on the command line. See:
116+
// https://magit.vc/manual/magit/My-Git-hooks-work-on-the-command_002dline-but-not-inside-Magit.html
117+
// * If the package's `hook` script is missing (e.g. user switched to a branch
118+
// without `node_modules`, or removed the `pre-commit` package), skip
119+
// silently with exit 0 so commits are not blocked.
120+
//
121+
var precommitContent = [
122+
'#!/usr/bin/env bash',
123+
'unset GIT_LITERAL_PATHSPECS',
124+
'HOOK=' + shellSingleQuote(hookLauncher),
125+
'if [ ! -f "$HOOK" ]; then',
126+
' exit 0',
127+
'fi',
128+
'exec bash "$HOOK" "$@"',
129+
''
130+
].join(os.EOL);
114131

115132
//
116133
// It could be that we do not have rights to this folder which could cause the

0 commit comments

Comments
 (0)