Add --clear-duplicate-external-refs flag to bd import

Fixes GH-234 by providing automatic resolution for duplicate external_ref
values instead of forcing manual JSONL editing.

Changes:
- Add ClearDuplicateExternalRefs option to importer.Options
- Modify validateNoDuplicateExternalRefs to clear duplicates when enabled
- Keep first occurrence, clear rest when flag is set
- Enhanced error message to suggest the flag
- Add comprehensive tests for the new behavior

Usage: bd import -i issues.jsonl --clear-duplicate-external-refs
Amp-Thread-ID: https://ampcode.com/threads/T-932dcf45-76f2-4994-9b5c-a6eb20a86036
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-11-06 13:01:44 -08:00
parent b5e2ef4a59
commit 9de98cf1cb
4 changed files with 80 additions and 31 deletions

View File

@@ -158,12 +158,13 @@ func issueDataChanged(existing *types.Issue, updates map[string]interface{}) boo
// ImportOptions configures how the import behaves
type ImportOptions struct {
DryRun bool // Preview changes without applying them
SkipUpdate bool // Skip updating existing issues (create-only mode)
Strict bool // Fail on any error (dependencies, labels, etc.)
RenameOnImport bool // Rename imported issues to match database prefix
SkipPrefixValidation bool // Skip prefix validation (for auto-import)
OrphanHandling string // Orphan handling mode: strict/resurrect/skip/allow (empty = use config)
DryRun bool // Preview changes without applying them
SkipUpdate bool // Skip updating existing issues (create-only mode)
Strict bool // Fail on any error (dependencies, labels, etc.)
RenameOnImport bool // Rename imported issues to match database prefix
SkipPrefixValidation bool // Skip prefix validation (for auto-import)
ClearDuplicateExternalRefs bool // Clear duplicate external_ref values instead of erroring
OrphanHandling string // Orphan handling mode: strict/resurrect/skip/allow (empty = use config)
}
// ImportResult contains statistics about the import operation
@@ -210,12 +211,13 @@ func importIssuesCore(ctx context.Context, dbPath string, store storage.Storage,
// Convert ImportOptions to importer.Options
importerOpts := importer.Options{
DryRun: opts.DryRun,
SkipUpdate: opts.SkipUpdate,
Strict: opts.Strict,
RenameOnImport: opts.RenameOnImport,
SkipPrefixValidation: opts.SkipPrefixValidation,
OrphanHandling: importer.OrphanHandling(orphanHandling),
DryRun: opts.DryRun,
SkipUpdate: opts.SkipUpdate,
Strict: opts.Strict,
RenameOnImport: opts.RenameOnImport,
SkipPrefixValidation: opts.SkipPrefixValidation,
ClearDuplicateExternalRefs: opts.ClearDuplicateExternalRefs,
OrphanHandling: importer.OrphanHandling(orphanHandling),
}
// Delegate to the importer package