mirror of
https://github.com/coder/coder.git
synced 2026-06-04 13:38:21 +00:00
c750695d83
This changes makes it so that we output the empty string for Format when there is no data. It turns out there are many places in the code where we have such handling, but in a way that would break the JSON formatter (since we'd output nothing on stdout or text rather than `[]`/`null`).
198 lines
4.5 KiB
Go
198 lines
4.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
agpl "github.com/coder/coder/v2/cli"
|
|
"github.com/coder/coder/v2/cli/cliui"
|
|
"github.com/coder/coder/v2/codersdk"
|
|
"github.com/coder/pretty"
|
|
"github.com/coder/serpent"
|
|
)
|
|
|
|
func (r *RootCmd) provisionerKeys() *serpent.Command {
|
|
cmd := &serpent.Command{
|
|
Use: "keys",
|
|
Short: "Manage provisioner keys",
|
|
Handler: func(inv *serpent.Invocation) error {
|
|
return inv.Command.HelpHandler(inv)
|
|
},
|
|
Aliases: []string{"key"},
|
|
Children: []*serpent.Command{
|
|
r.provisionerKeysCreate(),
|
|
r.provisionerKeysList(),
|
|
r.provisionerKeysDelete(),
|
|
},
|
|
}
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (r *RootCmd) provisionerKeysCreate() *serpent.Command {
|
|
var (
|
|
orgContext = agpl.NewOrganizationContext()
|
|
rawTags []string
|
|
)
|
|
|
|
cmd := &serpent.Command{
|
|
Use: "create <name>",
|
|
Short: "Create a new provisioner key",
|
|
Middleware: serpent.Chain(
|
|
serpent.RequireNArgs(1),
|
|
),
|
|
Handler: func(inv *serpent.Invocation) error {
|
|
ctx := inv.Context()
|
|
client, err := r.InitClient(inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
org, err := orgContext.Selected(inv, client)
|
|
if err != nil {
|
|
return xerrors.Errorf("current organization: %w", err)
|
|
}
|
|
|
|
tags, err := agpl.ParseProvisionerTags(rawTags)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
res, err := client.CreateProvisionerKey(ctx, org.ID, codersdk.CreateProvisionerKeyRequest{
|
|
Name: inv.Args[0],
|
|
Tags: tags,
|
|
})
|
|
if err != nil {
|
|
return xerrors.Errorf("create provisioner key: %w", err)
|
|
}
|
|
|
|
_, _ = fmt.Fprintf(
|
|
inv.Stdout,
|
|
"Successfully created provisioner key %s! Save this authentication token, it will not be shown again.\n\n%s\n",
|
|
pretty.Sprint(cliui.DefaultStyles.Keyword, strings.ToLower(inv.Args[0])),
|
|
pretty.Sprint(cliui.DefaultStyles.Keyword, res.Key),
|
|
)
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Options = serpent.OptionSet{
|
|
{
|
|
Flag: "tag",
|
|
FlagShorthand: "t",
|
|
Env: "CODER_PROVISIONERD_TAGS",
|
|
Description: "Tags to filter provisioner jobs by.",
|
|
Value: serpent.StringArrayOf(&rawTags),
|
|
},
|
|
}
|
|
orgContext.AttachOptions(cmd)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (r *RootCmd) provisionerKeysList() *serpent.Command {
|
|
var (
|
|
orgContext = agpl.NewOrganizationContext()
|
|
formatter = cliui.NewOutputFormatter(
|
|
cliui.TableFormat([]codersdk.ProvisionerKey{}, []string{"created at", "name", "tags"}),
|
|
cliui.JSONFormat(),
|
|
)
|
|
)
|
|
|
|
cmd := &serpent.Command{
|
|
Use: "list",
|
|
Short: "List provisioner keys in an organization",
|
|
Aliases: []string{"ls"},
|
|
Middleware: serpent.Chain(
|
|
serpent.RequireNArgs(0),
|
|
),
|
|
Handler: func(inv *serpent.Invocation) error {
|
|
ctx := inv.Context()
|
|
client, err := r.InitClient(inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
org, err := orgContext.Selected(inv, client)
|
|
if err != nil {
|
|
return xerrors.Errorf("current organization: %w", err)
|
|
}
|
|
|
|
keys, err := client.ListProvisionerKeys(ctx, org.ID)
|
|
if err != nil {
|
|
return xerrors.Errorf("list provisioner keys: %w", err)
|
|
}
|
|
|
|
out, err := formatter.Format(inv.Context(), keys)
|
|
if err != nil {
|
|
return xerrors.Errorf("display provisioner keys: %w", err)
|
|
}
|
|
|
|
if out == "" {
|
|
cliui.Infof(inv.Stderr, "No provisioner keys found.")
|
|
return nil
|
|
}
|
|
|
|
_, _ = fmt.Fprintln(inv.Stdout, out)
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
orgContext.AttachOptions(cmd)
|
|
formatter.AttachOptions(&cmd.Options)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (r *RootCmd) provisionerKeysDelete() *serpent.Command {
|
|
orgContext := agpl.NewOrganizationContext()
|
|
|
|
cmd := &serpent.Command{
|
|
Use: "delete <name>",
|
|
Short: "Delete a provisioner key",
|
|
Middleware: serpent.Chain(
|
|
serpent.RequireNArgs(1),
|
|
),
|
|
Handler: func(inv *serpent.Invocation) error {
|
|
ctx := inv.Context()
|
|
client, err := r.InitClient(inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
org, err := orgContext.Selected(inv, client)
|
|
if err != nil {
|
|
return xerrors.Errorf("current organization: %w", err)
|
|
}
|
|
|
|
_, err = cliui.Prompt(inv, cliui.PromptOptions{
|
|
Text: fmt.Sprintf("Are you sure you want to delete provisioner key %s?", pretty.Sprint(cliui.DefaultStyles.Keyword, inv.Args[0])),
|
|
IsConfirm: true,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = client.DeleteProvisionerKey(ctx, org.ID, inv.Args[0])
|
|
if err != nil {
|
|
return xerrors.Errorf("delete provisioner key: %w", err)
|
|
}
|
|
|
|
_, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted provisioner key %s!\n", pretty.Sprint(cliui.DefaultStyles.Keyword, strings.ToLower(inv.Args[0])))
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Options = serpent.OptionSet{
|
|
cliui.SkipPromptOption(),
|
|
}
|
|
orgContext.AttachOptions(cmd)
|
|
|
|
return cmd
|
|
}
|