Add git hooks support and refactor info command

This commit is contained in:
Steve Yegge
2025-11-06 15:00:15 -08:00
parent c4eddf0de4
commit 991c6248ca
5 changed files with 118 additions and 0 deletions

107
cmd/bd/hooks.go Normal file
View File

@@ -0,0 +1,107 @@
package main
import (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"
)
const hookVersionPrefix = "# bd-hooks-version: "
// HookStatus represents the status of a single git hook
type HookStatus struct {
Name string
Installed bool
Version string
Outdated bool
}
// CheckGitHooks checks the status of bd git hooks in .git/hooks/
func CheckGitHooks() ([]HookStatus, error) {
hooks := []string{"pre-commit", "post-merge", "pre-push"}
statuses := make([]HookStatus, 0, len(hooks))
for _, hookName := range hooks {
status := HookStatus{
Name: hookName,
}
// Check if hook exists
hookPath := filepath.Join(".git", "hooks", hookName)
version, err := getHookVersion(hookPath)
if err != nil {
// Hook doesn't exist or couldn't be read
status.Installed = false
} else {
status.Installed = true
status.Version = version
// Check if outdated (compare to current bd version)
if version != "" && version != Version {
status.Outdated = true
}
}
statuses = append(statuses, status)
}
return statuses, nil
}
// getHookVersion extracts the version from a hook file
func getHookVersion(path string) (string, error) {
file, err := os.Open(path)
if err != nil {
return "", err
}
defer file.Close()
scanner := bufio.NewScanner(file)
// Read first few lines looking for version marker
lineCount := 0
for scanner.Scan() && lineCount < 10 {
line := scanner.Text()
if strings.HasPrefix(line, hookVersionPrefix) {
version := strings.TrimSpace(strings.TrimPrefix(line, hookVersionPrefix))
return version, nil
}
lineCount++
}
// No version found (old hook)
return "", nil
}
// FormatHookWarnings returns a formatted warning message if hooks are outdated
func FormatHookWarnings(statuses []HookStatus) string {
var warnings []string
missingCount := 0
outdatedCount := 0
for _, status := range statuses {
if !status.Installed {
missingCount++
} else if status.Outdated {
outdatedCount++
}
}
if missingCount > 0 {
warnings = append(warnings, fmt.Sprintf("⚠️ Git hooks not installed (%d missing)", missingCount))
warnings = append(warnings, " Run: examples/git-hooks/install.sh")
}
if outdatedCount > 0 {
warnings = append(warnings, fmt.Sprintf("⚠️ Git hooks are outdated (%d hooks)", outdatedCount))
warnings = append(warnings, " Run: examples/git-hooks/install.sh")
}
if len(warnings) > 0 {
return strings.Join(warnings, "\n")
}
return ""
}

View File

@@ -196,6 +196,14 @@ Examples:
}
}
// Check git hooks status
hookStatuses, err := CheckGitHooks()
if err == nil {
if warning := FormatHookWarnings(hookStatuses); warning != "" {
fmt.Printf("\n%s\n", warning)
}
}
fmt.Println()
},
}

View File

@@ -1,4 +1,5 @@
#!/bin/sh
# bd-hooks-version: 0.22.0
#
# bd (beads) post-merge hook
#

View File

@@ -1,4 +1,5 @@
#!/bin/sh
# bd-hooks-version: 0.22.0
#
# bd (beads) pre-commit hook
#

View File

@@ -1,4 +1,5 @@
#!/bin/sh
# bd-hooks-version: 0.22.0
#
# bd (beads) pre-push hook
#