Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions internal/pkg/cli/command/apiKey/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import (
"github.com/pinecone-io/cli/internal/pkg/utils/msg"
"github.com/pinecone-io/cli/internal/pkg/utils/sdk"
"github.com/pinecone-io/cli/internal/pkg/utils/style"
"github.com/pinecone-io/cli/internal/pkg/utils/text"
"github.com/spf13/cobra"
)

type deleteAPIKeyOptions struct {
apiKeyId string
skipConfirmation bool
json bool
}

var (
Expand Down Expand Up @@ -58,7 +60,7 @@ func NewDeleteKeyCmd() *cobra.Command {
exit.Error(err, "Failed to describe existing API key")
}

if !options.skipConfirmation {
if !options.skipConfirmation && !options.json {
confirmDeleteApiKey(keyToDelete.Name)
}

Expand All @@ -67,21 +69,31 @@ func NewDeleteKeyCmd() *cobra.Command {
msg.FailMsg("Failed to delete API key %s: %s", style.Emphasis(keyToDelete.Name), err)
exit.Errorf(err, "Failed to delete API key %s", keyToDelete.Name)
}
msg.SuccessMsg("API key %s deleted", style.Emphasis(keyToDelete.Name))

// Check if the key is locally stored and clean it up if so
managedKey, ok := secrets.GetProjectManagedKey(keyToDelete.ProjectId)
if ok && managedKey.Id == keyToDelete.Id {
secrets.DeleteProjectManagedKey(keyToDelete.ProjectId)
msg.SuccessMsg("Deleted local record for key %s (project %s)", style.Emphasis(keyToDelete.Id), style.Emphasis(keyToDelete.ProjectId))
}

if options.json {
fmt.Println(text.IndentJSON(struct {
Deleted bool `json:"deleted"`
Name string `json:"name"`
Id string `json:"id"`
}{Deleted: true, Name: keyToDelete.Name, Id: keyToDelete.Id}))
return
}

msg.SuccessMsg("API key %s deleted", style.Emphasis(keyToDelete.Name))
},
}

cmd.Flags().StringVarP(&options.apiKeyId, "id", "i", "", "The ID of the API key to delete")
_ = cmd.MarkFlagRequired("id")

cmd.Flags().BoolVar(&options.skipConfirmation, "skip-confirmation", false, "Skip deletion confirmation prompt")
cmd.Flags().BoolVarP(&options.json, "json", "j", false, "Output result as JSON (also skips confirmation prompt)")
return cmd
}

Expand Down
22 changes: 20 additions & 2 deletions internal/pkg/cli/command/auth/logout.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
package auth

import (
"fmt"

"github.com/pinecone-io/cli/internal/pkg/utils/configuration/secrets"
"github.com/pinecone-io/cli/internal/pkg/utils/configuration/state"
"github.com/pinecone-io/cli/internal/pkg/utils/help"
"github.com/pinecone-io/cli/internal/pkg/utils/msg"
"github.com/pinecone-io/cli/internal/pkg/utils/text"
"github.com/spf13/cobra"
)

type logoutCmdOptions struct {
json bool
}

func NewLogoutCmd() *cobra.Command {
options := logoutCmdOptions{}

cmd := &cobra.Command{
Use: "logout",
Short: "Clears locally stored API keys (managed and default), service account details (client ID and secret), and user login token. Also clears organization and project target context.",
Expand All @@ -18,12 +27,21 @@ func NewLogoutCmd() *cobra.Command {
GroupID: help.GROUP_AUTH.ID,
Run: func(cmd *cobra.Command, args []string) {
secrets.ConfigFile.Clear()
msg.SuccessMsg("API keys and user access tokens cleared.")

state.ConfigFile.Clear()

if options.json {
fmt.Println(text.IndentJSON(struct {
Status string `json:"status"`
}{Status: "logged_out"}))
return
}

msg.SuccessMsg("API keys and user access tokens cleared.")
msg.SuccessMsg("State cleared.")
},
}

cmd.Flags().BoolVarP(&options.json, "json", "j", false, "Output result as JSON")

return cmd
}
21 changes: 20 additions & 1 deletion internal/pkg/cli/command/auth/whoami.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
package auth

import (
"fmt"

"github.com/pinecone-io/cli/internal/pkg/utils/exit"
"github.com/pinecone-io/cli/internal/pkg/utils/help"
"github.com/pinecone-io/cli/internal/pkg/utils/msg"
"github.com/pinecone-io/cli/internal/pkg/utils/oauth"
"github.com/pinecone-io/cli/internal/pkg/utils/style"
"github.com/pinecone-io/cli/internal/pkg/utils/text"
"github.com/spf13/cobra"
)

type whoamiCmdOptions struct {
json bool
}

func NewWhoAmICmd() *cobra.Command {
options := whoamiCmdOptions{}

cmd := &cobra.Command{
Use: "whoami",
Short: "See the currently logged in user",
Expand All @@ -18,7 +27,6 @@ func NewWhoAmICmd() *cobra.Command {
`),
GroupID: help.GROUP_AUTH.ID,
Run: func(cmd *cobra.Command, args []string) {

token, err := oauth.Token(cmd.Context())
if err != nil {
msg.FailMsg("Error retrieving oauth token: %s", err)
Expand All @@ -36,9 +44,20 @@ func NewWhoAmICmd() *cobra.Command {
exit.Error(err, "An auth token was fetched but an error occurred while parsing the token's claims")
return
}

if options.json {
fmt.Println(text.IndentJSON(struct {
Email string `json:"email"`
OrgId string `json:"organization_id"`
}{Email: claims.Email, OrgId: claims.OrgId}))
return
}

msg.InfoMsg("Logged in as " + style.Emphasis(claims.Email))
},
}

cmd.Flags().BoolVarP(&options.json, "json", "j", false, "Output as JSON")

return cmd
}
107 changes: 0 additions & 107 deletions internal/pkg/cli/command/backup/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/pinecone-io/cli/internal/pkg/cli/testutils"
"github.com/pinecone-io/go-pinecone/v5/pinecone"
"github.com/stretchr/testify/assert"
)

type mockBackupService struct {
Expand Down Expand Up @@ -60,109 +59,3 @@ func TestMain(m *testing.M) {
reset()
os.Exit(code)
}

func Test_runCreateBackupCmd_RequiresIndexName(t *testing.T) {
svc := &mockBackupService{}
opts := createBackupCmdOptions{}

err := runCreateBackupCmd(context.Background(), svc, opts)

assert.Error(t, err)
assert.Nil(t, svc.lastCreateBackupReq)
}

func Test_runCreateBackupCmd_PopulatesRequest(t *testing.T) {
svc := &mockBackupService{
createBackupResp: &pinecone.Backup{BackupId: "b1"},
}
opts := createBackupCmdOptions{
indexName: "idx",
description: "desc",
name: "name",
}

err := runCreateBackupCmd(context.Background(), svc, opts)

if assert.NoError(t, err) {
if assert.NotNil(t, svc.lastCreateBackupReq) {
assert.Equal(t, "idx", svc.lastCreateBackupReq.IndexName)
if assert.NotNil(t, svc.lastCreateBackupReq.Description) {
assert.Equal(t, "desc", *svc.lastCreateBackupReq.Description)
}
if assert.NotNil(t, svc.lastCreateBackupReq.Name) {
assert.Equal(t, "name", *svc.lastCreateBackupReq.Name)
}
}
}
}

func Test_runDescribeBackupCmd_RequiresBackupId(t *testing.T) {
svc := &mockBackupService{}
opts := describeBackupCmdOptions{}

err := runDescribeBackupCmd(context.Background(), svc, opts)

assert.Error(t, err)
assert.Empty(t, svc.lastDescribeBackupId)
}

func Test_runDescribeBackupCmd_Succeeds(t *testing.T) {
svc := &mockBackupService{
describeBackupResp: &pinecone.Backup{BackupId: "b1"},
}
opts := describeBackupCmdOptions{
backupId: "b1",
}

err := runDescribeBackupCmd(context.Background(), svc, opts)

assert.NoError(t, err)
assert.Equal(t, "b1", svc.lastDescribeBackupId)
}

func Test_runListBackupsCmd_PopulatesParams(t *testing.T) {
svc := &mockBackupService{
listBackupsResp: &pinecone.BackupList{},
}
opts := listBackupsCmdOptions{
indexName: "idx",
limit: 5,
paginationToken: "next",
}

err := runListBackupsCmd(context.Background(), svc, opts)

if assert.NoError(t, err) {
if assert.NotNil(t, svc.lastListBackupsParams) {
if assert.NotNil(t, svc.lastListBackupsParams.IndexName) {
assert.Equal(t, "idx", *svc.lastListBackupsParams.IndexName)
}
if assert.NotNil(t, svc.lastListBackupsParams.Limit) {
assert.Equal(t, 5, *svc.lastListBackupsParams.Limit)
}
if assert.NotNil(t, svc.lastListBackupsParams.PaginationToken) {
assert.Equal(t, "next", *svc.lastListBackupsParams.PaginationToken)
}
}
}
}

func Test_runDeleteBackupCmd_RequiresBackupId(t *testing.T) {
svc := &mockBackupService{}
opts := deleteBackupCmdOptions{}

err := runDeleteBackupCmd(context.Background(), svc, opts)

assert.Error(t, err)
assert.Empty(t, svc.lastDeleteBackupId)
}

func Test_runDeleteBackupCmd_Succeeds(t *testing.T) {
svc := &mockBackupService{}
opts := deleteBackupCmdOptions{backupId: "b1"}

err := runDeleteBackupCmd(context.Background(), svc, opts)

assert.NoError(t, err)
assert.Equal(t, "b1", svc.lastDeleteBackupId)
}
4 changes: 2 additions & 2 deletions internal/pkg/cli/command/backup/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package backup

import (
"context"
"fmt"
"strings"

"github.com/pinecone-io/cli/internal/pkg/utils/exit"
Expand Down Expand Up @@ -96,8 +97,7 @@ func runCreateBackupCmd(ctx context.Context, svc BackupService, options createBa
}

if options.json {
json := text.IndentJSON(backup)
pcio.Println(json)
fmt.Println(text.IndentJSON(backup))
} else {
msg.SuccessMsg("Backup %s created.\n", styleEmphasisId(backup))
presenters.PrintBackupTable(backup)
Expand Down
62 changes: 62 additions & 0 deletions internal/pkg/cli/command/backup/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package backup

import (
"context"
"testing"

"github.com/pinecone-io/cli/internal/pkg/cli/testutils"
"github.com/pinecone-io/go-pinecone/v5/pinecone"
"github.com/stretchr/testify/assert"
)

func Test_runCreateBackupCmd_RequiresIndexName(t *testing.T) {
svc := &mockBackupService{}
opts := createBackupCmdOptions{}

err := runCreateBackupCmd(context.Background(), svc, opts)

assert.Error(t, err)
assert.Nil(t, svc.lastCreateBackupReq)
}

func Test_runCreateBackupCmd_Succeeds(t *testing.T) {
svc := &mockBackupService{
createBackupResp: &pinecone.Backup{BackupId: "b1"},
}
opts := createBackupCmdOptions{
indexName: "idx",
description: "desc",
name: "name",
}

err := runCreateBackupCmd(context.Background(), svc, opts)

if assert.NoError(t, err) {
if assert.NotNil(t, svc.lastCreateBackupReq) {
assert.Equal(t, "idx", svc.lastCreateBackupReq.IndexName)
if assert.NotNil(t, svc.lastCreateBackupReq.Description) {
assert.Equal(t, "desc", *svc.lastCreateBackupReq.Description)
}
if assert.NotNil(t, svc.lastCreateBackupReq.Name) {
assert.Equal(t, "name", *svc.lastCreateBackupReq.Name)
}
}
}
}

func Test_runCreateBackupCmd_SucceedsJSON(t *testing.T) {
svc := &mockBackupService{
createBackupResp: &pinecone.Backup{BackupId: "b1"},
}
opts := createBackupCmdOptions{
indexName: "idx",
json: true,
}

out := testutils.CaptureStdout(t, func() {
err := runCreateBackupCmd(context.Background(), svc, opts)
assert.NoError(t, err)
})

assert.Contains(t, out, `"b1"`)
}
Loading
Loading