-
Notifications
You must be signed in to change notification settings - Fork 10
/
install.js
148 lines (119 loc) · 4.16 KB
/
install.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const fs = require('fs');
const path = require('path');
const detectGitDir = require('./git-dir');
// Hard to catch this output if there's no new-line after the script runs.
process.on('exit', () => console.log());
function env(name) {
if (!process.env[name]) {
throw new Error(`Required environment variable is empty or not defined - are you using an NPM-compatible package manager?: ${name}`);
}
return process.env[name];
}
const nodeBin = env('npm_node_execpath');
const packageManagerBin = env('npm_execpath');
const gitDir = detectGitDir();
if (!gitDir || !fs.existsSync(gitDir) || !fs.statSync(gitDir).isDirectory()) {
console.error('△ @vercel/git-hooks: .git directory not found or is not a directory; ignoring Git hook installation:', gitDir || 'reached filesystem boundary (root or drive)');
process.exit(0);
}
const hooksDir = path.join(gitDir, 'hooks');
const hook = `#!/usr/bin/env bash
# !! AUTO-GENERATED FILE !!
# Do not edit manually. This file was generated by @vercel/git-hooks, located at ${__dirname}.
# These values were generated at install-time.
# If they are incorrect, either re-install the package's dependencies (by
# wiping node_modules), or submitting an issue at https://github.com/vercel/git-hooks/issues
# for any incorrect detection functionality.
set -euo pipefail
if [ ! -z "\${ZEIT_GITHOOKS_RUNNING-}" ]; then
echo "△ ERROR: Refusing to run a nested git hook for fear of an endless loop." >&2
echo " You may \`unset ZEIT_GITHOOKS_RUNNING\` prior to running a nested" >&2
echo " Git command." >&2
echo >&2
exit 1
fi
export ZEIT_GITHOOKS_RUNNING=1
arg0="$(basename \${0})"
if [[ "\${arg0}" == "_do_hook.cjs" ]]; then
echo "You probably didn't mean to call this directly." >&2
exit 2
fi
"${nodeBin}" "$(dirname "\${0}")/_detect_package_hooks.cjs" "\${arg0}" | while IFS='' read -r hook || [[ -n "\${hook}" ]]; do
echo "△ run hook: \${arg0} -> \${hook}" >&2
if [[ $# -gt 0 ]]; then
"${nodeBin}" "${packageManagerBin}" run "\${hook}" -- "$@"
else
"${nodeBin}" "${packageManagerBin}" run "\${hook}"
fi
echo >&2
done
`;
const hookDetector = `
const fs = require('fs');
const path = require('path');
const hook = process.argv[2];
const scriptHook = \`git-\${hook}\`;
const packagePath = path.join(__dirname, '../../package.json');
if (fs.existsSync(packagePath) && fs.statSync(packagePath).isFile()) {
const pkg = require(packagePath);
const hooks = [];
if (pkg && typeof pkg.scripts === 'object' && scriptHook in pkg.scripts) {
hooks.push(scriptHook);
} else if (pkg && typeof pkg.git === 'object' && hook in pkg.git) {
if (typeof pkg.git[hook] === 'string') {
hooks.push(pkg.git[hook]);
} else if (Array.isArray(pkg.git[hook])) {
hooks.push(...pkg.git[hook]);
}
}
if (hooks.length > 0) {
console.log(hooks.join('\\n'));
}
}
`;
// Create hooks directory if necessary
if (!fs.existsSync(hooksDir)) {
fs.mkdirSync(hooksDir);
} else if (!fs.statSync(hooksDir).isDirectory()) {
throw new Error(`@vercel/git-hooks: .git/hooks directory exists but is not a directory - this is most likely an error on your part: ${hooksDir}`);
}
// Write the hook and detector script
function writeExecutable(path, ...args) {
fs.writeFileSync(path, ...args);
fs.chmodSync(path, 0o755);
}
console.error(`△ @vercel/git-hooks: installing base hook to ${hooksDir}`);
writeExecutable(path.join(hooksDir, '_do_hook.cjs'), hook, 'utf-8');
writeExecutable(path.join(hooksDir, '_detect_package_hooks.cjs'), hookDetector, 'utf-8');
// Populate each of the hooks
function installHook(name) {
const hookPath = path.join(hooksDir, name);
if (fs.existsSync(hookPath)) {
console.error(`△ @vercel/git-hooks: hook '${name}' already exists; skipping: ${hookPath}`);
return;
}
fs.symlinkSync('./_do_hook.cjs', hookPath);
}
[
'applypatch-msg',
'pre-applypatch',
'post-applypatch',
'pre-commit',
'prepare-commit-msg',
'commit-msg',
'post-commit',
'pre-rebase',
'post-checkout',
'post-merge',
'pre-push',
'pre-receive',
'update',
'post-receive',
'post-update',
'push-to-checkout',
'pre-auto-gc',
'post-rewrite',
'rebase',
'sendemail-validate'
].forEach(installHook);
console.error('△ @vercel/git-hooks: hooks installed successfully');