Fixed bug where issue IDs with multiple hyphens in the prefix and hash suffixes were incorrectly parsed. For example, `web-app-a3f8e9` was being parsed with prefix `web-` instead of `web-app`. Root cause: ExtractIssuePrefix() only checked for numeric suffixes. When it encountered a hash suffix, it fell back to using the first hyphen instead of the last hyphen. Changes: - Added isLikelyHash() helper to detect hexadecimal hash suffixes (4-8 chars) - Updated ExtractIssuePrefix() to handle both numeric and hash suffixes - Added comprehensive test cases for various prefix patterns Test coverage includes: - web-app-123 (numeric suffix) - web-app-a3f8e9 (hash suffix) - my-cool-app-a3f8e9 (three-part prefix with hash) - super-long-project-name-1a2b (four-part prefix) - Various hash lengths and case variations Co-authored-by: dubstylee <dubstylee@users.noreply.github.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
79 lines
2.3 KiB
Go
79 lines
2.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// ExtractIssuePrefix extracts the prefix from an issue ID like "bd-123" -> "bd"
|
|
// Uses the last hyphen before a numeric or hash suffix:
|
|
// - "beads-vscode-1" -> "beads-vscode" (numeric suffix)
|
|
// - "web-app-a3f8e9" -> "web-app" (hash suffix)
|
|
// - "my-cool-app-123" -> "my-cool-app" (numeric suffix)
|
|
// Only uses first hyphen for non-ID suffixes like "vc-baseline-test" -> "vc"
|
|
func ExtractIssuePrefix(issueID string) string {
|
|
// Try last hyphen first (handles multi-part prefixes like "beads-vscode-1")
|
|
lastIdx := strings.LastIndex(issueID, "-")
|
|
if lastIdx <= 0 {
|
|
return ""
|
|
}
|
|
|
|
suffix := issueID[lastIdx+1:]
|
|
// Check if suffix looks like an issue ID component (numeric or hash-like)
|
|
if len(suffix) > 0 {
|
|
// Extract just the numeric part (handle "123.1.2" -> check "123")
|
|
numPart := suffix
|
|
if dotIdx := strings.Index(suffix, "."); dotIdx > 0 {
|
|
numPart = suffix[:dotIdx]
|
|
}
|
|
|
|
// Check if it's numeric
|
|
var num int
|
|
if _, err := fmt.Sscanf(numPart, "%d", &num); err == nil {
|
|
// Suffix is numeric, use last hyphen
|
|
return issueID[:lastIdx]
|
|
}
|
|
|
|
// Check if it looks like a hash (hexadecimal characters, 4+ chars)
|
|
// Hash IDs are typically 4-8 hex characters (e.g., "a3f8e9", "1a2b")
|
|
if isLikelyHash(numPart) {
|
|
// Suffix looks like a hash, use last hyphen
|
|
return issueID[:lastIdx]
|
|
}
|
|
}
|
|
|
|
// Suffix is not numeric or hash-like (e.g., "vc-baseline-test"), fall back to first hyphen
|
|
firstIdx := strings.Index(issueID, "-")
|
|
if firstIdx <= 0 {
|
|
return ""
|
|
}
|
|
return issueID[:firstIdx]
|
|
}
|
|
|
|
// isLikelyHash checks if a string looks like a hash ID suffix.
|
|
// Returns true for hexadecimal strings of 4-8 characters.
|
|
// Hash IDs in beads are typically 4-6 characters (progressive length scaling).
|
|
func isLikelyHash(s string) bool {
|
|
if len(s) < 4 || len(s) > 8 {
|
|
return false
|
|
}
|
|
// Check if all characters are hexadecimal
|
|
for _, c := range s {
|
|
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// ExtractIssueNumber extracts the number from an issue ID like "bd-123" -> 123
|
|
func ExtractIssueNumber(issueID string) int {
|
|
idx := strings.LastIndex(issueID, "-")
|
|
if idx < 0 || idx == len(issueID)-1 {
|
|
return 0
|
|
}
|
|
var num int
|
|
_, _ = fmt.Sscanf(issueID[idx+1:], "%d", &num)
|
|
return num
|
|
}
|