Merge bd-xoyh-morsov: GH#517

This commit is contained in:
Steve Yegge
2025-12-16 01:17:18 -08:00
6 changed files with 1004 additions and 20157 deletions

View File

@@ -1061,3 +1061,25 @@ func HasGitRemote(ctx context.Context) bool {
}
return len(strings.TrimSpace(string(output))) > 0
}
// GetCurrentBranch returns the name of the current git branch
func GetCurrentBranch(ctx context.Context) (string, error) {
cmd := exec.CommandContext(ctx, "git", "symbolic-ref", "--short", "HEAD")
output, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("failed to get current branch: %w", err)
}
return strings.TrimSpace(string(output)), nil
}
// IsSyncBranchSameAsCurrent returns true if the sync branch is the same as the current branch.
// This is used to detect the case where we can't use a worktree because the branch is already
// checked out. In this case, we should commit directly to the current branch instead.
// See: https://github.com/steveyegge/beads/issues/519
func IsSyncBranchSameAsCurrent(ctx context.Context, syncBranch string) bool {
currentBranch, err := GetCurrentBranch(ctx)
if err != nil {
return false
}
return currentBranch == syncBranch
}

View File

@@ -683,3 +683,70 @@ func TestCountIssuesInContent(t *testing.T) {
})
}
}
// TestIsSyncBranchSameAsCurrent tests detection of sync.branch == current branch (GH#519)
func TestIsSyncBranchSameAsCurrent(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
ctx := context.Background()
t.Run("returns true when sync branch equals current branch", func(t *testing.T) {
repoDir := setupTestRepo(t)
defer os.RemoveAll(repoDir)
// Create initial commit so we can get current branch
writeFile(t, filepath.Join(repoDir, ".beads", "issues.jsonl"), `{"id":"test-1"}`)
runGit(t, repoDir, "add", ".")
runGit(t, repoDir, "commit", "-m", "initial commit")
// Get current branch name
currentBranch := strings.TrimSpace(getGitOutput(t, repoDir, "symbolic-ref", "--short", "HEAD"))
// Save original dir and change to test repo
origDir, _ := os.Getwd()
os.Chdir(repoDir)
defer os.Chdir(origDir)
// Should return true when sync branch == current branch
if !IsSyncBranchSameAsCurrent(ctx, currentBranch) {
t.Errorf("IsSyncBranchSameAsCurrent(%q) = false, want true", currentBranch)
}
})
t.Run("returns false when sync branch differs from current branch", func(t *testing.T) {
repoDir := setupTestRepo(t)
defer os.RemoveAll(repoDir)
// Create initial commit
writeFile(t, filepath.Join(repoDir, ".beads", "issues.jsonl"), `{"id":"test-1"}`)
runGit(t, repoDir, "add", ".")
runGit(t, repoDir, "commit", "-m", "initial commit")
// Save original dir and change to test repo
origDir, _ := os.Getwd()
os.Chdir(repoDir)
defer os.Chdir(origDir)
// Should return false when sync branch != current branch
if IsSyncBranchSameAsCurrent(ctx, "beads-sync") {
t.Error("IsSyncBranchSameAsCurrent(\"beads-sync\") = true, want false")
}
})
t.Run("returns false on error getting current branch", func(t *testing.T) {
// Test in a non-git directory
tmpDir, _ := os.MkdirTemp("", "non-git-*")
defer os.RemoveAll(tmpDir)
origDir, _ := os.Getwd()
os.Chdir(tmpDir)
defer os.Chdir(origDir)
// Should return false when not in a git repo
if IsSyncBranchSameAsCurrent(ctx, "any-branch") {
t.Error("IsSyncBranchSameAsCurrent in non-git dir = true, want false")
}
})
}

View File

@@ -52,7 +52,7 @@ func ParseIssueType(content string) (types.IssueType, error) {
func ValidatePriority(priorityStr string) (int, error) {
priority := ParsePriority(priorityStr)
if priority == -1 {
return -1, fmt.Errorf("invalid priority %q (expected 0-4 or P0-P4)", priorityStr)
return -1, fmt.Errorf("invalid priority %q (expected 0-4 or P0-P4, not words like high/medium/low)", priorityStr)
}
return priority, nil
}