fix: bd --no-db dep tree now shows complete tree (GH#836)

The memory storage GetDependencyTree was missing the root node at depth 0,
causing --no-db mode to only show dependencies without the root issue.

Fixed by:
- Adding root node at depth 0 before listing dependencies
- Setting ParentID on child nodes for proper tree rendering

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beads/crew/fang
2026-01-01 11:03:30 -08:00
committed by Steve Yegge
parent edc0fea02f
commit 95f14fa827
3 changed files with 101 additions and 7 deletions

View File

@@ -887,19 +887,43 @@ func (m *MemoryStorage) SetJSONLFileHash(ctx context.Context, fileHash string) e
// GetDependencyTree gets the dependency tree for an issue
func (m *MemoryStorage) GetDependencyTree(ctx context.Context, issueID string, maxDepth int, showAllPaths bool, reverse bool) ([]*types.TreeNode, error) {
// Simplified implementation - just return direct dependencies
// Note: reverse parameter is accepted for interface compatibility but not fully implemented in memory storage
// Get the root issue first
root, err := m.GetIssue(ctx, issueID)
if err != nil {
return nil, err
}
if root == nil {
return nil, nil
}
var nodes []*types.TreeNode
// Add root node at depth 0
rootNode := &types.TreeNode{
Depth: 0,
ParentID: issueID, // Root's parent is itself
}
rootNode.ID = root.ID
rootNode.Title = root.Title
rootNode.Description = root.Description
rootNode.Status = root.Status
rootNode.Priority = root.Priority
rootNode.IssueType = root.IssueType
nodes = append(nodes, rootNode)
// Get dependencies (or dependents if reverse)
// Note: reverse mode not fully implemented - uses same logic for now
deps, err := m.GetDependencies(ctx, issueID)
if err != nil {
return nil, err
}
var nodes []*types.TreeNode
// Add dependencies at depth 1
for _, dep := range deps {
node := &types.TreeNode{
Depth: 1,
Depth: 1,
ParentID: issueID, // Parent is the root
}
// Copy issue fields
node.ID = dep.ID
node.Title = dep.Title
node.Description = dep.Description

View File

@@ -223,8 +223,12 @@ func TestMemoryStorage_DependencyCounts_Records_Tree_Cycles(t *testing.T) {
if err != nil {
t.Fatalf("GetDependencyTree: %v", err)
}
if len(nodes) != 2 || nodes[0].Depth != 1 {
t.Fatalf("unexpected tree: %+v", nodes)
// Expect 3 nodes: root (A) at depth 0, plus 2 dependencies (B, C) at depth 1
if len(nodes) != 3 {
t.Fatalf("expected 3 nodes (root + 2 deps), got %d", len(nodes))
}
if nodes[0].ID != a.ID || nodes[0].Depth != 0 {
t.Fatalf("expected root node %s at depth 0, got %s at depth %d", a.ID, nodes[0].ID, nodes[0].Depth)
}
cycles, err := store.DetectCycles(ctx)

View File

@@ -0,0 +1,66 @@
package memory
import (
"context"
"testing"
"github.com/steveyegge/beads/internal/types"
)
func TestGetDependencyTree_IncludesRoot(t *testing.T) {
m := New("")
// Create parent and child issues
parent := &types.Issue{
ID: "bd-7zka",
Title: "Parent issue",
Status: types.StatusOpen,
Priority: 3,
}
child := &types.Issue{
ID: "bd-7zka.2",
Title: "Child issue",
Status: types.StatusOpen,
Priority: 3,
Dependencies: []*types.Dependency{
{IssueID: "bd-7zka.2", DependsOnID: "bd-7zka", Type: "blocks"},
},
}
if err := m.LoadFromIssues([]*types.Issue{parent, child}); err != nil {
t.Fatalf("LoadFromIssues failed: %v", err)
}
tree, err := m.GetDependencyTree(context.Background(), "bd-7zka.2", 50, false, false)
if err != nil {
t.Fatalf("GetDependencyTree failed: %v", err)
}
// Should have 2 nodes: root at depth 0, dependency at depth 1
if len(tree) != 2 {
t.Errorf("Expected 2 nodes, got %d", len(tree))
for i, node := range tree {
t.Logf(" [%d] ID=%s, Depth=%d, ParentID=%s", i, node.ID, node.Depth, node.ParentID)
}
return
}
// First node should be root at depth 0
if tree[0].ID != "bd-7zka.2" {
t.Errorf("Expected root ID 'bd-7zka.2', got '%s'", tree[0].ID)
}
if tree[0].Depth != 0 {
t.Errorf("Expected root depth 0, got %d", tree[0].Depth)
}
// Second node should be dependency at depth 1
if tree[1].ID != "bd-7zka" {
t.Errorf("Expected dependency ID 'bd-7zka', got '%s'", tree[1].ID)
}
if tree[1].Depth != 1 {
t.Errorf("Expected dependency depth 1, got %d", tree[1].Depth)
}
if tree[1].ParentID != "bd-7zka.2" {
t.Errorf("Expected dependency ParentID 'bd-7zka.2', got '%s'", tree[1].ParentID)
}
}