From 294916478c735cb33ddf777e6104af45fc8506b9 Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Thu, 30 Jan 2025 07:55:52 +0000 Subject: [PATCH 1/2] chore(cli): support deleting tokens by id --- .../coder_tokens_remove_--help.golden | 6 ++- cli/tokens.go | 41 ++++++++++++++++++- cli/tokens_test.go | 38 ++++++++++++++++- docs/reference/cli/tokens_remove.md | 12 +++++- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/cli/testdata/coder_tokens_remove_--help.golden b/cli/testdata/coder_tokens_remove_--help.golden index 30440e8ef2e7c..81c9a405db0cf 100644 --- a/cli/testdata/coder_tokens_remove_--help.golden +++ b/cli/testdata/coder_tokens_remove_--help.golden @@ -1,11 +1,15 @@ coder v0.0.0-devel USAGE: - coder tokens remove + coder tokens remove [flags] Delete a token Aliases: delete, rm +OPTIONS: + -y, --yes bool + Bypass prompts. + ——— Run `coder --help` for a list of global options. diff --git a/cli/tokens.go b/cli/tokens.go index 2488a687a0c07..88e3cd2585e2a 100644 --- a/cli/tokens.go +++ b/cli/tokens.go @@ -3,6 +3,7 @@ package cli import ( "fmt" "os" + "strings" "time" "golang.org/x/exp/slices" @@ -10,6 +11,7 @@ import ( "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" + "github.com/coder/pretty" "github.com/coder/serpent" ) @@ -223,17 +225,52 @@ func (r *RootCmd) listTokens() *serpent.Command { func (r *RootCmd) removeToken() *serpent.Command { client := new(codersdk.Client) cmd := &serpent.Command{ - Use: "remove ", + Use: "remove ", Aliases: []string{"delete"}, Short: "Delete a token", Middleware: serpent.Chain( serpent.RequireNArgs(1), r.InitClient(client), ), + Options: serpent.OptionSet{ + cliui.SkipPromptOption(), + }, Handler: func(inv *serpent.Invocation) error { token, err := client.APIKeyByName(inv.Context(), codersdk.Me, inv.Args[0]) if err != nil { - return xerrors.Errorf("fetch api key by name %s: %w", inv.Args[0], err) + // If it's a token, we need to extract the ID + maybeID := strings.Split(inv.Args[0], "-")[0] + token, err = client.APIKeyByID(inv.Context(), codersdk.Me, maybeID) + if err != nil { + return xerrors.Errorf("fetch api key by name or id: %w", err) + } + } + + var prompt string + if token.TokenName == "" { + prompt = fmt.Sprintf("Are you sure you want to delete the token with ID %s?\n ", + pretty.Sprint(cliui.DefaultStyles.Code, token.ID), + ) + } else { + prompt = fmt.Sprintf("Are you sure you want to delete the token with the name %s? (ID: %s)\n ", + pretty.Sprint(cliui.DefaultStyles.Code, token.TokenName), + pretty.Sprint(cliui.DefaultStyles.Code, token.ID), + ) + } + + if !token.LastUsed.IsZero() { + prompt = fmt.Sprintf("%sIt was last used on %s.", prompt, pretty.Sprint(cliui.DefaultStyles.Code, token.LastUsed.String())) + } else { + prompt = fmt.Sprintf("%sIt has never been used.", prompt) + } + + _, err = cliui.Prompt(inv, cliui.PromptOptions{ + Text: prompt, + IsConfirm: true, + Default: cliui.ConfirmYes, + }) + if err != nil { + return err } err = client.DeleteAPIKey(inv.Context(), codersdk.Me, token.ID) diff --git a/cli/tokens_test.go b/cli/tokens_test.go index 7c024f3ad1a6f..01eb66ad54075 100644 --- a/cli/tokens_test.go +++ b/cli/tokens_test.go @@ -93,7 +93,7 @@ func TestTokens(t *testing.T) { require.Contains(t, res, secondTokenID) // Test creating a token for third user from second user's (non-admin) session - inv, root = clitest.New(t, "tokens", "create", "--name", "token-two", "--user", thirdUser.ID.String()) + inv, root = clitest.New(t, "tokens", "create", "--name", "failed-token", "--user", thirdUser.ID.String()) clitest.SetupConfig(t, secondUserClient, root) buf = new(bytes.Buffer) inv.Stdout = buf @@ -113,7 +113,41 @@ func TestTokens(t *testing.T) { require.Len(t, tokens, 1) require.Equal(t, id, tokens[0].ID) - inv, root = clitest.New(t, "tokens", "rm", "token-one") + // Delete by name + inv, root = clitest.New(t, "tokens", "rm", "token-one", "--yes") + clitest.SetupConfig(t, client, root) + buf = new(bytes.Buffer) + inv.Stdout = buf + err = inv.WithContext(ctx).Run() + require.NoError(t, err) + res = buf.String() + require.NotEmpty(t, res) + require.Contains(t, res, "deleted") + + // Delete by ID + inv, root = clitest.New(t, "tokens", "rm", secondTokenID, "--yes") + clitest.SetupConfig(t, client, root) + buf = new(bytes.Buffer) + inv.Stdout = buf + err = inv.WithContext(ctx).Run() + require.NoError(t, err) + res = buf.String() + require.NotEmpty(t, res) + require.Contains(t, res, "deleted") + + // Create third token + inv, root = clitest.New(t, "tokens", "create", "--name", "token-three") + clitest.SetupConfig(t, client, root) + buf = new(bytes.Buffer) + inv.Stdout = buf + err = inv.WithContext(ctx).Run() + require.NoError(t, err) + res = buf.String() + require.NotEmpty(t, res) + fourthToken := res + + // Delete by token + inv, root = clitest.New(t, "tokens", "rm", fourthToken, "--yes") clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) inv.Stdout = buf diff --git a/docs/reference/cli/tokens_remove.md b/docs/reference/cli/tokens_remove.md index 8825040f5e3a7..e127ae4dbc309 100644 --- a/docs/reference/cli/tokens_remove.md +++ b/docs/reference/cli/tokens_remove.md @@ -11,5 +11,15 @@ Aliases: ## Usage ```console -coder tokens remove +coder tokens remove [flags] ``` + +## Options + +### -y, --yes + +| | | +|------|-------------------| +| Type | bool | + +Bypass prompts. From ec8ff1a61f52283018e77b133721a658873c2f28 Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Mon, 3 Feb 2025 07:04:47 +0000 Subject: [PATCH 2/2] remove prompt --- .../coder_tokens_remove_--help.golden | 6 +--- cli/tokens.go | 31 ------------------- cli/tokens_test.go | 6 ++-- docs/reference/cli/tokens_remove.md | 12 +------ 4 files changed, 5 insertions(+), 50 deletions(-) diff --git a/cli/testdata/coder_tokens_remove_--help.golden b/cli/testdata/coder_tokens_remove_--help.golden index 81c9a405db0cf..63caab0c7e09f 100644 --- a/cli/testdata/coder_tokens_remove_--help.golden +++ b/cli/testdata/coder_tokens_remove_--help.golden @@ -1,15 +1,11 @@ coder v0.0.0-devel USAGE: - coder tokens remove [flags] + coder tokens remove Delete a token Aliases: delete, rm -OPTIONS: - -y, --yes bool - Bypass prompts. - ——— Run `coder --help` for a list of global options. diff --git a/cli/tokens.go b/cli/tokens.go index 88e3cd2585e2a..d132547576d32 100644 --- a/cli/tokens.go +++ b/cli/tokens.go @@ -11,7 +11,6 @@ import ( "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" - "github.com/coder/pretty" "github.com/coder/serpent" ) @@ -232,9 +231,6 @@ func (r *RootCmd) removeToken() *serpent.Command { serpent.RequireNArgs(1), r.InitClient(client), ), - Options: serpent.OptionSet{ - cliui.SkipPromptOption(), - }, Handler: func(inv *serpent.Invocation) error { token, err := client.APIKeyByName(inv.Context(), codersdk.Me, inv.Args[0]) if err != nil { @@ -246,33 +242,6 @@ func (r *RootCmd) removeToken() *serpent.Command { } } - var prompt string - if token.TokenName == "" { - prompt = fmt.Sprintf("Are you sure you want to delete the token with ID %s?\n ", - pretty.Sprint(cliui.DefaultStyles.Code, token.ID), - ) - } else { - prompt = fmt.Sprintf("Are you sure you want to delete the token with the name %s? (ID: %s)\n ", - pretty.Sprint(cliui.DefaultStyles.Code, token.TokenName), - pretty.Sprint(cliui.DefaultStyles.Code, token.ID), - ) - } - - if !token.LastUsed.IsZero() { - prompt = fmt.Sprintf("%sIt was last used on %s.", prompt, pretty.Sprint(cliui.DefaultStyles.Code, token.LastUsed.String())) - } else { - prompt = fmt.Sprintf("%sIt has never been used.", prompt) - } - - _, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: prompt, - IsConfirm: true, - Default: cliui.ConfirmYes, - }) - if err != nil { - return err - } - err = client.DeleteAPIKey(inv.Context(), codersdk.Me, token.ID) if err != nil { return xerrors.Errorf("delete api key: %w", err) diff --git a/cli/tokens_test.go b/cli/tokens_test.go index 01eb66ad54075..0c717bb890f9e 100644 --- a/cli/tokens_test.go +++ b/cli/tokens_test.go @@ -114,7 +114,7 @@ func TestTokens(t *testing.T) { require.Equal(t, id, tokens[0].ID) // Delete by name - inv, root = clitest.New(t, "tokens", "rm", "token-one", "--yes") + inv, root = clitest.New(t, "tokens", "rm", "token-one") clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) inv.Stdout = buf @@ -125,7 +125,7 @@ func TestTokens(t *testing.T) { require.Contains(t, res, "deleted") // Delete by ID - inv, root = clitest.New(t, "tokens", "rm", secondTokenID, "--yes") + inv, root = clitest.New(t, "tokens", "rm", secondTokenID) clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) inv.Stdout = buf @@ -147,7 +147,7 @@ func TestTokens(t *testing.T) { fourthToken := res // Delete by token - inv, root = clitest.New(t, "tokens", "rm", fourthToken, "--yes") + inv, root = clitest.New(t, "tokens", "rm", fourthToken) clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) inv.Stdout = buf diff --git a/docs/reference/cli/tokens_remove.md b/docs/reference/cli/tokens_remove.md index e127ae4dbc309..ae443f6ad083e 100644 --- a/docs/reference/cli/tokens_remove.md +++ b/docs/reference/cli/tokens_remove.md @@ -11,15 +11,5 @@ Aliases: ## Usage ```console -coder tokens remove [flags] +coder tokens remove ``` - -## Options - -### -y, --yes - -| | | -|------|-------------------| -| Type | bool | - -Bypass prompts.