diff --git a/cli/publickey.go b/cli/publickey.go index ad6c016b9f..0be912bcd9 100644 --- a/cli/publickey.go +++ b/cli/publickey.go @@ -11,7 +11,11 @@ import ( ) func publickey() *cobra.Command { - return &cobra.Command{ + var ( + reset bool + ) + + cmd := &cobra.Command{ Use: "publickey", Aliases: []string{"pubkey"}, Short: "Output your public key for Git operations", @@ -21,6 +25,25 @@ func publickey() *cobra.Command { return xerrors.Errorf("create codersdk client: %w", err) } + if reset { + // Confirm prompt if using --reset. We don't want to accidentally + // reset our public key. + _, err := cliui.Prompt(cmd, cliui.PromptOptions{ + Text: "Confirm regenerate a new sshkey for your workspaces? This will require updating the key " + + "on any services it is registered with. This action cannot be reverted.", + IsConfirm: true, + }) + if err != nil { + return err + } + + // Reset the public key, let the retrieve re-read it. + _, err = client.RegenerateGitSSHKey(cmd.Context(), codersdk.Me) + if err != nil { + return err + } + } + key, err := client.GitSSHKey(cmd.Context(), codersdk.Me) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) @@ -40,4 +63,8 @@ func publickey() *cobra.Command { return nil }, } + cmd.Flags().BoolVar(&reset, "reset", false, "Regenerate your public key. This will require updating the key on any services it's registered with.") + cliui.AllowSkipPrompt(cmd) + + return cmd } diff --git a/cli/userlist.go b/cli/userlist.go index 7a9b9cb790..58325702cd 100644 --- a/cli/userlist.go +++ b/cli/userlist.go @@ -33,3 +33,32 @@ func userList() *cobra.Command { "Specify a column to filter in the table.") return cmd } + +func userSingle() *cobra.Command { + var ( + columns []string + ) + cmd := &cobra.Command{ + Use: "show ", + Short: "Show a single user. Use 'me' to indicate the currently authenticated user.", + Example: "coder users show me", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := createClient(cmd) + if err != nil { + return err + } + + user, err := client.User(cmd.Context(), args[0]) + if err != nil { + return err + } + + _, err = fmt.Fprintln(cmd.OutOrStdout(), displayUsers(columns, user)) + return err + }, + } + cmd.Flags().StringArrayVarP(&columns, "column", "c", []string{"username", "email", "created_at"}, + "Specify a column to filter in the table.") + return cmd +} diff --git a/cli/userlist_test.go b/cli/userlist_test.go index 8529f6980f..9938e9a63e 100644 --- a/cli/userlist_test.go +++ b/cli/userlist_test.go @@ -1,8 +1,10 @@ package cli_test import ( + "context" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/coder/coder/cli/clitest" @@ -51,3 +53,26 @@ func TestUserList(t *testing.T) { require.Contains(t, err.Error(), "Try logging in using 'coder login '.") }) } + +func TestUserShow(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := coderdtest.New(t, nil) + admin := coderdtest.CreateFirstUser(t, client) + other := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID) + otherUser, err := other.User(ctx, codersdk.Me) + require.NoError(t, err, "fetch other user") + cmd, root := clitest.New(t, "users", "show", otherUser.Username) + clitest.SetupConfig(t, client, root) + doneChan := make(chan struct{}) + pty := ptytest.New(t) + cmd.SetIn(pty.Input()) + cmd.SetOut(pty.Output()) + go func() { + defer close(doneChan) + err := cmd.Execute() + assert.NoError(t, err) + }() + pty.ExpectMatch(otherUser.Email) + <-doneChan +} diff --git a/cli/users.go b/cli/users.go index 29b20b3d1d..3bbb3067fb 100644 --- a/cli/users.go +++ b/cli/users.go @@ -18,6 +18,7 @@ func users() *cobra.Command { cmd.AddCommand( userCreate(), userList(), + userSingle(), createUserStatusCommand(codersdk.UserStatusActive), createUserStatusCommand(codersdk.UserStatusSuspended), )