From 26566b870f69c983827905b5e8d7342aaa194a88 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 26 May 2026 12:14:09 -0400 Subject: [PATCH 1/2] Move backup, restore, and collection commands under Work with Pinecone indexes. An index is the primary resource for storing, managing, and querying your vector data. Pinecone offers two types of indexes: dense and sparse. Dense indexes are best for semantic search, and sparse indexes are best for keyword search. --- .../pkg/cli/command/backup/backup_test.go | 51 ------------------- .../cli/command/index/backup/backup_test.go | 43 ++++++++++++++++ .../pkg/cli/command/{ => index}/backup/cmd.go | 30 +++++------ .../cli/command/{ => index}/backup/create.go | 6 +-- .../command/{ => index}/backup/create_test.go | 0 .../cli/command/{ => index}/backup/delete.go | 2 +- .../command/{ => index}/backup/delete_test.go | 0 .../command/{ => index}/backup/describe.go | 5 +- .../{ => index}/backup/describe_test.go | 0 .../cli/command/{ => index}/backup/list.go | 5 +- .../command/{ => index}/backup/list_test.go | 0 internal/pkg/cli/command/index/cmd.go | 8 +++ .../cli/command/{ => index}/collection/cmd.go | 8 ++- .../command/{ => index}/collection/create.go | 7 +-- .../command/{ => index}/collection/delete.go | 4 +- .../{ => index}/collection/delete_test.go | 0 .../{ => index}/collection/describe.go | 5 +- .../command/{ => index}/collection/list.go | 4 +- .../command/{backup => index}/restore/cmd.go | 37 +++++++------- .../{backup => index}/restore/describe.go | 2 +- .../command/{backup => index}/restore/list.go | 4 +- .../{backup => index}/restore/restore_test.go | 12 ++--- internal/pkg/cli/command/root/root.go | 4 -- internal/pkg/utils/help/groups.go | 4 ++ 24 files changed, 120 insertions(+), 121 deletions(-) delete mode 100644 internal/pkg/cli/command/backup/backup_test.go create mode 100644 internal/pkg/cli/command/index/backup/backup_test.go rename internal/pkg/cli/command/{ => index}/backup/cmd.go (60%) rename internal/pkg/cli/command/{ => index}/backup/create.go (91%) rename internal/pkg/cli/command/{ => index}/backup/create_test.go (100%) rename internal/pkg/cli/command/{ => index}/backup/delete.go (97%) rename internal/pkg/cli/command/{ => index}/backup/delete_test.go (100%) rename internal/pkg/cli/command/{ => index}/backup/describe.go (91%) rename internal/pkg/cli/command/{ => index}/backup/describe_test.go (100%) rename internal/pkg/cli/command/{ => index}/backup/list.go (96%) rename internal/pkg/cli/command/{ => index}/backup/list_test.go (100%) rename internal/pkg/cli/command/{ => index}/collection/cmd.go (80%) rename internal/pkg/cli/command/{ => index}/collection/create.go (90%) rename internal/pkg/cli/command/{ => index}/collection/delete.go (96%) rename internal/pkg/cli/command/{ => index}/collection/delete_test.go (100%) rename internal/pkg/cli/command/{ => index}/collection/describe.go (94%) rename internal/pkg/cli/command/{ => index}/collection/list.go (95%) rename internal/pkg/cli/command/{backup => index}/restore/cmd.go (74%) rename internal/pkg/cli/command/{backup => index}/restore/describe.go (97%) rename internal/pkg/cli/command/{backup => index}/restore/list.go (95%) rename internal/pkg/cli/command/{backup => index}/restore/restore_test.go (90%) diff --git a/internal/pkg/cli/command/backup/backup_test.go b/internal/pkg/cli/command/backup/backup_test.go deleted file mode 100644 index 9067f716..00000000 --- a/internal/pkg/cli/command/backup/backup_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package backup - -import ( - "context" - - "github.com/pinecone-io/go-pinecone/v5/pinecone" -) - -type mockBackupService struct { - lastCreateBackupReq *pinecone.CreateBackupParams - lastDescribeBackupId string - lastListBackupsParams *pinecone.ListBackupsParams - lastDeleteBackupId string - lastCreateIndexFromBackupReq *pinecone.CreateIndexFromBackupParams - - createBackupResp *pinecone.Backup - describeBackupResp *pinecone.Backup - listBackupsResp *pinecone.BackupList - createIndexFromBackupResp *pinecone.CreateIndexFromBackupResponse - - createBackupErr error - describeBackupErr error - listBackupsErr error - deleteBackupErr error - createIndexFromBackupErr error -} - -func (m *mockBackupService) CreateBackup(ctx context.Context, in *pinecone.CreateBackupParams) (*pinecone.Backup, error) { - m.lastCreateBackupReq = in - return m.createBackupResp, m.createBackupErr -} - -func (m *mockBackupService) DescribeBackup(ctx context.Context, backupId string) (*pinecone.Backup, error) { - m.lastDescribeBackupId = backupId - return m.describeBackupResp, m.describeBackupErr -} - -func (m *mockBackupService) ListBackups(ctx context.Context, in *pinecone.ListBackupsParams) (*pinecone.BackupList, error) { - m.lastListBackupsParams = in - return m.listBackupsResp, m.listBackupsErr -} - -func (m *mockBackupService) DeleteBackup(ctx context.Context, backupId string) error { - m.lastDeleteBackupId = backupId - return m.deleteBackupErr -} - -func (m *mockBackupService) CreateIndexFromBackup(ctx context.Context, in *pinecone.CreateIndexFromBackupParams) (*pinecone.CreateIndexFromBackupResponse, error) { - m.lastCreateIndexFromBackupReq = in - return m.createIndexFromBackupResp, m.createIndexFromBackupErr -} diff --git a/internal/pkg/cli/command/index/backup/backup_test.go b/internal/pkg/cli/command/index/backup/backup_test.go new file mode 100644 index 00000000..4a547207 --- /dev/null +++ b/internal/pkg/cli/command/index/backup/backup_test.go @@ -0,0 +1,43 @@ +package backup + +import ( + "context" + + "github.com/pinecone-io/go-pinecone/v5/pinecone" +) + +type mockBackupService struct { + lastCreateBackupReq *pinecone.CreateBackupParams + lastDescribeBackupId string + lastListBackupsParams *pinecone.ListBackupsParams + lastDeleteBackupId string + + createBackupResp *pinecone.Backup + describeBackupResp *pinecone.Backup + listBackupsResp *pinecone.BackupList + + createBackupErr error + describeBackupErr error + listBackupsErr error + deleteBackupErr error +} + +func (m *mockBackupService) CreateBackup(ctx context.Context, in *pinecone.CreateBackupParams) (*pinecone.Backup, error) { + m.lastCreateBackupReq = in + return m.createBackupResp, m.createBackupErr +} + +func (m *mockBackupService) DescribeBackup(ctx context.Context, backupId string) (*pinecone.Backup, error) { + m.lastDescribeBackupId = backupId + return m.describeBackupResp, m.describeBackupErr +} + +func (m *mockBackupService) ListBackups(ctx context.Context, in *pinecone.ListBackupsParams) (*pinecone.BackupList, error) { + m.lastListBackupsParams = in + return m.listBackupsResp, m.listBackupsErr +} + +func (m *mockBackupService) DeleteBackup(ctx context.Context, backupId string) error { + m.lastDeleteBackupId = backupId + return m.deleteBackupErr +} diff --git a/internal/pkg/cli/command/backup/cmd.go b/internal/pkg/cli/command/index/backup/cmd.go similarity index 60% rename from internal/pkg/cli/command/backup/cmd.go rename to internal/pkg/cli/command/index/backup/cmd.go index 14a21354..0b15f1de 100644 --- a/internal/pkg/cli/command/backup/cmd.go +++ b/internal/pkg/cli/command/index/backup/cmd.go @@ -1,19 +1,18 @@ package backup import ( - "github.com/pinecone-io/cli/internal/pkg/cli/command/backup/restore" "github.com/pinecone-io/cli/internal/pkg/utils/help" "github.com/spf13/cobra" ) + var ( backupHelp = help.Long(` Manage backups for serverless indexes. A backup is a static copy of a serverless index that only consumes storage. It is a non-queryable representation of a set of records. You can create a backup of a serverless index, and you can create a new index from a backup. - Use these commands to create, describe, list, and delete backups, or to - restore an index from a backup, or inspect restore jobs. + Use these commands to create, describe, list, and delete backups. See: https://docs.pinecone.io/guides/manage-data/backups-overview `) @@ -21,24 +20,25 @@ var ( func NewBackupCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "backup", - Short: "Manage serverless index backups", - Long: backupHelp, + Use: "backup", + Short: "Manage serverless index backups", + Long: backupHelp, + GroupID: help.GROUP_INDEX_MANAGEMENT.ID, Example: help.Examples(` # Create a backup for a serverless index - pc backup create --index-name my-index --name daily-backup + pc index backup create --index-name my-index --name daily-backup # List backups for a serverless index - pc backup list --index-name my-index + pc index backup list --index-name my-index - # Restore an index from a backup - pc backup restore --id backup-123 --name restored-index + # List all backups in the project + pc index backup list - # List restore jobs - pc backup restore list + # Describe a backup + pc index backup describe --id backup-123 - # Describe a restore job - pc backup restore describe --id rj-123 + # Delete a backup + pc index backup delete --id backup-123 `), } @@ -47,7 +47,5 @@ func NewBackupCmd() *cobra.Command { cmd.AddCommand(NewListBackupsCmd()) cmd.AddCommand(NewDeleteBackupCmd()) - cmd.AddCommand(restore.NewRestoreJobCmd()) - return cmd } diff --git a/internal/pkg/cli/command/backup/create.go b/internal/pkg/cli/command/index/backup/create.go similarity index 91% rename from internal/pkg/cli/command/backup/create.go rename to internal/pkg/cli/command/index/backup/create.go index 322a7e66..74d42a06 100644 --- a/internal/pkg/cli/command/backup/create.go +++ b/internal/pkg/cli/command/index/backup/create.go @@ -16,12 +16,12 @@ import ( "github.com/spf13/cobra" ) +// BackupService defines the SDK operations used by backup commands. type BackupService interface { CreateBackup(ctx context.Context, in *pinecone.CreateBackupParams) (*pinecone.Backup, error) DescribeBackup(ctx context.Context, backupId string) (*pinecone.Backup, error) ListBackups(ctx context.Context, in *pinecone.ListBackupsParams) (*pinecone.BackupList, error) DeleteBackup(ctx context.Context, backupId string) error - CreateIndexFromBackup(ctx context.Context, in *pinecone.CreateIndexFromBackupParams) (*pinecone.CreateIndexFromBackupResponse, error) } type createBackupCmdOptions struct { @@ -44,8 +44,8 @@ func NewCreateBackupCmd() *cobra.Command { the backup later. `), Example: help.Examples(` - pc backup create --index-name my-index - pc backup create --index-name my-index --name nightly --description "Nightly backup" + pc index backup create --index-name my-index + pc index backup create --index-name my-index --name nightly --description "Nightly backup" `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() diff --git a/internal/pkg/cli/command/backup/create_test.go b/internal/pkg/cli/command/index/backup/create_test.go similarity index 100% rename from internal/pkg/cli/command/backup/create_test.go rename to internal/pkg/cli/command/index/backup/create_test.go diff --git a/internal/pkg/cli/command/backup/delete.go b/internal/pkg/cli/command/index/backup/delete.go similarity index 97% rename from internal/pkg/cli/command/backup/delete.go rename to internal/pkg/cli/command/index/backup/delete.go index 5fe4c97c..1e4ff98a 100644 --- a/internal/pkg/cli/command/backup/delete.go +++ b/internal/pkg/cli/command/index/backup/delete.go @@ -26,7 +26,7 @@ func NewDeleteBackupCmd() *cobra.Command { Use: "delete", Short: "Delete a backup by ID", Example: help.Examples(` - pc backup delete --id backup-123 + pc index backup delete --id backup-123 `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() diff --git a/internal/pkg/cli/command/backup/delete_test.go b/internal/pkg/cli/command/index/backup/delete_test.go similarity index 100% rename from internal/pkg/cli/command/backup/delete_test.go rename to internal/pkg/cli/command/index/backup/delete_test.go diff --git a/internal/pkg/cli/command/backup/describe.go b/internal/pkg/cli/command/index/backup/describe.go similarity index 91% rename from internal/pkg/cli/command/backup/describe.go rename to internal/pkg/cli/command/index/backup/describe.go index c2946aa4..e4a00bf4 100644 --- a/internal/pkg/cli/command/backup/describe.go +++ b/internal/pkg/cli/command/index/backup/describe.go @@ -25,8 +25,11 @@ func NewDescribeBackupCmd() *cobra.Command { cmd := &cobra.Command{ Use: "describe", Short: "Describe a backup by ID", + Long: help.Long(` + Describe a backup by its ID, showing status, source index, and storage details. + `), Example: help.Examples(` - pc backup describe --id backup-123 + pc index backup describe --id backup-123 `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() diff --git a/internal/pkg/cli/command/backup/describe_test.go b/internal/pkg/cli/command/index/backup/describe_test.go similarity index 100% rename from internal/pkg/cli/command/backup/describe_test.go rename to internal/pkg/cli/command/index/backup/describe_test.go diff --git a/internal/pkg/cli/command/backup/list.go b/internal/pkg/cli/command/index/backup/list.go similarity index 96% rename from internal/pkg/cli/command/backup/list.go rename to internal/pkg/cli/command/index/backup/list.go index 4cf98629..90ef9ce6 100644 --- a/internal/pkg/cli/command/backup/list.go +++ b/internal/pkg/cli/command/index/backup/list.go @@ -2,7 +2,6 @@ package backup import ( "context" - "fmt" "github.com/pinecone-io/cli/internal/pkg/utils/exit" @@ -33,10 +32,10 @@ func NewListBackupsCmd() *cobra.Command { `), Example: help.Examples(` # List backups for the current project - pc backup list + pc index backup list # List backups for a specific index - pc backup list --index-name my-index --limit 10 + pc index backup list --index-name my-index --limit 10 `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() diff --git a/internal/pkg/cli/command/backup/list_test.go b/internal/pkg/cli/command/index/backup/list_test.go similarity index 100% rename from internal/pkg/cli/command/backup/list_test.go rename to internal/pkg/cli/command/index/backup/list_test.go diff --git a/internal/pkg/cli/command/index/cmd.go b/internal/pkg/cli/command/index/cmd.go index d6818783..7dca57f5 100644 --- a/internal/pkg/cli/command/index/cmd.go +++ b/internal/pkg/cli/command/index/cmd.go @@ -1,8 +1,11 @@ package index import ( + "github.com/pinecone-io/cli/internal/pkg/cli/command/index/backup" + "github.com/pinecone-io/cli/internal/pkg/cli/command/index/collection" "github.com/pinecone-io/cli/internal/pkg/cli/command/index/namespace" "github.com/pinecone-io/cli/internal/pkg/cli/command/index/record" + "github.com/pinecone-io/cli/internal/pkg/cli/command/index/restore" "github.com/pinecone-io/cli/internal/pkg/cli/command/index/vector" "github.com/pinecone-io/cli/internal/pkg/utils/help" "github.com/spf13/cobra" @@ -49,5 +52,10 @@ func NewIndexCmd() *cobra.Command { cmd.AddGroup(help.GROUP_INDEX_NAMESPACE) cmd.AddCommand(namespace.NewNamespaceCmd()) + cmd.AddGroup(help.GROUP_INDEX_MANAGEMENT) + cmd.AddCommand(backup.NewBackupCmd()) + cmd.AddCommand(restore.NewRestoreCmd()) + cmd.AddCommand(collection.NewCollectionCmd()) + return cmd } diff --git a/internal/pkg/cli/command/collection/cmd.go b/internal/pkg/cli/command/index/collection/cmd.go similarity index 80% rename from internal/pkg/cli/command/collection/cmd.go rename to internal/pkg/cli/command/index/collection/cmd.go index 4b805350..134409c4 100644 --- a/internal/pkg/cli/command/collection/cmd.go +++ b/internal/pkg/cli/command/index/collection/cmd.go @@ -29,7 +29,13 @@ func NewCollectionCmd() *cobra.Command { Use: "collection", Short: "Work with collections (pod-based indexes only)", Long: collectionHelp, - GroupID: help.GROUP_VECTORDB.ID, + GroupID: help.GROUP_INDEX_MANAGEMENT.ID, + Example: help.Examples(` + pc index collection list + pc index collection create --name my-collection --source my-index + pc index collection describe --name my-collection + pc index collection delete --name my-collection + `), } cmd.AddCommand(NewCreateCollectionCmd()) diff --git a/internal/pkg/cli/command/collection/create.go b/internal/pkg/cli/command/index/collection/create.go similarity index 90% rename from internal/pkg/cli/command/collection/create.go rename to internal/pkg/cli/command/index/collection/create.go index 1a241561..6b37fe81 100644 --- a/internal/pkg/cli/command/collection/create.go +++ b/internal/pkg/cli/command/index/collection/create.go @@ -29,7 +29,7 @@ func NewCreateCollectionCmd() *cobra.Command { Use: "create", Short: "Create a collection from a pod-based index", Example: help.Examples(` - pc collection create --name "collection-name" --source "index-source-name" + pc index collection create --name my-collection --source my-index `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() @@ -49,20 +49,17 @@ func NewCreateCollectionCmd() *cobra.Command { json := text.IndentJSON(collection) fmt.Fprintln(os.Stdout, json) } else { - describeCommand := fmt.Sprintf("pc collection describe --name %s", collection.Name) + describeCommand := fmt.Sprintf("pc index collection describe --name %s", collection.Name) msg.SuccessMsg("Collection %s created successfully. Run %s to check status. \n\n", style.Emphasis(collection.Name), style.Code(describeCommand)) presenters.PrintDescribeCollectionTable(collection) } }, } - // Required flags cmd.Flags().StringVarP(&options.name, "name", "n", "", "name you want to give the collection") _ = cmd.MarkFlagRequired("name") cmd.Flags().StringVarP(&options.sourceIndex, "source", "s", "", "name of the index to use as the source for the collection") _ = cmd.MarkFlagRequired("source") - - // Optional flags cmd.Flags().BoolVarP(&options.json, "json", "j", false, "output as JSON") return cmd diff --git a/internal/pkg/cli/command/collection/delete.go b/internal/pkg/cli/command/index/collection/delete.go similarity index 96% rename from internal/pkg/cli/command/collection/delete.go rename to internal/pkg/cli/command/index/collection/delete.go index bedfc986..20931ada 100644 --- a/internal/pkg/cli/command/collection/delete.go +++ b/internal/pkg/cli/command/index/collection/delete.go @@ -29,7 +29,7 @@ func NewDeleteCollectionCmd() *cobra.Command { Use: "delete", Short: "Delete a collection", Example: help.Examples(` - pc collection delete --name "collection-name" + pc index collection delete --name my-collection `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() @@ -43,10 +43,8 @@ func NewDeleteCollectionCmd() *cobra.Command { }, } - // required flags cmd.Flags().StringVarP(&options.name, "name", "n", "", "name of collection to delete") cmd.Flags().BoolVarP(&options.json, "json", "j", false, "Output result as JSON") - _ = cmd.MarkFlagRequired("name") return cmd diff --git a/internal/pkg/cli/command/collection/delete_test.go b/internal/pkg/cli/command/index/collection/delete_test.go similarity index 100% rename from internal/pkg/cli/command/collection/delete_test.go rename to internal/pkg/cli/command/index/collection/delete_test.go diff --git a/internal/pkg/cli/command/collection/describe.go b/internal/pkg/cli/command/index/collection/describe.go similarity index 94% rename from internal/pkg/cli/command/collection/describe.go rename to internal/pkg/cli/command/index/collection/describe.go index c7ea475d..2bc4026f 100644 --- a/internal/pkg/cli/command/collection/describe.go +++ b/internal/pkg/cli/command/index/collection/describe.go @@ -25,7 +25,7 @@ func NewDescribeCollectionCmd() *cobra.Command { Use: "describe", Short: "Describe a collection by name", Example: help.Examples(` - pc collection describe --name "collection-name" + pc index collection describe --name my-collection `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() @@ -46,11 +46,8 @@ func NewDescribeCollectionCmd() *cobra.Command { }, } - // required flags cmd.Flags().StringVarP(&options.name, "name", "n", "", "name of collection to describe") _ = cmd.MarkFlagRequired("name") - - // optional flags cmd.Flags().BoolVarP(&options.json, "json", "j", false, "output as JSON") return cmd diff --git a/internal/pkg/cli/command/collection/list.go b/internal/pkg/cli/command/index/collection/list.go similarity index 95% rename from internal/pkg/cli/command/collection/list.go rename to internal/pkg/cli/command/index/collection/list.go index 33cea4e3..e24d3687 100644 --- a/internal/pkg/cli/command/collection/list.go +++ b/internal/pkg/cli/command/index/collection/list.go @@ -29,7 +29,7 @@ func NewListCollectionsCmd() *cobra.Command { Use: "list", Short: "See the list of collections in your project", Example: help.Examples(` - pc collection list + pc index collection list `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() @@ -41,7 +41,6 @@ func NewListCollectionsCmd() *cobra.Command { exit.Error(err, "Failed to list collections") } - // Sort results alphabetically by name sort.SliceStable(collections, func(i, j int) bool { return collections[i].Name < collections[j].Name }) @@ -55,7 +54,6 @@ func NewListCollectionsCmd() *cobra.Command { }, } - // Optional flags cmd.Flags().BoolVarP(&options.json, "json", "j", false, "output as JSON") return cmd diff --git a/internal/pkg/cli/command/backup/restore/cmd.go b/internal/pkg/cli/command/index/restore/cmd.go similarity index 74% rename from internal/pkg/cli/command/backup/restore/cmd.go rename to internal/pkg/cli/command/index/restore/cmd.go index 3732a9bd..e6233b63 100644 --- a/internal/pkg/cli/command/backup/restore/cmd.go +++ b/internal/pkg/cli/command/index/restore/cmd.go @@ -16,18 +16,19 @@ import ( ) var ( - restoreJobHelp = help.Long(` - Restore an index from a backup, and list/describe restore jobs. + restoreHelp = help.Long(` + Restore an index from a backup, and list or describe restore jobs. - When restoring a serverless index from backup, you can change the index name, tags, and deletion protection setting. - All other properties of the restored index will remain identical to the source index, including cloud and region, - dimension and similarity metric, and associated embedding model when restoring an index with integrated embedding. + When restoring a serverless index from a backup, you can change the index name, tags, + and deletion protection setting. All other properties of the restored index will remain + identical to the source index, including cloud and region, dimension and similarity metric, + and associated embedding model when restoring an index with integrated embedding. See: https://docs.pinecone.io/guides/manage-data/restore-an-index `) ) -type restoreJobCmdOptions struct { +type restoreCmdOptions struct { backupId string name string deletionProtection string @@ -35,33 +36,35 @@ type restoreJobCmdOptions struct { json bool } +// RestoreJobService defines the SDK operations used by restore commands. type RestoreJobService interface { DescribeRestoreJob(ctx context.Context, restoreJobId string) (*pinecone.RestoreJob, error) ListRestoreJobs(ctx context.Context, in *pinecone.ListRestoreJobsParams) (*pinecone.RestoreJobList, error) CreateIndexFromBackup(ctx context.Context, in *pinecone.CreateIndexFromBackupParams) (*pinecone.CreateIndexFromBackupResponse, error) } -func NewRestoreJobCmd() *cobra.Command { - options := restoreJobCmdOptions{} +func NewRestoreCmd() *cobra.Command { + options := restoreCmdOptions{} cmd := &cobra.Command{ - Use: "restore", - Short: "Restore an index from a backup, and inspect restore jobs", - Long: restoreJobHelp, + Use: "restore", + Short: "Restore an index from a backup and manage restore jobs", + Long: restoreHelp, + GroupID: help.GROUP_INDEX_MANAGEMENT.ID, Example: help.Examples(` # Restore an index from a backup - pc backup restore --id backup-123 --name restored-index --tags env=prod,team=search --deletion-protection enabled + pc index restore --id backup-123 --name restored-index --tags env=prod,team=search --deletion-protection enabled # List restore jobs - pc backup restore list + pc index restore list # Describe a restore job - pc backup restore describe --id rj-123 + pc index restore describe --id rj-123 `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() pc := sdk.NewPineconeClient(ctx) - err := runRestoreJobCmd(ctx, pc, options) + err := runRestoreCmd(ctx, pc, options) if err != nil { msg.FailJSON(options.json, "Failed to create restore job: %s\n", err) exit.Error(err, "Failed to create restore job") @@ -83,7 +86,7 @@ func NewRestoreJobCmd() *cobra.Command { return cmd } -func runRestoreJobCmd(ctx context.Context, svc RestoreJobService, options restoreJobCmdOptions) error { +func runRestoreCmd(ctx context.Context, svc RestoreJobService, options restoreCmdOptions) error { if strings.TrimSpace(options.backupId) == "" { return fmt.Errorf("--id is required") } @@ -119,7 +122,7 @@ func runRestoreJobCmd(ctx context.Context, svc RestoreJobService, options restor msg.SuccessMsg("Restore job %s started for backup %s.\n", style.Emphasis(resp.RestoreJobId), style.Emphasis(options.backupId)) msg.InfoMsg("Created index ID: %s\n", style.Emphasis(resp.IndexId)) - msg.InfoMsg("Use %s to monitor progress.\n", style.Code("pc backup restore describe --id "+resp.RestoreJobId)) + msg.InfoMsg("Use %s to monitor progress.\n", style.Code("pc index restore describe --id "+resp.RestoreJobId)) return nil } diff --git a/internal/pkg/cli/command/backup/restore/describe.go b/internal/pkg/cli/command/index/restore/describe.go similarity index 97% rename from internal/pkg/cli/command/backup/restore/describe.go rename to internal/pkg/cli/command/index/restore/describe.go index 7aa2be33..c47fad39 100644 --- a/internal/pkg/cli/command/backup/restore/describe.go +++ b/internal/pkg/cli/command/index/restore/describe.go @@ -26,7 +26,7 @@ func NewDescribeRestoreJobCmd() *cobra.Command { Use: "describe", Short: "Describe a restore job by ID", Example: help.Examples(` - pc backup restore describe --id rj-123 + pc index restore describe --id rj-123 `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() diff --git a/internal/pkg/cli/command/backup/restore/list.go b/internal/pkg/cli/command/index/restore/list.go similarity index 95% rename from internal/pkg/cli/command/backup/restore/list.go rename to internal/pkg/cli/command/index/restore/list.go index ec483147..f32086cd 100644 --- a/internal/pkg/cli/command/backup/restore/list.go +++ b/internal/pkg/cli/command/index/restore/list.go @@ -27,8 +27,8 @@ func NewListRestoreJobsCmd() *cobra.Command { Use: "list", Short: "List restore jobs in the current project", Example: help.Examples(` - pc backup restore list - pc backup restore list --limit 5 --pagination-token token + pc index restore list + pc index restore list --limit 5 --pagination-token token `), Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() diff --git a/internal/pkg/cli/command/backup/restore/restore_test.go b/internal/pkg/cli/command/index/restore/restore_test.go similarity index 90% rename from internal/pkg/cli/command/backup/restore/restore_test.go rename to internal/pkg/cli/command/index/restore/restore_test.go index c7228227..8316472d 100644 --- a/internal/pkg/cli/command/backup/restore/restore_test.go +++ b/internal/pkg/cli/command/index/restore/restore_test.go @@ -90,31 +90,31 @@ func Test_runListRestoreJobsCmd_PopulatesParams(t *testing.T) { } } -func Test_runRestoreJobCmd_ValidatesRequired(t *testing.T) { +func Test_runRestoreCmd_ValidatesRequired(t *testing.T) { svc := &mockRestoreJobService{} - err := runRestoreJobCmd(context.Background(), svc, restoreJobCmdOptions{}) + err := runRestoreCmd(context.Background(), svc, restoreCmdOptions{}) assert.Error(t, err) - err = runRestoreJobCmd(context.Background(), svc, restoreJobCmdOptions{backupId: "b1"}) + err = runRestoreCmd(context.Background(), svc, restoreCmdOptions{backupId: "b1"}) assert.Error(t, err) } -func Test_runCreateIndexFromBackupCmd_Succeeds(t *testing.T) { +func Test_runRestoreCmd_Succeeds(t *testing.T) { svc := &mockRestoreJobService{ createIndexFromBackupResp: &pinecone.CreateIndexFromBackupResponse{ IndexId: "idx-id", RestoreJobId: "rj-1", }, } - opts := restoreJobCmdOptions{ + opts := restoreCmdOptions{ backupId: "b1", name: "new-index", deletionProtection: "enabled", tags: map[string]string{"env": "prod"}, } - err := runRestoreJobCmd(context.Background(), svc, opts) + err := runRestoreCmd(context.Background(), svc, opts) if assert.NoError(t, err) { if assert.NotNil(t, svc.lastCreateIndexFromBackupReq) { diff --git a/internal/pkg/cli/command/root/root.go b/internal/pkg/cli/command/root/root.go index 674eb192..a05007ce 100644 --- a/internal/pkg/cli/command/root/root.go +++ b/internal/pkg/cli/command/root/root.go @@ -11,8 +11,6 @@ import ( "github.com/pinecone-io/cli/internal/pkg/cli/command/apiKey" "github.com/pinecone-io/cli/internal/pkg/cli/command/auth" - "github.com/pinecone-io/cli/internal/pkg/cli/command/backup" - "github.com/pinecone-io/cli/internal/pkg/cli/command/collection" "github.com/pinecone-io/cli/internal/pkg/cli/command/config" "github.com/pinecone-io/cli/internal/pkg/cli/command/index" "github.com/pinecone-io/cli/internal/pkg/cli/command/login" @@ -172,8 +170,6 @@ func init() { // Vector database group rootCmd.AddGroup(help.GROUP_VECTORDB) rootCmd.AddCommand(index.NewIndexCmd()) - rootCmd.AddCommand(collection.NewCollectionCmd()) - rootCmd.AddCommand(backup.NewBackupCmd()) // Misc group rootCmd.AddCommand(version.NewVersionCmd()) diff --git a/internal/pkg/utils/help/groups.go b/internal/pkg/utils/help/groups.go index 69605f3d..d0d204ed 100644 --- a/internal/pkg/utils/help/groups.go +++ b/internal/pkg/utils/help/groups.go @@ -38,4 +38,8 @@ var ( ID: "index-namespace", Title: style.Heading("Index Namespace Commands"), } + GROUP_INDEX_MANAGEMENT = &cobra.Group{ + ID: "index-management", + Title: style.Heading("Index Management Commands"), + } ) From 8f93a20e06ca4a731fc736a63d5974082b543bd6 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 26 May 2026 12:49:11 -0400 Subject: [PATCH 2/2] make name required when calling index configure command, make sure we're properly passing metric and dimension when creating an integrated index, expose description, source index ID, and dimension in PrintBackupTable --- internal/pkg/cli/command/index/configure.go | 1 + internal/pkg/cli/command/index/create.go | 10 ++++++ internal/pkg/cli/command/index/create_test.go | 32 +++++++++++++++++++ internal/pkg/utils/presenters/backup.go | 3 ++ 4 files changed, 46 insertions(+) diff --git a/internal/pkg/cli/command/index/configure.go b/internal/pkg/cli/command/index/configure.go index d0636eaf..5e55925c 100644 --- a/internal/pkg/cli/command/index/configure.go +++ b/internal/pkg/cli/command/index/configure.go @@ -59,6 +59,7 @@ func NewConfigureIndexCmd() *cobra.Command { // Required flags cmd.Flags().StringVarP(&options.name, "name", "n", "", "Name of index to configure") + _ = cmd.MarkFlagRequired("name") // pods cmd.Flags().StringVarP(&options.podType, "pod-type", "t", "", "Type of pod to use, can only upgrade when configuring") diff --git a/internal/pkg/cli/command/index/create.go b/internal/pkg/cli/command/index/create.go index 14cfaa52..de037b5f 100644 --- a/internal/pkg/cli/command/index/create.go +++ b/internal/pkg/cli/command/index/create.go @@ -262,6 +262,14 @@ func runCreateIndexCmd(ctx context.Context, cmd *cobra.Command, service CreateIn return nil, err } + // Only forward metric if explicitly set — the model has its own default and + // the flag default ("cosine") must not silently override it. + var embedMetric *pinecone.IndexMetric + if cmd.Flags().Changed("metric") { + m := pinecone.IndexMetric(options.metric) + embedMetric = &m + } + args := pinecone.CreateIndexForModelRequest{ Name: options.name, Cloud: pinecone.Cloud(options.cloud), @@ -270,6 +278,8 @@ func runCreateIndexCmd(ctx context.Context, cmd *cobra.Command, service CreateIn Embed: pinecone.CreateIndexForModelEmbed{ Model: options.model, FieldMap: toInterfaceMap(options.fieldMap), + Metric: embedMetric, + Dimension: pointerOrNil(int(options.dimension)), ReadParameters: &readParams, WriteParameters: &writeParams, }, diff --git a/internal/pkg/cli/command/index/create_test.go b/internal/pkg/cli/command/index/create_test.go index f47d79ac..ce4ca194 100644 --- a/internal/pkg/cli/command/index/create_test.go +++ b/internal/pkg/cli/command/index/create_test.go @@ -134,6 +134,38 @@ func Test_runCreateIndexWithService_Integrated_Args(t *testing.T) { assert.Equal(t, toInterfaceMap(options.readParameters), *svc.lastIntegrated.Embed.ReadParameters) assert.Equal(t, toInterfaceMap(options.writeParameters), *svc.lastIntegrated.Embed.WriteParameters) assert.Equal(t, pinecone.IndexTags(options.tags), *svc.lastIntegrated.Tags) + // metric and dimension not explicitly set — must not be forwarded to the embed request + assert.Nil(t, svc.lastIntegrated.Embed.Metric) + assert.Nil(t, svc.lastIntegrated.Embed.Dimension) +} + +func Test_runCreateIndexWithService_Integrated_MetricAndDimension(t *testing.T) { + cmd := NewCreateIndexCmd() + _ = cmd.Flags().Set("metric", "dotproduct") + _ = cmd.Flags().Set("dimension", "512") + + svc := &mockIndexService{result: &pinecone.Index{Name: "my-index"}} + options := createIndexOptions{ + name: "my-index", + cloud: "aws", + region: "us-east-1", + model: "multilingual-e5-large", + fieldMap: map[string]string{"text": "chunk"}, + metric: "dotproduct", + dimension: 512, + } + + _, err := runCreateIndexCmd(context.Background(), cmd, svc, options) + assert.NoError(t, err) + + if assert.NotNil(t, svc.lastIntegrated) { + if assert.NotNil(t, svc.lastIntegrated.Embed.Metric) { + assert.Equal(t, pinecone.IndexMetric("dotproduct"), *svc.lastIntegrated.Embed.Metric) + } + if assert.NotNil(t, svc.lastIntegrated.Embed.Dimension) { + assert.Equal(t, 512, *svc.lastIntegrated.Embed.Dimension) + } + } } func Test_createIndexOptions_deriveIndexType(t *testing.T) { diff --git a/internal/pkg/utils/presenters/backup.go b/internal/pkg/utils/presenters/backup.go index fb21c40f..4d903e80 100644 --- a/internal/pkg/utils/presenters/backup.go +++ b/internal/pkg/utils/presenters/backup.go @@ -23,10 +23,13 @@ func PrintBackupTable(backup *pinecone.Backup) { fmt.Fprintf(writer, "Backup ID\t%s\n", backup.BackupId) fmt.Fprintf(writer, "Name\t%s\n", DisplayOrNone(backup.Name)) + fmt.Fprintf(writer, "Description\t%s\n", DisplayOrNone(backup.Description)) fmt.Fprintf(writer, "Status\t%s\n", colorizeBackupStatus(backup.Status)) fmt.Fprintf(writer, "Source Index\t%s\n", backup.SourceIndexName) + fmt.Fprintf(writer, "Source Index ID\t%s\n", backup.SourceIndexId) fmt.Fprintf(writer, "Cloud\t%s\n", backup.Cloud) fmt.Fprintf(writer, "Region\t%s\n", backup.Region) + fmt.Fprintf(writer, "Dimension\t%s\n", DisplayOrNone(backup.Dimension)) fmt.Fprintf(writer, "Record Count\t%s\n", DisplayOrNone(backup.RecordCount)) fmt.Fprintf(writer, "Namespace Count\t%s\n", DisplayOrNone(backup.NamespaceCount)) fmt.Fprintf(writer, "Size (bytes)\t%s\n", DisplayOrNone(backup.SizeBytes))