bd sync: 2025-11-09 14:53:59
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -45,6 +45,11 @@ func TestExtractPrefix(t *testing.T) {
|
|||||||
{"no-number", "no"}, // Has hyphen, so "no" is prefix
|
{"no-number", "no"}, // Has hyphen, so "no" is prefix
|
||||||
{"nonumber", ""}, // No hyphen
|
{"nonumber", ""}, // No hyphen
|
||||||
{"", ""},
|
{"", ""},
|
||||||
|
// Multi-part suffixes (bd-fasa regression tests)
|
||||||
|
{"vc-baseline-test", "vc"},
|
||||||
|
{"vc-92cl-gate-test", "vc"},
|
||||||
|
{"bd-multi-part-id", "bd"},
|
||||||
|
{"prefix-a-b-c-d", "prefix"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
@@ -628,6 +628,7 @@ func attemptAutoMerge(conflictedPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// detectPrefixFromIssues extracts the common prefix from issue IDs
|
// detectPrefixFromIssues extracts the common prefix from issue IDs
|
||||||
|
// Only considers the first hyphen, so "vc-baseline-test" -> "vc"
|
||||||
func detectPrefixFromIssues(issues []*types.Issue) string {
|
func detectPrefixFromIssues(issues []*types.Issue) string {
|
||||||
if len(issues) == 0 {
|
if len(issues) == 0 {
|
||||||
return ""
|
return ""
|
||||||
@@ -636,10 +637,10 @@ func detectPrefixFromIssues(issues []*types.Issue) string {
|
|||||||
// Count prefix occurrences
|
// Count prefix occurrences
|
||||||
prefixCounts := make(map[string]int)
|
prefixCounts := make(map[string]int)
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
// Extract prefix from issue ID (e.g., "bd-123" -> "bd")
|
// Extract prefix from issue ID using first hyphen only
|
||||||
parts := strings.SplitN(issue.ID, "-", 2)
|
idx := strings.Index(issue.ID, "-")
|
||||||
if len(parts) == 2 {
|
if idx > 0 {
|
||||||
prefixCounts[parts[0]]++
|
prefixCounts[issue.ID[:idx]]++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
137
cmd/bd/import_multipart_id_test.go
Normal file
137
cmd/bd/import_multipart_id_test.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/steveyegge/beads/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestImportMultiPartIDs tests that issue IDs with hyphens in the suffix
|
||||||
|
// (like "vc-baseline-test") are correctly recognized as having prefix "vc"
|
||||||
|
// and not treated as having different prefixes like "vc-baseline-"
|
||||||
|
func TestImportMultiPartIDs(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
dbPath := filepath.Join(tmpDir, ".beads", "beads.db")
|
||||||
|
|
||||||
|
// Create database with "vc" prefix
|
||||||
|
st := newTestStoreWithPrefix(t, dbPath, "vc")
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// Create issues with multi-part IDs
|
||||||
|
issues := []*types.Issue{
|
||||||
|
{
|
||||||
|
ID: "vc-baseline-test",
|
||||||
|
Title: "Baseline test issue",
|
||||||
|
Description: "Issue with hyphenated suffix",
|
||||||
|
Status: "open",
|
||||||
|
Priority: 1,
|
||||||
|
IssueType: "task",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "vc-92cl-gate-test",
|
||||||
|
Title: "Gate test issue",
|
||||||
|
Description: "Another issue with hyphenated suffix",
|
||||||
|
Status: "open",
|
||||||
|
Priority: 1,
|
||||||
|
IssueType: "task",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "vc-test",
|
||||||
|
Title: "Simple test issue",
|
||||||
|
Description: "Issue without hyphenated suffix",
|
||||||
|
Status: "open",
|
||||||
|
Priority: 1,
|
||||||
|
IssueType: "task",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import should succeed without prefix mismatch errors
|
||||||
|
opts := ImportOptions{
|
||||||
|
DryRun: false,
|
||||||
|
SkipUpdate: false,
|
||||||
|
Strict: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := importIssuesCore(ctx, dbPath, st, issues, opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Import failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not detect prefix mismatch
|
||||||
|
if result.PrefixMismatch {
|
||||||
|
t.Errorf("Import incorrectly detected prefix mismatch")
|
||||||
|
t.Logf("Mismatched prefixes: %v", result.MismatchPrefixes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// All issues should be created
|
||||||
|
if result.Created != 3 {
|
||||||
|
t.Errorf("Expected 3 issues created, got %d", result.Created)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify issues exist in database
|
||||||
|
for _, issue := range issues {
|
||||||
|
dbIssue, err := st.GetIssue(ctx, issue.ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to get issue %s: %v", issue.ID, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dbIssue.Title != issue.Title {
|
||||||
|
t.Errorf("Issue %s title mismatch: got %q, want %q", issue.ID, dbIssue.Title, issue.Title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestDetectPrefixFromIssues tests the detectPrefixFromIssues function
|
||||||
|
// with multi-part IDs
|
||||||
|
func TestDetectPrefixFromIssues(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
issues []*types.Issue
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple IDs",
|
||||||
|
issues: []*types.Issue{
|
||||||
|
{ID: "bd-1"},
|
||||||
|
{ID: "bd-2"},
|
||||||
|
{ID: "bd-3"},
|
||||||
|
},
|
||||||
|
expected: "bd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-part IDs",
|
||||||
|
issues: []*types.Issue{
|
||||||
|
{ID: "vc-baseline-test"},
|
||||||
|
{ID: "vc-92cl-gate-test"},
|
||||||
|
{ID: "vc-test"},
|
||||||
|
},
|
||||||
|
expected: "vc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed multi-part IDs",
|
||||||
|
issues: []*types.Issue{
|
||||||
|
{ID: "prefix-a-b-c"},
|
||||||
|
{ID: "prefix-x-y-z"},
|
||||||
|
{ID: "prefix-simple"},
|
||||||
|
},
|
||||||
|
expected: "prefix",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty list",
|
||||||
|
issues: []*types.Issue{},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := detectPrefixFromIssues(tt.issues)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("detectPrefixFromIssues() = %q, want %q", result, tt.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -241,12 +241,13 @@ Examples:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// extractPrefix extracts the prefix from an issue ID (e.g., "bd-123" -> "bd")
|
// extractPrefix extracts the prefix from an issue ID (e.g., "bd-123" -> "bd")
|
||||||
|
// Only considers the first hyphen, so "vc-baseline-test" -> "vc"
|
||||||
func extractPrefix(issueID string) string {
|
func extractPrefix(issueID string) string {
|
||||||
parts := strings.Split(issueID, "-")
|
idx := strings.Index(issueID, "-")
|
||||||
if len(parts) > 0 {
|
if idx <= 0 {
|
||||||
return parts[0]
|
|
||||||
}
|
|
||||||
return ""
|
return ""
|
||||||
|
}
|
||||||
|
return issueID[:idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// VersionChange represents agent-relevant changes for a specific version
|
// VersionChange represents agent-relevant changes for a specific version
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ func detectPrefix(_ string, memStore *memory.MemoryStorage) (string, error) {
|
|||||||
|
|
||||||
// extractIssuePrefix extracts the prefix from an issue ID like "bd-123" -> "bd"
|
// extractIssuePrefix extracts the prefix from an issue ID like "bd-123" -> "bd"
|
||||||
func extractIssuePrefix(issueID string) string {
|
func extractIssuePrefix(issueID string) string {
|
||||||
idx := strings.LastIndex(issueID, "-")
|
idx := strings.Index(issueID, "-")
|
||||||
if idx <= 0 {
|
if idx <= 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestExtractIssuePrefix(t *testing.T) {
|
|||||||
{"standard ID", "bd-123", "bd"},
|
{"standard ID", "bd-123", "bd"},
|
||||||
{"custom prefix", "myproject-456", "myproject"},
|
{"custom prefix", "myproject-456", "myproject"},
|
||||||
{"hash ID", "bd-abc123def", "bd"},
|
{"hash ID", "bd-abc123def", "bd"},
|
||||||
{"hyphenated prefix", "alpha-beta-1", "alpha-beta"},
|
{"multi-part suffix", "alpha-beta-1", "alpha"}, // Only first hyphen (bd-fasa)
|
||||||
{"no hyphen", "nohyphen", ""},
|
{"no hyphen", "nohyphen", ""},
|
||||||
{"empty", "", ""},
|
{"empty", "", ""},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,9 +322,9 @@ func TestExtractIssuePrefix(t *testing.T) {
|
|||||||
expected: "bd",
|
expected: "bd",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "hyphenated prefix",
|
name: "multi-part suffix",
|
||||||
issueID: "alpha-beta-1",
|
issueID: "alpha-beta-1",
|
||||||
expected: "alpha-beta",
|
expected: "alpha", // Only first hyphen (bd-fasa)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ExtractIssuePrefix extracts the prefix from an issue ID like "bd-123" -> "bd"
|
// ExtractIssuePrefix extracts the prefix from an issue ID like "bd-123" -> "bd"
|
||||||
|
// Only considers the first hyphen, so "vc-baseline-test" -> "vc"
|
||||||
func ExtractIssuePrefix(issueID string) string {
|
func ExtractIssuePrefix(issueID string) string {
|
||||||
idx := strings.LastIndex(issueID, "-")
|
idx := strings.Index(issueID, "-")
|
||||||
if idx <= 0 {
|
if idx <= 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user