package cli import ( "context" "encoding/json" "fmt" "io" "time" "github.com/charmbracelet/lipgloss" "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" "golang.org/x/xerrors" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) func userList() *cobra.Command { var ( columns []string outputFormat string ) cmd := &cobra.Command{ Use: "list", Aliases: []string{"ls"}, RunE: func(cmd *cobra.Command, args []string) error { client, err := CreateClient(cmd) if err != nil { return err } users, err := client.Users(cmd.Context(), codersdk.UsersRequest{}) if err != nil { return err } out := "" switch outputFormat { case "table", "": out, err = cliui.DisplayTable(users, "Username", columns) if err != nil { return xerrors.Errorf("render table: %w", err) } case "json": outBytes, err := json.Marshal(users) if err != nil { return xerrors.Errorf("marshal users to JSON: %w", err) } out = string(outBytes) default: return xerrors.Errorf(`unknown output format %q, only "table" and "json" are supported`, outputFormat) } _, err = fmt.Fprintln(cmd.OutOrStdout(), out) return err }, } cmd.Flags().StringArrayVarP(&columns, "column", "c", []string{"username", "email", "created_at", "status"}, "Specify a column to filter in the table. Available columns are: id, username, email, created_at, status.") cmd.Flags().StringVarP(&outputFormat, "output", "o", "table", "Output format. Available formats are: table, json.") return cmd } func userSingle() *cobra.Command { var outputFormat string cmd := &cobra.Command{ Use: "show ", Short: "Show a single user. Use 'me' to indicate the currently authenticated user.", Example: formatExamples( example{ Command: "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 } out := "" switch outputFormat { case "table", "": out = displayUser(cmd.Context(), cmd.ErrOrStderr(), client, user) case "json": outBytes, err := json.Marshal(user) if err != nil { return xerrors.Errorf("marshal user to JSON: %w", err) } out = string(outBytes) default: return xerrors.Errorf(`unknown output format %q, only "table" and "json" are supported`, outputFormat) } _, err = fmt.Fprintln(cmd.OutOrStdout(), out) return err }, } cmd.Flags().StringVarP(&outputFormat, "output", "o", "table", "Output format. Available formats are: table, json.") return cmd } func displayUser(ctx context.Context, stderr io.Writer, client *codersdk.Client, user codersdk.User) string { tw := cliui.Table() addRow := func(name string, value interface{}) { key := "" if name != "" { key = name + ":" } tw.AppendRow(table.Row{ key, value, }) } // Add rows for each of the user's fields. addRow("ID", user.ID.String()) addRow("Username", user.Username) addRow("Email", user.Email) addRow("Status", user.Status) addRow("Created At", user.CreatedAt.Format(time.Stamp)) addRow("", "") firstRole := true for _, role := range user.Roles { if role.DisplayName == "" { // Skip roles with no display name. continue } key := "" if firstRole { key = "Roles" firstRole = false } addRow(key, role.DisplayName) } if firstRole { addRow("Roles", "(none)") } addRow("", "") firstOrg := true for _, orgID := range user.OrganizationIDs { org, err := client.Organization(ctx, orgID) if err != nil { warn := cliui.Styles.Warn.Copy().Align(lipgloss.Left) _, _ = fmt.Fprintf(stderr, warn.Render("Could not fetch organization %s: %+v"), orgID, err) continue } key := "" if firstOrg { key = "Organizations" firstOrg = false } addRow(key, org.Name) } if firstOrg { addRow("Organizations", "(none)") } return tw.Render() }