-
Notifications
You must be signed in to change notification settings - Fork 1k
Open
Description
Summary
Refactor the current Jira and Linear integrations into a plugin-based architecture that enables:
- Easier addition of new tracker integrations (Azure DevOps, GitHub Issues, GitLab, etc.)
- Shared sync logic, conflict resolution, and field mapping
- Consistent CLI experience across all trackers
Current State
- Jira (
cmd/bd/jira.go): Hybrid Go + Python scripts - Linear (
cmd/bd/linear.go+internal/linear/): Fully Go-native
Both implementations duplicate:
- Sync statistics tracking (PullStats, PushStats, SyncResult)
- Conflict resolution strategies (prefer-local, prefer-remote, timestamp-based)
- Command flag patterns (--pull, --push, --dry-run, --create-only)
- Field mapping logic (status, priority, type, relations)
- Config validation patterns
Proposed Architecture
Core Interface
// internal/tracker/interface.go
type IssueTracker interface {
Name() string
ValidateConfig(ctx context.Context, store storage.Storage) error
FetchIssues(ctx context.Context, opts FetchOptions) ([]ExternalIssue, error)
CreateIssue(ctx context.Context, issue *types.Issue) (*ExternalIssue, error)
UpdateIssue(ctx context.Context, externalID string, issue *types.Issue) error
FetchIssueTimestamp(ctx context.Context, externalRef string) (time.Time, error)
IsExternalRef(externalRef string) bool
ExtractExternalID(externalRef string) string
BuildExternalRef(externalID string) string
}
type FieldMapper interface {
ToBeadsStatus(externalStatus string) types.Status
FromBeadsStatus(status types.Status) string
ToBeadsPriority(externalPriority string) int
FromBeadsPriority(priority int) string
// ... etc
}Shared Components
| Component | Purpose |
|---|---|
SyncEngine |
Orchestrates pull/push/conflict resolution |
MappingConfig |
Configurable field mappings with defaults |
ConflictResolver |
Timestamp-based, prefer-local, prefer-remote |
| Command factory | Generates consistent Cobra commands per tracker |
Plugin Registry
// internal/tracker/registry.go
func Register(tracker IssueTracker)
func Get(name string) IssueTracker
func List() []stringImplementation Phases
Phase 1: Extract Common Framework (~1,625 lines)
internal/tracker/interface.go- Core interfacesinternal/tracker/types.go- Shared types (SyncStats, ExternalIssue, etc.)internal/tracker/mapping.go- Default mapping frameworkinternal/tracker/sync.go- SyncEngine implementationinternal/tracker/conflict.go- Conflict detection and resolutioninternal/tracker/registry.go- Plugin registry
Phase 2: Refactor Linear (~400 lines modified)
- Implement IssueTracker interface
- Delegate to shared SyncEngine
- Remove duplicated conflict/sync logic
Phase 3: Refactor Jira (~300 lines modified)
- Implement IssueTracker interface
- Option to migrate Python scripts to Go
Phase 4: Azure DevOps Plugin (~850 lines)
internal/azuredevops/client.go- REST API clientinternal/azuredevops/mapping.go- Default field mappingsinternal/azuredevops/wiql.go- WIQL query builder
Azure DevOps mappings:
| ADO State | Beads Status |
|---|---|
| New | open |
| Active | in_progress |
| Resolved | in_progress |
| Closed | closed |
| ADO Type | Beads Type |
|---|---|
| Bug | bug |
| User Story | feature |
| Task | task |
| Epic | epic |
Benefits
- Extensibility: Adding new trackers requires only implementing the interface
- Consistency: All trackers share the same CLI patterns and behavior
- Maintainability: Bug fixes to sync logic benefit all trackers
- Testing: Shared logic can be tested once with mock trackers
Estimated Effort
| Phase | New Code | Modified |
|---|---|---|
| Phase 1 | ~1,625 lines | - |
| Phase 2 | - | ~400 lines |
| Phase 3 | - | ~300 lines |
| Phase 4 | ~850 lines | - |
| Tests | ~1,200 lines | - |
| Total | ~3,675 lines | ~700 lines |
Offer to Implement
I'm willing to implement this feature if there's interest. I would start with Phase 1 (common framework) and Phase 4 (Azure DevOps) as I have an immediate use case for Azure DevOps integration.
Happy to discuss the design or adjust based on feedback.
Related: This came up while working on #1145 (issue-prefix config fix).
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels