package cli import ( "bytes" "encoding/json" "fmt" "strings" "github.com/spf13/cobra" "golang.org/x/xerrors" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) func features() *cobra.Command { cmd := &cobra.Command{ Short: "List features", Use: "features", Aliases: []string{"feature"}, } cmd.AddCommand( featuresList(), ) return cmd } func featuresList() *cobra.Command { var ( featureColumns = []string{"Name", "Entitlement", "Enabled", "Limit", "Actual"} 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 } entitlements, err := client.Entitlements(cmd.Context()) if err != nil { return err } out := "" switch outputFormat { case "table", "": out, err = displayFeatures(columns, entitlements.Features) if err != nil { return xerrors.Errorf("render table: %w", err) } case "json": buf := new(bytes.Buffer) enc := json.NewEncoder(buf) enc.SetIndent("", " ") err = enc.Encode(entitlements) if err != nil { return xerrors.Errorf("marshal features to JSON: %w", err) } out = buf.String() 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", featureColumns, fmt.Sprintf("Specify a column to filter in the table. Available columns are: %s", strings.Join(featureColumns, ", "))) cmd.Flags().StringVarP(&outputFormat, "output", "o", "table", "Output format. Available formats are: table, json.") return cmd } type featureRow struct { Name string `table:"name"` Entitlement string `table:"entitlement"` Enabled bool `table:"enabled"` Limit *int64 `table:"limit"` Actual *int64 `table:"actual"` } // displayFeatures will return a table displaying all features passed in. // filterColumns must be a subset of the feature fields and will determine which // columns to display func displayFeatures(filterColumns []string, features map[string]codersdk.Feature) (string, error) { rows := make([]featureRow, 0, len(features)) for name, feat := range features { rows = append(rows, featureRow{ Name: name, Entitlement: string(feat.Entitlement), Enabled: feat.Enabled, Limit: feat.Limit, Actual: feat.Actual, }) } return cliui.DisplayTable(rows, "name", filterColumns) }