Skip to content

Commit ac934d2

Browse files
committed
chore: wip
1 parent 214fc4d commit ac934d2

File tree

4 files changed

+69
-5
lines changed

4 files changed

+69
-5
lines changed

bin/cli.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,27 @@ if (['1', 'true'].includes(SKIP_INSTALL_GIT_HOOKS || '')) {
2222
cli
2323
.command('[configPath]', 'Install git hooks, optionally from specified config file')
2424
.option('--verbose', 'Enable verbose logging')
25+
.option('--force', 'Force reinstall hooks even if already installed')
2526
.example('git-hooks')
2627
.example('git-hooks ../src/config.ts')
2728
.example('git-hooks --verbose')
28-
.action(async (configPath?: string, options?: { verbose?: boolean }) => {
29+
.example('git-hooks --force')
30+
.action(async (configPath?: string, options?: { verbose?: boolean, force?: boolean }) => {
2931
try {
3032
if (options?.verbose) {
3133
log.debug(`Config path: ${configPath || 'using default'}`)
3234
log.debug(`Working directory: ${process.cwd()}`)
3335
}
3436

37+
// Check if hooks are already installed unless --force is used
38+
if (!options?.force) {
39+
const { areHooksInstalled } = await import('../src/git-hooks')
40+
if (areHooksInstalled(process.cwd())) {
41+
log.info('Git hooks are already installed. Use --force to reinstall.')
42+
process.exit(0)
43+
}
44+
}
45+
3546
if (configPath) {
3647
const config = await import(configPath)
3748
setHooksFromConfig(process.cwd(), { configFile: config, verbose: options?.verbose ?? false })

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"git-hooks": "./dist/bin/cli.js",
4242
"bun-git-hooks": "./dist/bin/cli.js"
4343
},
44-
"files": ["README.md", "dist"],
44+
"files": ["README.md", "dist", "scripts"],
4545
"scripts": {
4646
"build": "bun build.ts && bun run compile",
4747
"compile": "bun build ./bin/cli.ts --compile --minify --outfile bin/git-hooks",
@@ -51,7 +51,7 @@
5151
"compile:windows-x64": "bun build ./bin/cli.ts --compile --minify --target=bun-windows-x64 --outfile bin/git-hooks-windows-x64.exe",
5252
"compile:darwin-x64": "bun build ./bin/cli.ts --compile --minify --target=bun-darwin-x64 --outfile bin/git-hooks-darwin-x64",
5353
"compile:darwin-arm64": "bun build ./bin/cli.ts --compile --minify --target=bun-darwin-arm64 --outfile bin/git-hooks-darwin-arm64",
54-
"postinstall": "bunx git-hooks && bun ./scripts/postinstall.ts",
54+
"postinstall": "bun ./scripts/postinstall.ts",
5555
"uninstall": "bun ./scripts/uninstall.ts",
5656
"fresh": "bunx rimraf node_modules/ bun.lock && bun i",
5757
"prepublishOnly": "bun --bun run build && bun run compile:all",

scripts/postinstall.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { mkdir, symlink } from 'node:fs/promises'
44
import { join } from 'node:path'
55
import process from 'node:process'
6-
import { checkBunGitHooksInDependencies, getProjectRootDirectoryFromNodeModules, setHooksFromConfig } from '../src/git-hooks'
6+
import { areHooksInstalled, checkBunGitHooksInDependencies, getProjectRootDirectoryFromNodeModules, setHooksFromConfig } from '../src/git-hooks'
77

88
/**
99
* Creates the pre-commit from command in config by default
@@ -42,7 +42,14 @@ async function postinstall() {
4242

4343
if (checkBunGitHooksInDependencies(projectDirectory)) {
4444
try {
45+
// Check if hooks are already installed to avoid unnecessary reinstalls
46+
if (areHooksInstalled(projectDirectory)) {
47+
console.log('[INFO] Git hooks are already installed, skipping setup')
48+
return
49+
}
50+
4551
setHooksFromConfig(projectDirectory)
52+
console.log('[INFO] Git hooks installed successfully')
4653
}
4754
catch (err) {
4855
console.log(`[ERROR] Was not able to set git hooks. Reason: ${err}`)

src/git-hooks.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,50 @@ function _getPackageJson(projectPath = process.cwd()): { packageJsonContent: any
185185
return { packageJsonContent: JSON.parse(packageJsonDataRaw), packageJsonPath: targetPackageJson }
186186
}
187187

188+
/**
189+
* Checks if git hooks are already installed and up-to-date
190+
*/
191+
export function areHooksInstalled(projectRootPath: string = process.cwd()): boolean {
192+
const gitRoot = getGitProjectRoot(projectRootPath)
193+
if (!gitRoot) {
194+
return false
195+
}
196+
197+
if (!config || Object.keys(config).length === 0) {
198+
return false
199+
}
200+
201+
// Check if at least one configured hook exists and contains our script marker
202+
const configuredHooks = Object.keys(config).filter(key =>
203+
VALID_GIT_HOOKS.includes(key as typeof VALID_GIT_HOOKS[number])
204+
)
205+
206+
if (configuredHooks.length === 0) {
207+
return false
208+
}
209+
210+
// Check if all configured hooks exist
211+
for (const hook of configuredHooks) {
212+
const hookPath = path.normalize(path.join(gitRoot, 'hooks', hook))
213+
if (!fs.existsSync(hookPath)) {
214+
return false
215+
}
216+
217+
// Verify the hook contains our prepend script (marker of our installation)
218+
try {
219+
const hookContent = fs.readFileSync(hookPath, 'utf-8')
220+
if (!hookContent.includes('SKIP_BUN_GIT_HOOKS')) {
221+
return false
222+
}
223+
}
224+
catch {
225+
return false
226+
}
227+
}
228+
229+
return true
230+
}
231+
188232
/**
189233
* Parses the config and sets git hooks
190234
*/
@@ -524,6 +568,7 @@ const gitHooks: {
524568
getGitProjectRoot: typeof getGitProjectRoot
525569
runStagedLint: typeof runStagedLint
526570
getStagedFiles: typeof getStagedFiles
571+
areHooksInstalled: typeof areHooksInstalled
527572
} = {
528573
PREPEND_SCRIPT,
529574
setHooksFromConfig,
@@ -532,7 +577,8 @@ const gitHooks: {
532577
getProjectRootDirectoryFromNodeModules,
533578
getGitProjectRoot,
534579
runStagedLint,
535-
getStagedFiles
580+
getStagedFiles,
581+
areHooksInstalled
536582
}
537583

538584
export default gitHooks

0 commit comments

Comments
 (0)