The `bd update --type` command was rejecting custom types (like role, agent, rig) even when configured via types.custom. The issue was that type validation used IsValid() which only checks the 5 core types, ignoring custom types. Changes: - CLI (update.go): Use IsValidWithCustom() with types from config - Storage (validators.go): Add validateIssueTypeWithCustom() function - Storage (queries.go, transaction.go): Fetch and pass custom types The error message now dynamically shows all valid types including custom ones. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
114 lines
3.9 KiB
Go
114 lines
3.9 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/steveyegge/beads/internal/types"
|
|
)
|
|
|
|
// validatePriority validates a priority value
|
|
func validatePriority(value interface{}) error {
|
|
if priority, ok := value.(int); ok {
|
|
if priority < 0 || priority > 4 {
|
|
return fmt.Errorf("priority must be between 0 and 4 (got %d)", priority)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validateStatus validates a status value (built-in statuses only)
|
|
func validateStatus(value interface{}) error {
|
|
return validateStatusWithCustom(value, nil)
|
|
}
|
|
|
|
// validateStatusWithCustom validates a status value, allowing custom statuses.
|
|
// Note: tombstone status is blocked here (bd-y68) - use bd delete instead of bd update --status=tombstone
|
|
func validateStatusWithCustom(value interface{}, customStatuses []string) error {
|
|
if status, ok := value.(string); ok {
|
|
// Block direct status update to tombstone (bd-y68)
|
|
// Tombstones should only be created via bd delete, not bd update --status=tombstone
|
|
if types.Status(status) == types.StatusTombstone {
|
|
return fmt.Errorf("cannot set status to tombstone directly; use 'bd delete' instead")
|
|
}
|
|
if !types.Status(status).IsValidWithCustom(customStatuses) {
|
|
return fmt.Errorf("invalid status: %s", status)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validateIssueType validates an issue type value (built-in types only)
|
|
func validateIssueType(value interface{}) error {
|
|
return validateIssueTypeWithCustom(value, nil)
|
|
}
|
|
|
|
// validateIssueTypeWithCustom validates an issue type value, allowing custom types.
|
|
// Custom types are configured via bd config set types.custom "type1,type2,..."
|
|
func validateIssueTypeWithCustom(value interface{}, customTypes []string) error {
|
|
if issueType, ok := value.(string); ok {
|
|
// Normalize first to support aliases like "enhancement" -> "feature"
|
|
if !types.IssueType(issueType).Normalize().IsValidWithCustom(customTypes) {
|
|
return fmt.Errorf("invalid issue type: %s", issueType)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validateTitle validates a title value
|
|
func validateTitle(value interface{}) error {
|
|
if title, ok := value.(string); ok {
|
|
if len(title) == 0 || len(title) > 500 {
|
|
return fmt.Errorf("title must be 1-500 characters")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validateEstimatedMinutes validates an estimated_minutes value
|
|
func validateEstimatedMinutes(value interface{}) error {
|
|
if mins, ok := value.(int); ok {
|
|
if mins < 0 {
|
|
return fmt.Errorf("estimated_minutes cannot be negative")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// fieldValidators maps field names to their validation functions
|
|
var fieldValidators = map[string]func(interface{}) error{
|
|
"priority": validatePriority,
|
|
"status": validateStatus,
|
|
"issue_type": validateIssueType,
|
|
"title": validateTitle,
|
|
"estimated_minutes": validateEstimatedMinutes,
|
|
}
|
|
|
|
// validateFieldUpdate validates a field update value (built-in statuses and types only)
|
|
func validateFieldUpdate(key string, value interface{}) error {
|
|
return validateFieldUpdateWithCustom(key, value, nil, nil)
|
|
}
|
|
|
|
// validateFieldUpdateWithCustomStatuses validates a field update value,
|
|
// allowing custom statuses for status field validation.
|
|
// DEPRECATED: Use validateFieldUpdateWithCustom instead which also handles custom types.
|
|
func validateFieldUpdateWithCustomStatuses(key string, value interface{}, customStatuses []string) error {
|
|
return validateFieldUpdateWithCustom(key, value, customStatuses, nil)
|
|
}
|
|
|
|
// validateFieldUpdateWithCustom validates a field update value,
|
|
// allowing custom statuses and custom types for validation (GH#hq-8hif1z).
|
|
func validateFieldUpdateWithCustom(key string, value interface{}, customStatuses, customTypes []string) error {
|
|
// Special handling for status field to support custom statuses
|
|
if key == "status" {
|
|
return validateStatusWithCustom(value, customStatuses)
|
|
}
|
|
// Special handling for issue_type field to support custom types
|
|
if key == "issue_type" {
|
|
return validateIssueTypeWithCustom(value, customTypes)
|
|
}
|
|
if validator, ok := fieldValidators[key]; ok {
|
|
return validator(value)
|
|
}
|
|
return nil
|
|
}
|