feat(bd-1pj6): Add custom status states via config

Users can now define custom status states for multi-step pipelines using:
  bd config set status.custom "awaiting_review,awaiting_testing,awaiting_docs"

Changes:
- Add Status.IsValidWithCustom() method for custom status validation
- Add Issue.ValidateWithCustomStatuses() method
- Add GetCustomStatuses() method to storage interface
- Update CreateIssue/UpdateIssue to support custom statuses
- Add comprehensive tests for custom status functionality
- Update config command help text with custom status documentation

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-28 23:19:16 -08:00
parent 26f84b6a47
commit a5ec5c6977
12 changed files with 375 additions and 30 deletions

View File

@@ -3,6 +3,7 @@ package sqlite
import (
"context"
"database/sql"
"strings"
)
// SetConfig sets a configuration value
@@ -93,3 +94,37 @@ func (s *SQLiteStorage) GetMetadata(ctx context.Context, key string) (string, er
}
return value, wrapDBError("get metadata", err)
}
// CustomStatusConfigKey is the config key for custom status states
const CustomStatusConfigKey = "status.custom"
// GetCustomStatuses retrieves the list of custom status states from config.
// Custom statuses are stored as comma-separated values in the "status.custom" config key.
// Returns an empty slice if no custom statuses are configured.
func (s *SQLiteStorage) GetCustomStatuses(ctx context.Context) ([]string, error) {
value, err := s.GetConfig(ctx, CustomStatusConfigKey)
if err != nil {
return nil, err
}
if value == "" {
return nil, nil
}
return parseCustomStatuses(value), nil
}
// parseCustomStatuses splits a comma-separated string into a slice of trimmed status names.
// Empty entries are filtered out.
func parseCustomStatuses(value string) []string {
if value == "" {
return nil
}
parts := strings.Split(value, ",")
result := make([]string, 0, len(parts))
for _, p := range parts {
trimmed := strings.TrimSpace(p)
if trimmed != "" {
result = append(result, trimmed)
}
}
return result
}