diff --git a/CHANGELOG.md b/CHANGELOG.md index 456b2c53..249abccb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log + +## [v0.1.1] + +### Added + +- `import`: added flag `--ignore-existing` to ignore TMs that have conflicts with existing TMs instead of returning an error code + + ## [v0.1.0] ### Added diff --git a/cmd/import.go b/cmd/import.go index d35be615..656d5afe 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -39,16 +39,19 @@ func init() { Has no effect when file-or-dirname points to a file. Overrides --opt-path`) importCmd.Flags().Bool("force", false, `Force import, even if there are conflicts with existing TMs.`) + importCmd.Flags().Bool("ignore-existing", false, `Ignore TMs that have conflicts with existing TMs instead of returning an error code.`) } func executeImport(cmd *cobra.Command, args []string) { optPath := cmd.Flag("opt-path").Value.String() optTree, _ := cmd.Flags().GetBool("opt-tree") force, _ := cmd.Flags().GetBool("force") + ie, _ := cmd.Flags().GetBool("ignore-existing") spec := RepoSpec(cmd) opts := repos.ImportOptions{ - Force: force, - OptPath: optPath, + Force: force, + OptPath: optPath, + IgnoreExisting: ie, } _, err := cli.NewImportExecutor(time.Now).Import(context.Background(), args[0], spec, optTree, opts) if err != nil { diff --git a/internal/app/cli/import.go b/internal/app/cli/import.go index f03050c4..e95137e9 100644 --- a/internal/app/cli/import.go +++ b/internal/app/cli/import.go @@ -121,6 +121,9 @@ func (p *ImportExecutor) importFile(ctx context.Context, filename string, repo r var errExists *repos.ErrTMIDConflict if errors.As(err, &errExists) { res.Message = fmt.Sprintf("file %s already exists as %s", filename, errExists.ExistingId) + if opts.IgnoreExisting { + return res, nil + } return res, err } err := fmt.Errorf("error importing file %s: %w", filename, err) diff --git a/internal/app/cli/import_test.go b/internal/app/cli/import_test.go index e19714ce..50adb003 100644 --- a/internal/app/cli/import_test.go +++ b/internal/app/cli/import_test.go @@ -145,6 +145,49 @@ func TestImportExecutor_Import_Directory(t *testing.T) { assert.Equalf(t, repos.ImportResultError, res[3].Type, "res[3]: want ImportResultError, got %v", res[3].Type) } }) + t.Run("import directory with ignore-existing", func(t *testing.T) { + clk := testutils.NewTestClock(time.Date(2023, time.November, 10, 12, 32, 43, 0, time.UTC), time.Second) + e := NewImportExecutor(clk.Now) + opts := repos.ImportOptions{ + IgnoreExisting: true, + } + tmid := model.MustParseTMID("omnicorp-tm-department/omnicorp/omnilamp/v3.2.1-20231110123243-98b3fbd291f4.tm.json") + r.On("Import", mock.Anything, tmid, mock.Anything, opts).Return(repos.ImportResult{Type: repos.ImportResultOK, TmID: tmid.String()}, nil) + tmid = model.MustParseTMID("omnicorp-tm-department/omnicorp/omnilamp/v0.0.0-20231110123244-575dfac219e2.tm.json") + r.On("Import", mock.Anything, tmid, mock.Anything, opts).Return(repos.ImportResult{Type: repos.ImportResultOK, TmID: tmid.String()}, nil) + tmid = model.MustParseTMID("omnicorp-tm-department/omnicorp/omnilamp/v3.2.1-20231110123245-98b3fbd291f4.tm.json") + cErr := &repos.ErrTMIDConflict{Type: repos.IdConflictSameContent, + ExistingId: "omnicorp-tm-department/omnicorp/omnilamp/v3.2.1-20231110123243-98b3fbd291f4.tm.json"} + r.On("Import", mock.Anything, tmid, mock.Anything, opts).Return( + repos.ImportResult{ + Type: repos.ImportResultError, + TmID: "", + Message: cErr.Error(), + Err: cErr, + }, cErr) + tmid = model.MustParseTMID("omnicorp-tm-department/omnicorp/omnilamp/v0.0.0-20231110123246-575dfac219e2.tm.json") + cErr = &repos.ErrTMIDConflict{Type: repos.IdConflictSameContent, + ExistingId: "omnicorp-tm-department/omnicorp/omnilamp/v0.0.0-20231110123244-575dfac219e2.tm.json"} + r.On("Import", mock.Anything, tmid, mock.Anything, opts).Return( + repos.ImportResult{ + Type: repos.ImportResultError, + TmID: "", + Message: cErr.Error(), + Err: cErr, + }, cErr) + r.On("Index", mock.Anything, + "omnicorp-tm-department/omnicorp/omnilamp/v3.2.1-20231110123243-98b3fbd291f4.tm.json", + "omnicorp-tm-department/omnicorp/omnilamp/v0.0.0-20231110123244-575dfac219e2.tm.json").Return(nil) + + res, err := e.Import(context.Background(), "../../../test/data/import", model.NewRepoSpec("repo"), false, opts) + assert.NoError(t, err) + if assert.Len(t, res, 4) { + assert.Equalf(t, repos.ImportResultOK, res[0].Type, "res[0]: want ImportResultOK, got %v", res[0].Type) + assert.Equalf(t, repos.ImportResultOK, res[1].Type, "res[1]: want ImportResultOK, got %v", res[1].Type) + assert.Equalf(t, repos.ImportResultError, res[2].Type, "res[2]: want ImportResultError, got %v", res[2].Type) + assert.Equalf(t, repos.ImportResultError, res[3].Type, "res[3]: want ImportResultError, got %v", res[3].Type) + } + }) t.Run("import directory with optPath", func(t *testing.T) { clk := testutils.NewTestClock(time.Date(2023, time.November, 10, 12, 32, 43, 0, time.UTC), time.Second) diff --git a/internal/repos/repo.go b/internal/repos/repo.go index 9ccae968..7bcfe0c4 100644 --- a/internal/repos/repo.go +++ b/internal/repos/repo.go @@ -123,8 +123,9 @@ type Repo interface { } type ImportOptions struct { - Force bool - OptPath string + Force bool + OptPath string + IgnoreExisting bool } var Get = func(spec model.RepoSpec) (Repo, error) {