fix(doctor): remove circular error message in --fix mode
When `bd doctor --fix` fails to apply a fix, it was showing "Manual fix: Run 'bd doctor --fix' ..." which is circular and unhelpful. Now extracts just the manual command from the fix message: - "..., or manually: <cmd>" -> extracts <cmd> - "bd doctor --fix or <alt>" -> extracts <alt> - No alternative available -> shows nothing Closes GH#403 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2
.beads/.gitignore
vendored
2
.beads/.gitignore
vendored
@@ -30,3 +30,5 @@ beads.right.meta.json
|
|||||||
!issues.jsonl
|
!issues.jsonl
|
||||||
!metadata.json
|
!metadata.json
|
||||||
!config.json
|
!config.json
|
||||||
|
deletions.jsonl
|
||||||
|
deletions.jsonl.migrated
|
||||||
|
|||||||
1137
.beads/issues.jsonl
1137
.beads/issues.jsonl
File diff suppressed because one or more lines are too long
@@ -404,7 +404,11 @@ func applyFixList(path string, fixes []doctorCheck) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errorCount++
|
errorCount++
|
||||||
color.Red(" ✗ Error: %v\n", err)
|
color.Red(" ✗ Error: %v\n", err)
|
||||||
fmt.Printf(" Manual fix: %s\n", check.Fix)
|
// GH#403: Don't suggest "bd doctor --fix" when we're already running --fix
|
||||||
|
manualFix := extractManualFix(check.Fix)
|
||||||
|
if manualFix != "" {
|
||||||
|
fmt.Printf(" Manual fix: %s\n", manualFix)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fixedCount++
|
fixedCount++
|
||||||
color.Green(" ✓ Fixed\n")
|
color.Green(" ✓ Fixed\n")
|
||||||
@@ -418,6 +422,53 @@ func applyFixList(path string, fixes []doctorCheck) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractManualFix extracts the manual fix portion from a Fix message.
|
||||||
|
// GH#403: When running "bd doctor --fix", suggesting "Run 'bd doctor --fix'" is circular.
|
||||||
|
// This function extracts just the manual command when available.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// - "Run 'bd doctor --fix' to ..., or manually: git config ..." -> "git config ..."
|
||||||
|
// - "Run 'bd doctor --fix' or bd init" -> "bd init"
|
||||||
|
// - "Run: bd init or bd doctor --fix" -> "bd init"
|
||||||
|
// - "Run 'bd doctor --fix'" -> "" (no alternative)
|
||||||
|
func extractManualFix(fix string) string {
|
||||||
|
// Pattern 1: "..., or manually: <command>" - extract everything after "manually:"
|
||||||
|
if idx := strings.Index(strings.ToLower(fix), "manually:"); idx != -1 {
|
||||||
|
manual := strings.TrimSpace(fix[idx+len("manually:"):])
|
||||||
|
return manual
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pattern 2: "Run 'bd doctor --fix' or <alternative>" - extract the alternative
|
||||||
|
// Also handles "Run: bd init or bd doctor --fix"
|
||||||
|
fixLower := strings.ToLower(fix)
|
||||||
|
if strings.Contains(fixLower, "bd doctor --fix") {
|
||||||
|
// Try to find " or " and extract the other option
|
||||||
|
if idx := strings.Index(fixLower, " or "); idx != -1 {
|
||||||
|
before := fix[:idx]
|
||||||
|
after := fix[idx+4:] // len(" or ") = 4
|
||||||
|
|
||||||
|
// Check which side has "bd doctor --fix"
|
||||||
|
if strings.Contains(strings.ToLower(before), "bd doctor --fix") {
|
||||||
|
// "bd doctor --fix or <alternative>" - return alternative
|
||||||
|
return strings.TrimSpace(after)
|
||||||
|
}
|
||||||
|
// "<alternative> or bd doctor --fix" - return alternative
|
||||||
|
// Remove any "Run:" or "Run " prefix
|
||||||
|
result := strings.TrimSpace(before)
|
||||||
|
result = strings.TrimPrefix(result, "Run:")
|
||||||
|
result = strings.TrimPrefix(result, "Run ")
|
||||||
|
return strings.TrimSpace(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// No " or " found - the whole fix is just "bd doctor --fix"
|
||||||
|
// Return empty string to indicate no manual alternative
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// No "bd doctor --fix" in the message - return as-is
|
||||||
|
return fix
|
||||||
|
}
|
||||||
|
|
||||||
// runCheckHealth runs lightweight health checks for git hooks.
|
// runCheckHealth runs lightweight health checks for git hooks.
|
||||||
// Silent on success, prints a hint if issues detected.
|
// Silent on success, prints a hint if issues detected.
|
||||||
// Respects hints.doctor config setting.
|
// Respects hints.doctor config setting.
|
||||||
|
|||||||
@@ -1265,3 +1265,62 @@ func TestCheckSyncBranchHookQuick(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestExtractManualFix tests the extractManualFix function (GH#403)
|
||||||
|
func TestExtractManualFix(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "manually pattern with git config",
|
||||||
|
input: "Run 'bd doctor --fix' to update to correct config, or manually: git config merge.beads.driver \"bd merge %A %O %A %B\"",
|
||||||
|
expected: "git config merge.beads.driver \"bd merge %A %O %A %B\"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "manually pattern with newline",
|
||||||
|
input: "Run 'bd doctor --fix' to auto-migrate, or manually:\nbd init && bd import",
|
||||||
|
expected: "bd init && bd import",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "or alternative after bd doctor --fix",
|
||||||
|
input: "Run 'bd doctor --fix' or bd init",
|
||||||
|
expected: "bd init",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "or alternative before bd doctor --fix",
|
||||||
|
input: "Run: bd init (safe to re-run) or bd doctor --fix",
|
||||||
|
expected: "bd init (safe to re-run)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "just bd doctor --fix",
|
||||||
|
input: "Run 'bd doctor --fix'",
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no bd doctor --fix at all",
|
||||||
|
input: "Run 'bd init' to initialize the database",
|
||||||
|
expected: "Run 'bd init' to initialize the database",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty input",
|
||||||
|
input: "",
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update configuration suggestion",
|
||||||
|
input: "Run 'bd doctor --fix' to update the configuration",
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := extractManualFix(tc.input)
|
||||||
|
if result != tc.expected {
|
||||||
|
t.Errorf("extractManualFix(%q) = %q, expected %q", tc.input, result, tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user