feat: Add 'bd orphans' command with DRY refactoring of orphan detection
Implements the 'bd orphans' command to identify issues referenced in commits but still open in the database, and refactors to eliminate code duplication. - Creates cmd/bd/orphans.go with Cobra command structure - Identifies orphaned issues (referenced in git commits but still open/in_progress) - Supports multiple output formats (human, JSON, detailed) - Auto-close with --fix flag DRY refactoring: - Extracted FindOrphanedIssues() to cmd/bd/doctor/git.go as shared core logic - Moved OrphanIssue type to cmd/bd/doctor/types.go - Refactored CheckOrphanedIssues() to use FindOrphanedIssues() Cherry-picked from PR #767 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
82
cmd/bd/orphans_test.go
Normal file
82
cmd/bd/orphans_test.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestOrphansBasic tests basic orphan detection
|
||||
func TestOrphansBasic(t *testing.T) {
|
||||
// Create a temporary directory with a git repo and beads database
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Initialize git repo
|
||||
cmd := exec.Command("git", "init")
|
||||
cmd.Dir = tmpDir
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Failed to init git repo: %v", err)
|
||||
}
|
||||
|
||||
// Configure git user (needed for commits)
|
||||
ctx := context.Background()
|
||||
for _, cmd := range []*exec.Cmd{
|
||||
exec.CommandContext(ctx, "git", "-C", tmpDir, "config", "user.email", "test@example.com"),
|
||||
exec.CommandContext(ctx, "git", "-C", tmpDir, "config", "user.name", "Test User"),
|
||||
} {
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Failed to configure git: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create .beads directory
|
||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create .beads dir: %v", err)
|
||||
}
|
||||
|
||||
// Create a minimal database with beads.db
|
||||
// For this test, we'll skip creating an actual database
|
||||
// since the test is primarily about integration
|
||||
|
||||
// Test: findOrphanedIssues should handle missing database gracefully
|
||||
orphans, err := findOrphanedIssues(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("findOrphanedIssues failed: %v", err)
|
||||
}
|
||||
|
||||
// Should be empty list since no database
|
||||
if len(orphans) != 0 {
|
||||
t.Errorf("Expected empty orphans list, got %d", len(orphans))
|
||||
}
|
||||
}
|
||||
|
||||
// TestOrphansNotGitRepo tests behavior in non-git directories
|
||||
func TestOrphansNotGitRepo(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Should not error, just return empty list
|
||||
orphans, err := findOrphanedIssues(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("findOrphanedIssues failed: %v", err)
|
||||
}
|
||||
|
||||
if len(orphans) != 0 {
|
||||
t.Errorf("Expected empty orphans list for non-git repo, got %d", len(orphans))
|
||||
}
|
||||
}
|
||||
|
||||
// TestCloseIssueCommand tests that close issue command is properly formed
|
||||
func TestCloseIssueCommand(t *testing.T) {
|
||||
// This is a basic test to ensure the closeIssue function
|
||||
// attempts to run the correct command.
|
||||
// In a real environment, this would fail since bd close requires
|
||||
// a valid beads database.
|
||||
|
||||
// Just test that the function doesn't panic
|
||||
// (actual close will fail, which is expected)
|
||||
_ = closeIssue("bd-test-invalid")
|
||||
// Error is expected since the issue doesn't exist
|
||||
}
|
||||
Reference in New Issue
Block a user