fix(dolt): add hook compatibility check and migration warning
Two improvements for Dolt backend users with stale git hooks: 1. Migration warning: When running 'bd migrate --to-dolt', warn if installed hooks lack the Dolt backend check and suggest reinstalling. 2. Doctor check: New CheckGitHooksDoltCompatibility() detects when hooks exist but lack the Dolt skip logic, surfacing the error with a clear fix message. Both changes help users who migrated to Dolt but have pre-migration hooks that try to run JSONL sync (which fails with Dolt backend). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -281,6 +281,13 @@ func runDiagnostics(path string) doctorResult {
|
|||||||
result.OverallOK = false
|
result.OverallOK = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check git hooks Dolt compatibility (hooks without Dolt check cause errors)
|
||||||
|
doltHooksCheck := convertWithCategory(doctor.CheckGitHooksDoltCompatibility(path), doctor.CategoryGit)
|
||||||
|
result.Checks = append(result.Checks, doltHooksCheck)
|
||||||
|
if doltHooksCheck.Status == statusError {
|
||||||
|
result.OverallOK = false
|
||||||
|
}
|
||||||
|
|
||||||
// If no .beads/, skip remaining checks
|
// If no .beads/, skip remaining checks
|
||||||
if installCheck.Status != statusOK {
|
if installCheck.Status != statusOK {
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
_ "github.com/ncruces/go-sqlite3/driver"
|
_ "github.com/ncruces/go-sqlite3/driver"
|
||||||
_ "github.com/ncruces/go-sqlite3/embed"
|
_ "github.com/ncruces/go-sqlite3/embed"
|
||||||
"github.com/steveyegge/beads/cmd/bd/doctor/fix"
|
"github.com/steveyegge/beads/cmd/bd/doctor/fix"
|
||||||
|
"github.com/steveyegge/beads/internal/configfile"
|
||||||
"github.com/steveyegge/beads/internal/git"
|
"github.com/steveyegge/beads/internal/git"
|
||||||
"github.com/steveyegge/beads/internal/storage"
|
"github.com/steveyegge/beads/internal/storage"
|
||||||
"github.com/steveyegge/beads/internal/syncbranch"
|
"github.com/steveyegge/beads/internal/syncbranch"
|
||||||
@@ -760,6 +761,74 @@ func CheckSyncBranchHealth(path string) DoctorCheck {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckGitHooksDoltCompatibility checks if installed git hooks are compatible with Dolt backend.
|
||||||
|
// Hooks installed before Dolt support was added don't have the backend check and will
|
||||||
|
// fail with confusing errors on git pull/commit.
|
||||||
|
func CheckGitHooksDoltCompatibility(path string) DoctorCheck {
|
||||||
|
backend, beadsDir := getBackendAndBeadsDir(path)
|
||||||
|
|
||||||
|
// Only relevant for Dolt backend
|
||||||
|
if backend != configfile.BackendDolt {
|
||||||
|
return DoctorCheck{
|
||||||
|
Name: "Git Hooks Dolt Compatibility",
|
||||||
|
Status: StatusOK,
|
||||||
|
Message: "N/A (not using Dolt backend)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're in a git repository
|
||||||
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
|
if err != nil {
|
||||||
|
return DoctorCheck{
|
||||||
|
Name: "Git Hooks Dolt Compatibility",
|
||||||
|
Status: StatusOK,
|
||||||
|
Message: "N/A (not a git repository)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check post-merge hook (most likely to cause issues with Dolt)
|
||||||
|
postMergePath := filepath.Join(hooksDir, "post-merge")
|
||||||
|
content, err := os.ReadFile(postMergePath)
|
||||||
|
if err != nil {
|
||||||
|
// No hook installed - that's fine
|
||||||
|
return DoctorCheck{
|
||||||
|
Name: "Git Hooks Dolt Compatibility",
|
||||||
|
Status: StatusOK,
|
||||||
|
Message: "N/A (no post-merge hook installed)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentStr := string(content)
|
||||||
|
|
||||||
|
// Check if it's a bd hook
|
||||||
|
if !strings.Contains(contentStr, bdInlineHookMarker) && !strings.Contains(contentStr, "bd") {
|
||||||
|
return DoctorCheck{
|
||||||
|
Name: "Git Hooks Dolt Compatibility",
|
||||||
|
Status: StatusOK,
|
||||||
|
Message: "N/A (not a bd hook)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it has the Dolt backend skip logic
|
||||||
|
if strings.Contains(contentStr, `"backend"`) && strings.Contains(contentStr, `"dolt"`) {
|
||||||
|
return DoctorCheck{
|
||||||
|
Name: "Git Hooks Dolt Compatibility",
|
||||||
|
Status: StatusOK,
|
||||||
|
Message: "Hooks have Dolt backend check",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook exists but lacks Dolt check - this will cause errors
|
||||||
|
_ = beadsDir // silence unused warning
|
||||||
|
return DoctorCheck{
|
||||||
|
Name: "Git Hooks Dolt Compatibility",
|
||||||
|
Status: StatusError,
|
||||||
|
Message: "Git hooks incompatible with Dolt backend",
|
||||||
|
Detail: "Installed hooks attempt JSONL sync which fails with Dolt. This causes errors on git pull/commit.",
|
||||||
|
Fix: "Run 'bd hooks install --force' to update hooks for Dolt compatibility",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FixGitHooks fixes missing or broken git hooks by calling bd hooks install.
|
// FixGitHooks fixes missing or broken git hooks by calling bd hooks install.
|
||||||
func FixGitHooks(path string) error {
|
func FixGitHooks(path string) error {
|
||||||
return fix.GitHooks(path)
|
return fix.GitHooks(path)
|
||||||
|
|||||||
@@ -146,10 +146,44 @@ func handleToDoltMigration(dryRun bool, autoYes bool) {
|
|||||||
|
|
||||||
printSuccess("Updated metadata.json to use Dolt backend")
|
printSuccess("Updated metadata.json to use Dolt backend")
|
||||||
|
|
||||||
|
// Check if git hooks need updating for Dolt compatibility
|
||||||
|
if hooksNeedDoltUpdate(beadsDir) {
|
||||||
|
printWarning("Git hooks need updating for Dolt backend")
|
||||||
|
if !jsonOutput {
|
||||||
|
fmt.Println(" The pre-commit and post-merge hooks use JSONL sync which doesn't apply to Dolt.")
|
||||||
|
fmt.Println(" Run 'bd hooks install --force' to update them.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Final status
|
// Final status
|
||||||
printFinalStatus("dolt", imported, skipped, backupPath, doltPath, sqlitePath, true)
|
printFinalStatus("dolt", imported, skipped, backupPath, doltPath, sqlitePath, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hooksNeedDoltUpdate checks if installed git hooks lack the Dolt backend skip logic.
|
||||||
|
func hooksNeedDoltUpdate(beadsDir string) bool {
|
||||||
|
// Find git hooks directory
|
||||||
|
repoRoot := filepath.Dir(beadsDir)
|
||||||
|
hooksDir := filepath.Join(repoRoot, ".git", "hooks")
|
||||||
|
|
||||||
|
// Check post-merge hook (most likely to cause issues)
|
||||||
|
postMergePath := filepath.Join(hooksDir, "post-merge")
|
||||||
|
content, err := os.ReadFile(postMergePath)
|
||||||
|
if err != nil {
|
||||||
|
return false // No hook installed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a bd hook and lacks the Dolt skip logic
|
||||||
|
contentStr := string(content)
|
||||||
|
if !strings.Contains(contentStr, "bd") {
|
||||||
|
return false // Not a bd hook
|
||||||
|
}
|
||||||
|
if strings.Contains(contentStr, `"backend"`) && strings.Contains(contentStr, `"dolt"`) {
|
||||||
|
return false // Already has Dolt check
|
||||||
|
}
|
||||||
|
|
||||||
|
return true // bd hook without Dolt check
|
||||||
|
}
|
||||||
|
|
||||||
// handleToSQLiteMigration migrates from Dolt to SQLite backend (escape hatch).
|
// handleToSQLiteMigration migrates from Dolt to SQLite backend (escape hatch).
|
||||||
func handleToSQLiteMigration(dryRun bool, autoYes bool) {
|
func handleToSQLiteMigration(dryRun bool, autoYes bool) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|||||||
Reference in New Issue
Block a user