fix(update): accept custom types from types.custom config (GH#hq-8hif1z)

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>
This commit is contained in:
jasper
2026-01-24 15:07:17 -08:00
committed by John Ogle
parent 1e329754a9
commit d8ec84c728
4 changed files with 69 additions and 30 deletions

View File

@@ -887,12 +887,11 @@ func (s *SQLiteStorage) UpdateIssue(ctx context.Context, id string, updates map[
return fmt.Errorf("issue %s not found", id)
}
// Fetch custom statuses and types for validation
// Fetch custom statuses and types for validation (GH#hq-8hif1z)
customStatuses, err := s.GetCustomStatuses(ctx)
if err != nil {
return wrapDBError("get custom statuses", err)
}
customTypes, err := s.GetCustomTypes(ctx)
if err != nil {
return wrapDBError("get custom types", err)

View File

@@ -400,12 +400,11 @@ func (t *sqliteTxStorage) UpdateIssue(ctx context.Context, id string, updates ma
return fmt.Errorf("issue %s not found", id)
}
// Fetch custom statuses and types for validation
// Fetch custom statuses and types for validation (GH#hq-8hif1z)
customStatuses, err := t.GetCustomStatuses(ctx)
if err != nil {
return fmt.Errorf("failed to get custom statuses: %w", err)
}
customTypes, err := t.GetCustomTypes(ctx)
if err != nil {
return fmt.Errorf("failed to get custom types: %w", err)

View File

@@ -37,11 +37,17 @@ func validateStatusWithCustom(value interface{}, customStatuses []string) error
return nil
}
// validateIssueType validates an issue type value
// 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().IsValid() {
if !types.IssueType(issueType).Normalize().IsValidWithCustom(customTypes) {
return fmt.Errorf("invalid issue type: %s", issueType)
}
}
@@ -77,19 +83,26 @@ var fieldValidators = map[string]func(interface{}) error{
"estimated_minutes": validateEstimatedMinutes,
}
// validateFieldUpdate validates a field update value (built-in statuses only)
// validateFieldUpdate validates a field update value (built-in statuses and types only)
func validateFieldUpdate(key string, value interface{}) error {
return validateFieldUpdateWithCustomStatuses(key, value, nil)
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 their respective field validations.
// 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 (federation trust model)
// Special handling for issue_type field to support custom types
if key == "issue_type" {
return validateIssueTypeWithCustom(value, customTypes)
}
@@ -98,21 +111,3 @@ func validateFieldUpdateWithCustom(key string, value interface{}, customStatuses
}
return nil
}
// validateFieldUpdateWithCustomStatuses validates a field update value,
// allowing custom statuses for status field validation.
func validateFieldUpdateWithCustomStatuses(key string, value interface{}, customStatuses []string) error {
return validateFieldUpdateWithCustom(key, value, customStatuses, nil)
}
// validateIssueTypeWithCustom validates an issue type value, allowing custom types.
func validateIssueTypeWithCustom(value interface{}, customTypes []string) error {
if issueType, ok := value.(string); ok {
// Normalize first to support aliases like "enhancement" -> "feature"
normalized := types.IssueType(issueType).Normalize()
if !normalized.IsValidWithCustom(customTypes) {
return fmt.Errorf("invalid issue type: %s", issueType)
}
}
return nil
}