From 0dbcd12dc8527f7d1d476e2ad03e3d5cd868b8b9 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Mon, 6 Mar 2023 21:23:32 +0000 Subject: [PATCH 001/175] Build out basic command scaffold --- cli/clibase/clibase.go | 3 + cli/clibase/clibasetest/invokation.go | 27 +++++++ cli/clibase/cmd.go | 108 +++++++++++++++++++++++++- cli/clibase/command_test.go | 53 +++++++++++++ 4 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 cli/clibase/clibasetest/invokation.go create mode 100644 cli/clibase/command_test.go diff --git a/cli/clibase/clibase.go b/cli/clibase/clibase.go index 692ea5734cc97..cbca6b81433cc 100644 --- a/cli/clibase/clibase.go +++ b/cli/clibase/clibase.go @@ -5,6 +5,9 @@ // We will extend its usage to the rest of our application, completely replacing // cobra/viper. It's also a candidate to be broken out into its own open-source // library, so we avoid deep coupling with Coder concepts. +// +// The Command interface is loosely based on the chi middleware pattern and +// http.Handler/HandlerFunc. package clibase import ( diff --git a/cli/clibase/clibasetest/invokation.go b/cli/clibase/clibasetest/invokation.go new file mode 100644 index 0000000000000..688aea0578775 --- /dev/null +++ b/cli/clibase/clibasetest/invokation.go @@ -0,0 +1,27 @@ +package clibasetest + +import ( + "bytes" + + "github.com/coder/coder/cli/clibase" +) + +// IO is the standard input, output, and error for a command. +type IO struct { + Stdin *bytes.Buffer + Stdout *bytes.Buffer + Stderr *bytes.Buffer +} + +// FakeIO sets Stdin, Stdout, and Stderr to buffers. +func FakeIO(i *clibase.Invokation) *IO { + io := &IO{ + Stdin: bytes.NewBuffer(nil), + Stdout: bytes.NewBuffer(nil), + Stderr: bytes.NewBuffer(nil), + } + i.Stdout = io.Stdout + i.Stderr = io.Stderr + i.Stdin = io.Stdin + return io +} diff --git a/cli/clibase/cmd.go b/cli/clibase/cmd.go index d268e3b0bfca3..753c11a696e2d 100644 --- a/cli/clibase/cmd.go +++ b/cli/clibase/cmd.go @@ -1,6 +1,12 @@ package clibase -import "strings" +import ( + "context" + "fmt" + "io" + "runtime" + "strings" +) // Cmd describes an executable command. type Cmd struct { @@ -12,11 +18,14 @@ type Cmd struct { Use string // Short is a one-line description of the command. Short string + // Hidden determines whether the command should be hidden from help. + Hidden bool // Long is a detailed description of the command, // presented on its help page. It may contain examples. Long string - Options OptionSet + Options *OptionSet Annotations Annotations + Handler Handler } // Name returns the first word in the Use string. @@ -46,3 +55,98 @@ func (c *Cmd) FullUsage() string { uses = append(uses, c.Use) return strings.Join(uses, " ") } + +// Invokation represents an instance of a command being executed. +type Invokation struct { + parent *Invokation + + ctx context.Context + Command *Command + Args []string + Stdout io.Writer + Stderr io.Writer + Stdin io.Reader + + err error +} + +func (i *Invokation) Context() context.Context { + return i.ctx +} + +func (i *Invokation) Exit(err error) { + if i.parent != nil { + i.parent.Exit(err) + return + } + + i.err = err + // Goexit simulates an os.Exit, but can be captured in tests and + // middleware. + runtime.Goexit() +} + +func (i *Invokation) Run() error { + waitDone := make(chan struct{}) + go func() { + defer close(waitDone) + i.Command.Handler.ServeCommand(i) + }() + <-waitDone + return i.err +} + +// WithContext returns a copy of the Invokation with the given context. +func (i *Invokation) WithContext(ctx context.Context) *Invokation { + i2 := *i + i2.parent = i + i2.ctx = ctx + return &i2 +} + +// Middleware returns the next handler in the chain, +// or nil if there are no more. +type Middleware func(next Handler) Handler + +// Chain returns a Handler that first calls middleware in order. +func Chain(h Handler, ms ...Middleware) Handler { + return HandlerFunc(func(i *Invokation) { + if len(ms) == 0 { + h.ServeCommand(i) + return + } + Chain(ms[0](h), ms[1:]...).ServeCommand(i) + }) +} + +func RequireNArgs(want int) Middleware { + return func(next Handler) Handler { + return HandlerFunc(func(i *Invokation) { + if len(i.Args) != want { + i.Exit( + fmt.Errorf( + "wanted %v args but got %v", + want, + len(i.Args), + ), + ) + } + next.ServeCommand(i) + }) + } +} + +// HandlerFunc is to Handler what http.HandlerFunc is to http.Handler. +type HandlerFunc func(i *Invokation) + +func (h HandlerFunc) ServeCommand(i *Invokation) { + h(i) +} + +var _ Handler = HandlerFunc(nil) + +// Handler describes the executable portion of a command. It +// is loosely based on the http.Handler interface. +type Handler interface { + ServeCommand(i *Invokation) +} diff --git a/cli/clibase/command_test.go b/cli/clibase/command_test.go new file mode 100644 index 0000000000000..72c620762dafe --- /dev/null +++ b/cli/clibase/command_test.go @@ -0,0 +1,53 @@ +package clibase_test + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/cli/clibase" + "github.com/coder/coder/cli/clibase/clibasetest" +) + +func TestCommand_ToUpper(t *testing.T) { + t.Parallel() + + cmd := &clibase.Command{ + Use: "toupper [word]", + Short: "Converts a word to upper case", + Handler: clibase.Chain( + clibase.HandlerFunc(func(i *clibase.Invokation) { + _, _ = i.Stdout.Write( + []byte( + strings.ToUpper(i.Args[0]), + ), + ) + }), + clibase.RequireNArgs(1), + ), + } + + t.Run("OK", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"hello"}, + Command: cmd, + } + io := clibasetest.FakeIO(i) + i.Run() + require.Equal(t, "HELLO", io.Stdout.String()) + }) + + t.Run("BadArgs", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"hello", "world"}, + Command: cmd, + } + io := clibasetest.FakeIO(i) + err := i.Run() + require.Empty(t, io.Stdout.String()) + require.Error(t, err) + }) +} From 18d31bffdda82918b7a2a9628c04dd432ffed76a Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Mon, 6 Mar 2023 22:05:48 +0000 Subject: [PATCH 002/175] Fixup middleware --- cli/clibase/cmd.go | 38 ++++++++++++++++++++-------- cli/clibase/command_test.go | 49 +++++++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/cli/clibase/cmd.go b/cli/clibase/cmd.go index 753c11a696e2d..7553848ea18e1 100644 --- a/cli/clibase/cmd.go +++ b/cli/clibase/cmd.go @@ -25,7 +25,11 @@ type Cmd struct { Long string Options *OptionSet Annotations Annotations - Handler Handler + + // Middleware is called before the Handler. + // Use Chain() to combine multiple middlewares. + Middleware Middleware + Handler Handler } // Name returns the first word in the Use string. @@ -63,6 +67,8 @@ type Invokation struct { ctx context.Context Command *Command Args []string + // Environ is the environment variables is os.Environ() form. + Environ []string Stdout io.Writer Stderr io.Writer Stdin io.Reader @@ -82,7 +88,8 @@ func (i *Invokation) Exit(err error) { i.err = err // Goexit simulates an os.Exit, but can be captured in tests and - // middleware. + // middleware. Production callers may switch on err to determine the right + // exit code. Perhaps in the future we could add an ExitCoder interface. runtime.Goexit() } @@ -90,7 +97,7 @@ func (i *Invokation) Run() error { waitDone := make(chan struct{}) go func() { defer close(waitDone) - i.Command.Handler.ServeCommand(i) + i.Command.Middleware(i.Command.Handler).ServeCommand(i) }() <-waitDone return i.err @@ -108,17 +115,28 @@ func (i *Invokation) WithContext(ctx context.Context) *Invokation { // or nil if there are no more. type Middleware func(next Handler) Handler -// Chain returns a Handler that first calls middleware in order. -func Chain(h Handler, ms ...Middleware) Handler { - return HandlerFunc(func(i *Invokation) { - if len(ms) == 0 { - h.ServeCommand(i) - return +func chain(ms ...Middleware) Middleware { + return Middleware(func(next Handler) Handler { + if len(ms) > 0 { + return chain(ms[1:]...)(ms[0](next)) } - Chain(ms[0](h), ms[1:]...).ServeCommand(i) + return next }) } +// Chain returns a Handler that first calls middleware in order. +// +//nolint:revive +func Chain(ms ...Middleware) Middleware { + // We need to reverse the array to provide top-to-bottom execution + // order when defining a command. + reversed := make([]Middleware, len(ms)) + for i := range ms { + reversed[len(ms)-1-i] = ms[i] + } + return chain(reversed...) +} + func RequireNArgs(want int) Middleware { return func(next Handler) Handler { return HandlerFunc(func(i *Invokation) { diff --git a/cli/clibase/command_test.go b/cli/clibase/command_test.go index 72c620762dafe..3d466eb6226c5 100644 --- a/cli/clibase/command_test.go +++ b/cli/clibase/command_test.go @@ -16,16 +16,16 @@ func TestCommand_ToUpper(t *testing.T) { cmd := &clibase.Command{ Use: "toupper [word]", Short: "Converts a word to upper case", - Handler: clibase.Chain( - clibase.HandlerFunc(func(i *clibase.Invokation) { - _, _ = i.Stdout.Write( - []byte( - strings.ToUpper(i.Args[0]), - ), - ) - }), + Middleware: clibase.Chain( clibase.RequireNArgs(1), ), + Handler: clibase.HandlerFunc(func(i *clibase.Invokation) { + _, _ = i.Stdout.Write( + []byte( + strings.ToUpper(i.Args[0]), + ), + ) + }), } t.Run("OK", func(t *testing.T) { @@ -51,3 +51,36 @@ func TestCommand_ToUpper(t *testing.T) { require.Error(t, err) }) } + +func TestCommand_MiddlewareOrder(t *testing.T) { + t.Parallel() + + mw := func(letter string) clibase.Middleware { + return func(next clibase.Handler) clibase.Handler { + return clibase.HandlerFunc(func(i *clibase.Invokation) { + _, _ = i.Stdout.Write([]byte(letter)) + next.ServeCommand(i) + }) + } + } + + cmd := &clibase.Command{ + Use: "toupper [word]", + Short: "Converts a word to upper case", + Middleware: clibase.Chain( + mw("A"), + mw("B"), + mw("C"), + ), + Handler: clibase.HandlerFunc(func(i *clibase.Invokation) { + }), + } + + i := &clibase.Invokation{ + Args: []string{"hello", "world"}, + Command: cmd, + } + io := clibasetest.FakeIO(i) + require.NoError(t, i.Run()) + require.Equal(t, "ABC", io.Stdout.String()) +} From ec8e62619eccfade2ab56d7df6b94f9ce3c2d78d Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Mon, 6 Mar 2023 23:39:13 +0000 Subject: [PATCH 003/175] Support global flags --- cli/bigcli/env_test.go | 44 +++++++ cli/clibase/cmd.go | 165 +++++++++++++++++--------- cli/clibase/cmd_test.go | 167 ++++++++++++++++++++++++++ cli/clibase/command_test.go | 86 -------------- cli/clibase/env.go | 4 +- cli/clibase/env_test.go | 2 +- cli/clibase/option.go | 18 ++- cli/clibase/option_test.go | 4 +- cli/clitest/clitest.go | 3 +- cli/configssh.go | 2 +- cli/create.go | 2 +- cli/delete.go | 2 +- cli/list.go | 2 +- cli/logout.go | 2 +- cli/parameterslist.go | 2 +- cli/ping.go | 2 +- cli/portforward.go | 2 +- cli/publickey.go | 2 +- cli/rename.go | 2 +- cli/restart.go | 2 +- cli/root.go | 227 +++++++++++++++++------------------- cli/scaletest.go | 4 +- cli/schedule.go | 8 +- cli/server.go | 4 +- cli/show.go | 30 ++--- cli/speedtest.go | 2 +- cli/ssh.go | 2 +- cli/start.go | 2 +- cli/state.go | 4 +- cli/stop.go | 2 +- cli/templatecreate.go | 2 +- cli/templatedelete.go | 2 +- cli/templateedit.go | 2 +- cli/templatelist.go | 2 +- cli/templatepull.go | 2 +- cli/templatepush.go | 2 +- cli/templateversions.go | 2 +- cli/tokens.go | 6 +- cli/update.go | 2 +- cli/usercreate.go | 2 +- cli/userlist.go | 4 +- cli/userstatus.go | 2 +- 42 files changed, 504 insertions(+), 326 deletions(-) create mode 100644 cli/bigcli/env_test.go create mode 100644 cli/clibase/cmd_test.go delete mode 100644 cli/clibase/command_test.go diff --git a/cli/bigcli/env_test.go b/cli/bigcli/env_test.go new file mode 100644 index 0000000000000..b74870d7e21f3 --- /dev/null +++ b/cli/bigcli/env_test.go @@ -0,0 +1,44 @@ +package clibase_test + +import ( + "reflect" + "testing" + + "github.com/coder/coder/cli/clibase" +) + +func TestFilterNamePrefix(t *testing.T) { + t.Parallel() + type args struct { + environ []string + prefix string + } + tests := []struct { + name string + args args + want []clibase.EnvVar + }{ + {"empty", args{[]string{}, "SHIRE"}, nil}, + { + "ONE", + args{ + []string{ + "SHIRE_BRANDYBUCK=hmm", + }, + "SHIRE_", + }, + []clibase.EnvVar{ + {Name: "BRANDYBUCK", Value: "hmm"}, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := clibase.ParseEnviron(tt.args.environ, tt.args.prefix); !reflect.DeepEqual(got, tt.want) { + t.Errorf("EnvsWithPrefix() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cli/clibase/cmd.go b/cli/clibase/cmd.go index 7553848ea18e1..93730f5aadbd7 100644 --- a/cli/clibase/cmd.go +++ b/cli/clibase/cmd.go @@ -4,8 +4,10 @@ import ( "context" "fmt" "io" - "runtime" "strings" + + "github.com/spf13/pflag" + "golang.org/x/xerrors" ) // Cmd describes an executable command. @@ -28,8 +30,9 @@ type Cmd struct { // Middleware is called before the Handler. // Use Chain() to combine multiple middlewares. - Middleware Middleware - Handler Handler + Middleware MiddlewareFunc + Handler HandlerFunc + HelpHandler HandlerFunc } // Name returns the first word in the Use string. @@ -65,42 +68,102 @@ type Invokation struct { parent *Invokation ctx context.Context - Command *Command + Command *Cmd Args []string - // Environ is the environment variables is os.Environ() form. - Environ []string - Stdout io.Writer - Stderr io.Writer - Stdin io.Reader - - err error + // Env is a list of environment variables. Use EnvsWithPrefix to parse + // os.Environ. + Env []EnvVar + Stdout io.Writer + Stderr io.Writer + Stdin io.Reader } func (i *Invokation) Context() context.Context { return i.ctx } -func (i *Invokation) Exit(err error) { - if i.parent != nil { - i.parent.Exit(err) - return +// run recursively executes the command and its children. +// allArgs is wired through the stack so that global flags can be accepted +// anywhere in the command invokation. +func (i *Invokation) run(allArgs []string, flagSet *pflag.FlagSet) error { + err := i.Command.Options.SetDefaults() + if err != nil { + return xerrors.Errorf("setting defaults: %w", err) + } + + childrenMap := make(map[string]*Cmd) + for _, child := range i.Command.Children { + if _, ok := childrenMap[child.Name()]; ok { + return xerrors.Errorf("duplicate command name: %s", child.Name()) + } + childrenMap[child.Name()] = child } - i.err = err - // Goexit simulates an os.Exit, but can be captured in tests and - // middleware. Production callers may switch on err to determine the right - // exit code. Perhaps in the future we could add an ExitCoder interface. - runtime.Goexit() + if flagSet == nil { + flagSet = pflag.NewFlagSet(i.Command.Name(), pflag.ContinueOnError) + } + + additionalFlags := i.Command.Options.FlagSet() + flagSet.AddFlagSet(additionalFlags) + + // Run child command if found. + for argI, arg := range i.Args { + if child, ok := childrenMap[arg]; ok { + i.Args = i.Args[argI+1:] + child.Parent = i.Command + i.Command = child + err := i.run(allArgs, flagSet) + if err != nil { + return xerrors.Errorf( + "subcommand %s: %w", child.Name(), err, + ) + } + return nil + } + } + + err = i.Command.Options.ParseEnv(i.Env) + if err != nil { + return xerrors.Errorf("parsing env: %w", err) + } + + err = flagSet.Parse(allArgs) + if err != nil { + return xerrors.Errorf("parsing flags: %w", err) + } + + mw := i.Command.Middleware + if mw == nil { + mw = Chain() + } + + if i.Command.Handler == nil { + if i.Command.HelpHandler != nil { + return i.Command.HelpHandler(i) + } + return xerrors.Errorf("no handler or help for command %s", i.Command.FullName()) + } + + i.Args = stripFlags(i.Args) + return mw(i.Command.Handler)(i) +} + +func stripFlags(args []string) []string { + var stripped []string + for _, arg := range args { + if strings.HasPrefix(arg, "-") { + continue + } + stripped = append(stripped, arg) + } + return stripped } +// Run executes the command. +// +//nolint:revive func (i *Invokation) Run() error { - waitDone := make(chan struct{}) - go func() { - defer close(waitDone) - i.Command.Middleware(i.Command.Handler).ServeCommand(i) - }() - <-waitDone - return i.err + return i.run(i.Args, nil) } // WithContext returns a copy of the Invokation with the given context. @@ -111,12 +174,12 @@ func (i *Invokation) WithContext(ctx context.Context) *Invokation { return &i2 } -// Middleware returns the next handler in the chain, +// MiddlewareFunc returns the next handler in the chain, // or nil if there are no more. -type Middleware func(next Handler) Handler +type MiddlewareFunc func(next HandlerFunc) HandlerFunc -func chain(ms ...Middleware) Middleware { - return Middleware(func(next Handler) Handler { +func chain(ms ...MiddlewareFunc) MiddlewareFunc { + return MiddlewareFunc(func(next HandlerFunc) HandlerFunc { if len(ms) > 0 { return chain(ms[1:]...)(ms[0](next)) } @@ -127,44 +190,30 @@ func chain(ms ...Middleware) Middleware { // Chain returns a Handler that first calls middleware in order. // //nolint:revive -func Chain(ms ...Middleware) Middleware { +func Chain(ms ...MiddlewareFunc) MiddlewareFunc { // We need to reverse the array to provide top-to-bottom execution // order when defining a command. - reversed := make([]Middleware, len(ms)) + reversed := make([]MiddlewareFunc, len(ms)) for i := range ms { reversed[len(ms)-1-i] = ms[i] } return chain(reversed...) } -func RequireNArgs(want int) Middleware { - return func(next Handler) Handler { - return HandlerFunc(func(i *Invokation) { +func RequireNArgs(want int) MiddlewareFunc { + return func(next HandlerFunc) HandlerFunc { + return func(i *Invokation) error { if len(i.Args) != want { - i.Exit( - fmt.Errorf( - "wanted %v args but got %v", - want, - len(i.Args), - ), + return fmt.Errorf( + "wanted %v args but got %v", + want, + len(i.Args), ) } - next.ServeCommand(i) - }) + return next(i) + } } } -// HandlerFunc is to Handler what http.HandlerFunc is to http.Handler. -type HandlerFunc func(i *Invokation) - -func (h HandlerFunc) ServeCommand(i *Invokation) { - h(i) -} - -var _ Handler = HandlerFunc(nil) - -// Handler describes the executable portion of a command. It -// is loosely based on the http.Handler interface. -type Handler interface { - ServeCommand(i *Invokation) -} +// HandlerFunc handles an Invokation of a command. +type HandlerFunc func(i *Invokation) error diff --git a/cli/clibase/cmd_test.go b/cli/clibase/cmd_test.go new file mode 100644 index 0000000000000..e0ed7f5b41ea4 --- /dev/null +++ b/cli/clibase/cmd_test.go @@ -0,0 +1,167 @@ +package clibase_test + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/cli/clibase" + "github.com/coder/coder/cli/clibase/clibasetest" +) + +func TestCommand_ToUpper(t *testing.T) { + t.Parallel() + + cmd := func() *clibase.Cmd { + var ( + verbose clibase.Bool + lower clibase.Bool + ) + return &clibase.Cmd{ + Use: "root [subcommand]", + Options: &clibase.OptionSet{ + clibase.Option{ + Name: "verbose", + Flag: "verbose", + Value: &verbose, + }, + }, + Children: []*clibase.Cmd{ + { + Use: "toupper [word]", + Short: "Converts a word to upper case", + Middleware: clibase.Chain( + clibase.RequireNArgs(1), + ), + Options: &clibase.OptionSet{ + clibase.Option{ + Name: "lower", + Flag: "lower", + Value: &lower, + }, + }, + Handler: clibase.HandlerFunc(func(i *clibase.Invokation) error { + w := i.Args[0] + if lower { + w = strings.ToLower(w) + } else { + w = strings.ToUpper(w) + } + _, _ = i.Stdout.Write( + []byte( + w, + ), + ) + if verbose { + i.Stdout.Write([]byte("!!!")) + } + return nil + }), + }, + }, + } + } + + t.Run("OK", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"root", "toupper", "hello"}, + Command: cmd(), + } + io := clibasetest.FakeIO(i) + i.Run() + require.Equal(t, "HELLO", io.Stdout.String()) + }) + + t.Run("NoSubcommand", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"root", "na"}, + Command: cmd(), + } + io := clibasetest.FakeIO(i) + err := i.Run() + require.Empty(t, io.Stdout.String()) + require.Error(t, err) + }) + + t.Run("BadArgs", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"root", "toupper"}, + Command: cmd(), + } + io := clibasetest.FakeIO(i) + err := i.Run() + require.Empty(t, io.Stdout.String()) + require.Error(t, err) + }) + + t.Run("Verbose", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"root", "--verbose", "toupper", "hello"}, + Command: cmd(), + } + io := clibasetest.FakeIO(i) + require.NoError(t, i.Run()) + require.Equal(t, "HELLO!!!", io.Stdout.String()) + }) + + t.Run("VerboseAnywhere", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"root", "toupper", "--verbose", "hello"}, + Command: cmd(), + } + io := clibasetest.FakeIO(i) + require.NoError(t, i.Run()) + require.Equal(t, "HELLO!!!", io.Stdout.String()) + }) + + t.Run("LowerVerbose", func(t *testing.T) { + t.Parallel() + i := &clibase.Invokation{ + Args: []string{"root", "toupper", "--verbose", "hello", "--lower"}, + Command: cmd(), + } + io := clibasetest.FakeIO(i) + require.NoError(t, i.Run()) + require.Equal(t, "hello!!!", io.Stdout.String()) + }) +} + +func TestCommand_MiddlewareOrder(t *testing.T) { + t.Parallel() + + mw := func(letter string) clibase.MiddlewareFunc { + return func(next clibase.HandlerFunc) clibase.HandlerFunc { + return clibase.HandlerFunc(func(i *clibase.Invokation) error { + _, _ = i.Stdout.Write([]byte(letter)) + return next(i) + }) + } + } + + cmd := &clibase.Cmd{ + Use: "toupper [word]", + Short: "Converts a word to upper case", + Middleware: clibase.Chain( + mw("A"), + mw("B"), + mw("C"), + ), + Handler: clibase.HandlerFunc(func(i *clibase.Invokation) error { + return nil + }), + } + + i := &clibase.Invokation{ + Args: []string{"hello", "world"}, + Command: cmd, + } + io := clibasetest.FakeIO(i) + require.NoError(t, i.Run()) + require.Equal(t, "ABC", io.Stdout.String()) +} diff --git a/cli/clibase/command_test.go b/cli/clibase/command_test.go deleted file mode 100644 index 3d466eb6226c5..0000000000000 --- a/cli/clibase/command_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package clibase_test - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/coder/coder/cli/clibase" - "github.com/coder/coder/cli/clibase/clibasetest" -) - -func TestCommand_ToUpper(t *testing.T) { - t.Parallel() - - cmd := &clibase.Command{ - Use: "toupper [word]", - Short: "Converts a word to upper case", - Middleware: clibase.Chain( - clibase.RequireNArgs(1), - ), - Handler: clibase.HandlerFunc(func(i *clibase.Invokation) { - _, _ = i.Stdout.Write( - []byte( - strings.ToUpper(i.Args[0]), - ), - ) - }), - } - - t.Run("OK", func(t *testing.T) { - t.Parallel() - i := &clibase.Invokation{ - Args: []string{"hello"}, - Command: cmd, - } - io := clibasetest.FakeIO(i) - i.Run() - require.Equal(t, "HELLO", io.Stdout.String()) - }) - - t.Run("BadArgs", func(t *testing.T) { - t.Parallel() - i := &clibase.Invokation{ - Args: []string{"hello", "world"}, - Command: cmd, - } - io := clibasetest.FakeIO(i) - err := i.Run() - require.Empty(t, io.Stdout.String()) - require.Error(t, err) - }) -} - -func TestCommand_MiddlewareOrder(t *testing.T) { - t.Parallel() - - mw := func(letter string) clibase.Middleware { - return func(next clibase.Handler) clibase.Handler { - return clibase.HandlerFunc(func(i *clibase.Invokation) { - _, _ = i.Stdout.Write([]byte(letter)) - next.ServeCommand(i) - }) - } - } - - cmd := &clibase.Command{ - Use: "toupper [word]", - Short: "Converts a word to upper case", - Middleware: clibase.Chain( - mw("A"), - mw("B"), - mw("C"), - ), - Handler: clibase.HandlerFunc(func(i *clibase.Invokation) { - }), - } - - i := &clibase.Invokation{ - Args: []string{"hello", "world"}, - Command: cmd, - } - io := clibasetest.FakeIO(i) - require.NoError(t, i.Run()) - require.Equal(t, "ABC", io.Stdout.String()) -} diff --git a/cli/clibase/env.go b/cli/clibase/env.go index 0a5e19e0ff159..dc11c930c97e3 100644 --- a/cli/clibase/env.go +++ b/cli/clibase/env.go @@ -25,9 +25,9 @@ type EnvVar struct { Value string } -// EnvsWithPrefix returns all environment variables starting with +// ParseEnviron returns all environment variables starting with // prefix without said prefix. -func EnvsWithPrefix(environ []string, prefix string) []EnvVar { +func ParseEnviron(environ []string, prefix string) []EnvVar { var filtered []EnvVar for _, line := range environ { name := envName(line) diff --git a/cli/clibase/env_test.go b/cli/clibase/env_test.go index 55fc0c6efdc94..b74870d7e21f3 100644 --- a/cli/clibase/env_test.go +++ b/cli/clibase/env_test.go @@ -36,7 +36,7 @@ func TestFilterNamePrefix(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := clibase.EnvsWithPrefix(tt.args.environ, tt.args.prefix); !reflect.DeepEqual(got, tt.want) { + if got := clibase.ParseEnviron(tt.args.environ, tt.args.prefix); !reflect.DeepEqual(got, tt.want) { t.Errorf("EnvsWithPrefix() = %v, want %v", got, tt.want) } }) diff --git a/cli/clibase/option.go b/cli/clibase/option.go index 1c3c05fda2d44..5b03c910f800e 100644 --- a/cli/clibase/option.go +++ b/cli/clibase/option.go @@ -58,6 +58,10 @@ func (s *OptionSet) Add(opts ...Option) { // FlagSet returns a pflag.FlagSet for the OptionSet. func (s *OptionSet) FlagSet() *pflag.FlagSet { + if s == nil { + return &pflag.FlagSet{} + } + fs := pflag.NewFlagSet("", pflag.ContinueOnError) for _, opt := range *s { if opt.Flag == "" { @@ -90,14 +94,19 @@ func (s *OptionSet) FlagSet() *pflag.FlagSet { } // ParseEnv parses the given environment variables into the OptionSet. -func (s *OptionSet) ParseEnv(globalPrefix string, environ []string) error { +// Use EnvsWithPrefix to filter out prefixes. +func (s *OptionSet) ParseEnv(vs []EnvVar) error { + if s == nil { + return nil + } + var merr *multierror.Error // We parse environment variables first instead of using a nested loop to // avoid N*M complexity when there are a lot of options and environment // variables. envs := make(map[string]string) - for _, v := range EnvsWithPrefix(environ, globalPrefix) { + for _, v := range vs { envs[v.Name] = v.Value } @@ -124,7 +133,12 @@ func (s *OptionSet) ParseEnv(globalPrefix string, environ []string) error { // SetDefaults sets the default values for each Option. // It should be called before all parsing (e.g. ParseFlags, ParseEnv). func (s *OptionSet) SetDefaults() error { + if s == nil { + return nil + } + var merr *multierror.Error + for _, opt := range *s { if opt.Default == "" { continue diff --git a/cli/clibase/option_test.go b/cli/clibase/option_test.go index 00a133b712d28..c1faadc812c63 100644 --- a/cli/clibase/option_test.go +++ b/cli/clibase/option_test.go @@ -87,7 +87,9 @@ func TestOptionSet_ParseEnv(t *testing.T) { }, } - err := os.ParseEnv("CODER_", []string{"CODER_WORKSPACE_NAME=foo"}) + err := os.ParseEnv([]clibase.EnvVar{ + {Name: "WORKSPACE_NAME", Value: "foo"}, + }) require.NoError(t, err) require.EqualValues(t, "foo", workspaceName) }) diff --git a/cli/clitest/clitest.go b/cli/clitest/clitest.go index a0e235df4fd4b..d866ab54234e0 100644 --- a/cli/clitest/clitest.go +++ b/cli/clitest/clitest.go @@ -18,6 +18,7 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/cli" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/config" "github.com/coder/coder/codersdk" "github.com/coder/coder/provisioner/echo" @@ -26,7 +27,7 @@ import ( // New creates a CLI instance with a configuration pointed to a // temporary testing directory. -func New(t *testing.T, args ...string) (*cobra.Command, config.Root) { +func New(t *testing.T, args ...string) (*clibase.Command, config.Root) { return NewWithSubcommands(t, cli.AGPL(), args...) } diff --git a/cli/configssh.go b/cli/configssh.go index 090489c2ba611..85efed8d5666c 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -156,7 +156,7 @@ func configSSH() *cobra.Command { ), Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/create.go b/cli/create.go index 72f84d123a3a4..5c95697db9cde 100644 --- a/cli/create.go +++ b/cli/create.go @@ -30,7 +30,7 @@ func create() *cobra.Command { Use: "create [name]", Short: "Create a workspace", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/delete.go b/cli/delete.go index 4c655339d8a8f..384d16a273322 100644 --- a/cli/delete.go +++ b/cli/delete.go @@ -29,7 +29,7 @@ func deleteWorkspace() *cobra.Command { return err } - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/list.go b/cli/list.go index 33493cf807080..a69945084f4db 100644 --- a/cli/list.go +++ b/cli/list.go @@ -82,7 +82,7 @@ func list() *cobra.Command { Aliases: []string{"ls"}, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/logout.go b/cli/logout.go index d40a9ef45940c..689bd4f949857 100644 --- a/cli/logout.go +++ b/cli/logout.go @@ -16,7 +16,7 @@ func logout() *cobra.Command { Use: "logout", Short: "Unauthenticate your local session", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/parameterslist.go b/cli/parameterslist.go index 1249f2a642be7..3539e19696bd2 100644 --- a/cli/parameterslist.go +++ b/cli/parameterslist.go @@ -24,7 +24,7 @@ func parameterList() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { scope, name := args[0], args[1] - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/ping.go b/cli/ping.go index 09cdca42747dc..7c596064fcea8 100644 --- a/cli/ping.go +++ b/cli/ping.go @@ -31,7 +31,7 @@ func ping() *cobra.Command { ctx, cancel := context.WithCancel(cmd.Context()) defer cancel() - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/portforward.go b/cli/portforward.go index b3728212a904a..1b34dd9062216 100644 --- a/cli/portforward.go +++ b/cli/portforward.go @@ -65,7 +65,7 @@ func portForward() *cobra.Command { return xerrors.New("no port-forwards requested") } - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/publickey.go b/cli/publickey.go index 3872baf594946..0064bef401cc7 100644 --- a/cli/publickey.go +++ b/cli/publickey.go @@ -18,7 +18,7 @@ func publickey() *cobra.Command { Aliases: []string{"pubkey"}, Short: "Output your Coder public key used for Git operations", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) } diff --git a/cli/rename.go b/cli/rename.go index ac364b80ea93b..fb6383d1c5cd8 100644 --- a/cli/rename.go +++ b/cli/rename.go @@ -17,7 +17,7 @@ func rename() *cobra.Command { Short: "Rename a workspace", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/restart.go b/cli/restart.go index 687297d371f5f..693e9bfd5cfd2 100644 --- a/cli/restart.go +++ b/cli/restart.go @@ -28,7 +28,7 @@ func restart() *cobra.Command { return err } - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/root.go b/cli/root.go index f3db7af279f62..e5d3c6411b77c 100644 --- a/cli/root.go +++ b/cli/root.go @@ -26,6 +26,7 @@ import ( "github.com/spf13/cobra" "github.com/coder/coder/buildinfo" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/cli/config" @@ -71,43 +72,15 @@ func init() { cobra.AddTemplateFuncs(templateFunctions) } -func Core() []*cobra.Command { +func Core() []*clibase.Command { + r := &rootCmd{} // Please re-sort this list alphabetically if you change it! - return []*cobra.Command{ - configSSH(), - create(), - deleteWorkspace(), - dotfiles(), - gitssh(), - list(), - login(), - logout(), - parameters(), - ping(), - portForward(), - publickey(), - rename(), - resetPassword(), - restart(), - scaletest(), - schedules(), - show(), - speedtest(), - ssh(), - start(), - state(), - stop(), - templates(), - tokens(), - update(), - users(), - versionCmd(), - vscodeSSH(), - workspaceAgent(), - } -} - -func AGPL() []*cobra.Command { + return []*clibase.Command{ + show(r), + } +} + +func AGPL() []*clibase.Command { all := append(Core(), Server(func(_ context.Context, o *coderd.Options) (*coderd.API, io.Closer, error) { api := coderd.New(o) return api, api, nil @@ -257,86 +230,104 @@ func isTest() bool { return flag.Lookup("test.v") != nil } -// CreateClient returns a new client from the command context. +type rootCmd struct { + clientURL *url.URL + token string + globalConfig string + header []string + + noVersionCheck bool + noFeatureWarning bool +} + +// useClient returns a new client from the command context. // It reads from global configuration files if flags are not set. -func CreateClient(cmd *cobra.Command) (*codersdk.Client, error) { - root := createConfig(cmd) - rawURL, err := cmd.Flags().GetString(varURL) - if err != nil || rawURL == "" { - rawURL, err = root.URL().Read() - if err != nil { - // If the configuration files are absent, the user is logged out - if os.IsNotExist(err) { - return nil, errUnauthenticated - } - return nil, err - } - } - serverURL, err := url.Parse(strings.TrimSpace(rawURL)) - if err != nil { - return nil, err - } - token, err := cmd.Flags().GetString(varToken) - if err != nil || token == "" { - token, err = root.Session().Read() - if err != nil { - // If the configuration files are absent, the user is logged out - if os.IsNotExist(err) { - return nil, errUnauthenticated - } - return nil, err - } - } - client, err := createUnauthenticatedClient(cmd, serverURL) - if err != nil { - return nil, err - } - client.SetSessionToken(token) +func (r *rootCmd) useClient(c *codersdk.Client) clibase.MiddlewareFunc { + return func(next clibase.HandlerFunc) clibase.HandlerFunc { + return clibase.HandlerFunc( + func(i *clibase.Invokation) error { + root := r.createConfig() + clientURL := r.clientURL + var err error + if clientURL == nil { + rawURL, err := root.URL().Read() + // If the configuration files are absent, the user is logged out + if os.IsNotExist(err) { + return (errUnauthenticated) + } + if err != nil { + return err + } + + clientURL, err = url.Parse(strings.TrimSpace(rawURL)) + if err != nil { + return err + } + } - // We send these requests in parallel to minimize latency. - var ( - versionErr = make(chan error) - warningErr = make(chan error) - ) - go func() { - versionErr <- checkVersions(cmd, client) - close(versionErr) - }() + token := r.token + if token == "" { + token, err = root.Session().Read() + // If the configuration files are absent, the user is logged out + if os.IsNotExist(err) { + return (errUnauthenticated) + } + if err != nil { + return err + } + } - go func() { - warningErr <- checkWarnings(cmd, client) - close(warningErr) - }() + client, err := r.createUnauthenticatedClient(clientURL) + if err != nil { + return err + } - if err = <-versionErr; err != nil { - // Just log the error here. We never want to fail a command - // due to a pre-run. - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), - cliui.Styles.Warn.Render("check versions error: %s"), err) - _, _ = fmt.Fprintln(cmd.ErrOrStderr()) - } + client.SetSessionToken(token) + + // We send these requests in parallel to minimize latency. + var ( + versionErr = make(chan error) + warningErr = make(chan error) + ) + go func() { + versionErr <- r.checkVersions(i, client) + close(versionErr) + }() + + go func() { + warningErr <- r.checkWarnings(i, client) + close(warningErr) + }() + + if err = <-versionErr; err != nil { + // Just log the error here. We never want to fail a command + // due to a pre-run. + _, _ = fmt.Fprintf(i.Stderr, + cliui.Styles.Warn.Render("check versions error: %s"), err) + _, _ = fmt.Fprintln(i.Stderr) + } - if err = <-warningErr; err != nil { - // Same as above - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), - cliui.Styles.Warn.Render("check entitlement warnings error: %s"), err) - _, _ = fmt.Fprintln(cmd.ErrOrStderr()) - } + if err = <-warningErr; err != nil { + // Same as above + _, _ = fmt.Fprintf(i.Stderr, + cliui.Styles.Warn.Render("check entitlement warnings error: %s"), err) + _, _ = fmt.Fprintln(i.Stderr) + } - return client, nil + *c = *client + return nil + }, + ) + } } -func createUnauthenticatedClient(cmd *cobra.Command, serverURL *url.URL) (*codersdk.Client, error) { +func (r *rootCmd) createUnauthenticatedClient(serverURL *url.URL) (*codersdk.Client, error) { client := codersdk.New(serverURL) - headers, err := cmd.Flags().GetStringArray(varHeader) - if err != nil { - return nil, err - } transport := &headerTransport{ transport: http.DefaultTransport, headers: map[string]string{}, } - for _, header := range headers { + for _, header := range r.header { parts := strings.SplitN(header, "=", 2) if len(parts) < 2 { return nil, xerrors.Errorf("split header %q had less than two parts", header) @@ -381,7 +372,7 @@ func CurrentOrganization(cmd *cobra.Command, client *codersdk.Client) (codersdk. // namedWorkspace fetches and returns a workspace by an identifier, which may be either // a bare name (for a workspace owned by the current user) or a "user/workspace" combination, // where user is either a username or UUID. -func namedWorkspace(cmd *cobra.Command, client *codersdk.Client, identifier string) (codersdk.Workspace, error) { +func namedWorkspace(ctx context.Context, client *codersdk.Client, identifier string) (codersdk.Workspace, error) { parts := strings.Split(identifier, "/") var owner, name string @@ -396,16 +387,12 @@ func namedWorkspace(cmd *cobra.Command, client *codersdk.Client, identifier stri return codersdk.Workspace{}, xerrors.Errorf("invalid workspace name: %q", identifier) } - return client.WorkspaceByOwnerAndName(cmd.Context(), owner, name, codersdk.WorkspaceOptions{}) + return client.WorkspaceByOwnerAndName(ctx, owner, name, codersdk.WorkspaceOptions{}) } // createConfig consumes the global configuration flag to produce a config root. -func createConfig(cmd *cobra.Command) config.Root { - globalRoot, err := cmd.Flags().GetString(config.FlagName) - if err != nil { - panic(err) - } - return config.Root(globalRoot) +func (r *rootCmd) createConfig() config.Root { + return config.Root(r.globalConfig) } // isTTY returns whether the passed reader is a TTY or not. @@ -598,12 +585,12 @@ func FormatCobraError(err error, cmd *cobra.Command) string { return cliui.Styles.Error.Render(output.String()) } -func checkVersions(cmd *cobra.Command, client *codersdk.Client) error { - if cliflag.IsSetBool(cmd, varNoVersionCheck) { +func (r *rootCmd) checkVersions(i *clibase.Invokation, client *codersdk.Client) error { + if r.noVersionCheck { return nil } - ctx, cancel := context.WithTimeout(cmd.Context(), 10*time.Second) + ctx, cancel := context.WithTimeout(i.Context(), 10*time.Second) defer cancel() clientVersion := buildinfo.Version() @@ -629,25 +616,25 @@ func checkVersions(cmd *cobra.Command, client *codersdk.Client) error { if !buildinfo.VersionsMatch(clientVersion, info.Version) { warn := cliui.Styles.Warn.Copy().Align(lipgloss.Left) - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), warn.Render(fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) - _, _ = fmt.Fprintln(cmd.ErrOrStderr()) + _, _ = fmt.Fprintf(i.Stderr, warn.Render(fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) + _, _ = fmt.Fprintln(i.Stderr) } return nil } -func checkWarnings(cmd *cobra.Command, client *codersdk.Client) error { - if cliflag.IsSetBool(cmd, varNoFeatureWarning) { +func (r *rootCmd) checkWarnings(i *clibase.Invokation, client *codersdk.Client) error { + if r.noFeatureWarning { return nil } - ctx, cancel := context.WithTimeout(cmd.Context(), 10*time.Second) + ctx, cancel := context.WithTimeout(i.Context(), 10*time.Second) defer cancel() entitlements, err := client.Entitlements(ctx) if err == nil { for _, w := range entitlements.Warnings { - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Warn.Render(w)) + _, _ = fmt.Fprintln(i.Stderr, cliui.Styles.Warn.Render(w)) } } return nil diff --git a/cli/scaletest.go b/cli/scaletest.go index b367b580bba60..4e05813ce4698 100644 --- a/cli/scaletest.go +++ b/cli/scaletest.go @@ -317,7 +317,7 @@ func scaletestCleanup() *cobra.Command { Long: "Cleanup scaletest workspaces, then cleanup scaletest users. The strategy flags will apply to each stage of the cleanup process.", RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } @@ -502,7 +502,7 @@ func scaletestCreateWorkspaces() *cobra.Command { It is recommended that all rate limits are disabled on the server before running this scaletest. This test generates many login events which will be rate limited against the (most likely single) IP.`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/schedule.go b/cli/schedule.go index ff81b8e81dc50..9a663d134c6a3 100644 --- a/cli/schedule.go +++ b/cli/schedule.go @@ -80,7 +80,7 @@ func scheduleShow() *cobra.Command { Long: scheduleShowDescriptionLong, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } @@ -109,7 +109,7 @@ func scheduleStart() *cobra.Command { Long: scheduleStartDescriptionLong, Args: cobra.RangeArgs(2, 4), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } @@ -159,7 +159,7 @@ func scheduleStop() *cobra.Command { Short: "Edit workspace stop schedule", Long: scheduleStopDescriptionLong, RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } @@ -210,7 +210,7 @@ func scheduleOverride() *cobra.Command { return err } - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create client: %w", err) } diff --git a/cli/server.go b/cli/server.go index c598112d9d63a..d42e6c97a30cb 100644 --- a/cli/server.go +++ b/cli/server.go @@ -94,7 +94,7 @@ func ReadGitAuthProvidersFromEnv(environ []string) ([]codersdk.GitAuthConfig, er sort.Strings(environ) var providers []codersdk.GitAuthConfig - for _, v := range clibase.EnvsWithPrefix(environ, envPrefix+"GITAUTH_") { + for _, v := range clibase.ParseEnviron(environ, envPrefix+"GITAUTH_") { tokens := strings.SplitN(v.Name, "_", 2) if len(tokens) != 2 { return nil, xerrors.Errorf("invalid env var: %s", v.Name) @@ -154,7 +154,7 @@ func ReadGitAuthProvidersFromEnv(environ []string) ([]codersdk.GitAuthConfig, er } // nolint:gocyclo -func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *cobra.Command { +func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *clibase.Command { root := &cobra.Command{ Use: "server", Short: "Start a Coder server", diff --git a/cli/show.go b/cli/show.go index 9ed91d3e511a9..c000132ebf442 100644 --- a/cli/show.go +++ b/cli/show.go @@ -1,32 +1,32 @@ package cli import ( - "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" + "github.com/coder/coder/codersdk" ) -func show() *cobra.Command { - return &cobra.Command{ - Annotations: workspaceCommand, - Use: "show ", - Short: "Display details of a workspace's resources and agents", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) - if err != nil { - return err - } - buildInfo, err := client.BuildInfo(cmd.Context()) +func show(root *rootCmd) *clibase.Command { + var client *codersdk.Client + return &clibase.Command{ + Use: "show ", + Short: "Display details of a workspace's resources and agents", + Middleware: clibase.Chain( + clibase.RequireNArgs(1), + root.useClient(client), + ), + Handler: func(i *clibase.Invokation) error { + buildInfo, err := client.BuildInfo(i.Context()) if err != nil { return xerrors.Errorf("get server version: %w", err) } - workspace, err := namedWorkspace(cmd, client, args[0]) + workspace, err := namedWorkspace(i.Context(), client, i.Args[0]) if err != nil { return xerrors.Errorf("get workspace: %w", err) } - return cliui.WorkspaceResources(cmd.OutOrStdout(), workspace.LatestBuild.Resources, cliui.WorkspaceResourcesOptions{ + return cliui.WorkspaceResources(i.Stdout, workspace.LatestBuild.Resources, cliui.WorkspaceResourcesOptions{ WorkspaceName: workspace.Name, ServerVersion: buildInfo.Version, }) diff --git a/cli/speedtest.go b/cli/speedtest.go index 2fc62227fdd58..a9d9757fe9f6d 100644 --- a/cli/speedtest.go +++ b/cli/speedtest.go @@ -32,7 +32,7 @@ func speedtest() *cobra.Command { ctx, cancel := context.WithCancel(cmd.Context()) defer cancel() - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) } diff --git a/cli/ssh.go b/cli/ssh.go index 5adeba63bbae6..0d7868ed1b707 100644 --- a/cli/ssh.go +++ b/cli/ssh.go @@ -57,7 +57,7 @@ func ssh() *cobra.Command { ctx, cancel := context.WithCancel(cmd.Context()) defer cancel() - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/start.go b/cli/start.go index 7bf4782e14bad..da44c359914c7 100644 --- a/cli/start.go +++ b/cli/start.go @@ -17,7 +17,7 @@ func start() *cobra.Command { Short: "Start a workspace", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/state.go b/cli/state.go index cbb2074dacf7b..bf4cbd7a064c5 100644 --- a/cli/state.go +++ b/cli/state.go @@ -31,7 +31,7 @@ func statePull() *cobra.Command { Short: "Pull a Terraform state file from a workspace.", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } @@ -73,7 +73,7 @@ func statePush() *cobra.Command { Args: cobra.ExactArgs(2), Short: "Push a Terraform state file to a workspace.", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/stop.go b/cli/stop.go index 9bb355ef0bd5a..91afd21bf6dde 100644 --- a/cli/stop.go +++ b/cli/stop.go @@ -25,7 +25,7 @@ func stop() *cobra.Command { return err } - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 4a139a72dd1b1..b38f0190f8ceb 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -36,7 +36,7 @@ func templateCreate() *cobra.Command { Short: "Create a template from the current directory or as specified by flag", Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/templatedelete.go b/cli/templatedelete.go index 230bb4bc2662d..4cffe60ac9711 100644 --- a/cli/templatedelete.go +++ b/cli/templatedelete.go @@ -23,7 +23,7 @@ func templateDelete() *cobra.Command { templates = []codersdk.Template{} ) - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/templateedit.go b/cli/templateedit.go index 1e487fa8000c2..bddf5780a8dab 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -28,7 +28,7 @@ func templateEdit() *cobra.Command { Args: cobra.ExactArgs(1), Short: "Edit the metadata of a template by name.", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create client: %w", err) } diff --git a/cli/templatelist.go b/cli/templatelist.go index 874f74e876c63..a8e7d5d7d2e1c 100644 --- a/cli/templatelist.go +++ b/cli/templatelist.go @@ -20,7 +20,7 @@ func templateList() *cobra.Command { Short: "List all the templates available for the organization", Aliases: []string{"ls"}, RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/templatepull.go b/cli/templatepull.go index efcaa559e9595..4b10924a93bcd 100644 --- a/cli/templatepull.go +++ b/cli/templatepull.go @@ -31,7 +31,7 @@ func templatePull() *cobra.Command { dest = args[1] } - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create client: %w", err) } diff --git a/cli/templatepush.go b/cli/templatepush.go index 273ee9788d752..439f3eb1d5f1e 100644 --- a/cli/templatepush.go +++ b/cli/templatepush.go @@ -103,7 +103,7 @@ func templatePush() *cobra.Command { Args: cobra.MaximumNArgs(1), Short: "Push a new template version from the current directory or as specified by flag", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/templateversions.go b/cli/templateversions.go index 91f8408e7a0a4..11d9018d59b95 100644 --- a/cli/templateversions.go +++ b/cli/templateversions.go @@ -46,7 +46,7 @@ func templateVersionsList() *cobra.Command { Args: cobra.ExactArgs(1), Short: "List all the versions of the specified template", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create client: %w", err) } diff --git a/cli/tokens.go b/cli/tokens.go index 3d51e0f1ff59d..d42cd6b2d6b49 100644 --- a/cli/tokens.go +++ b/cli/tokens.go @@ -57,7 +57,7 @@ func createToken() *cobra.Command { Use: "create", Short: "Create a token", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) } @@ -136,7 +136,7 @@ func listTokens() *cobra.Command { Aliases: []string{"ls"}, Short: "List tokens", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) } @@ -184,7 +184,7 @@ func removeToken() *cobra.Command { Short: "Delete a token", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) } diff --git a/cli/update.go b/cli/update.go index 4e25893119374..9f9546f1e46da 100644 --- a/cli/update.go +++ b/cli/update.go @@ -24,7 +24,7 @@ func update() *cobra.Command { Long: "Will update and start a given workspace if it is out of date. Use --always-prompt to change " + "the parameter values of the workspace.", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/usercreate.go b/cli/usercreate.go index 203686d6ff720..2b94ce0d93cdb 100644 --- a/cli/usercreate.go +++ b/cli/usercreate.go @@ -21,7 +21,7 @@ func userCreate() *cobra.Command { cmd := &cobra.Command{ Use: "create", RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/userlist.go b/cli/userlist.go index 52d07f4a4f127..00a20220cee6f 100644 --- a/cli/userlist.go +++ b/cli/userlist.go @@ -23,7 +23,7 @@ func userList() *cobra.Command { Use: "list", Aliases: []string{"ls"}, RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } @@ -62,7 +62,7 @@ func userSingle() *cobra.Command { ), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } diff --git a/cli/userstatus.go b/cli/userstatus.go index 96c6b7523ae3c..3bedda3fa7487 100644 --- a/cli/userstatus.go +++ b/cli/userstatus.go @@ -43,7 +43,7 @@ func createUserStatusCommand(sdkStatus codersdk.UserStatus) *cobra.Command { }, ), RunE: func(cmd *cobra.Command, args []string) error { - client, err := CreateClient(cmd) + client, err := useClient(cmd) if err != nil { return err } From e54d393bece64aba99e7b239042c95347c336ade Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Tue, 7 Mar 2023 00:31:18 +0000 Subject: [PATCH 004/175] Make progress... --- cli/clibase/cmd.go | 23 ++-- cli/clibase/cmd_test.go | 2 +- cli/clibase/env.go | 12 ++- cli/gitaskpass.go | 16 +-- cli/root.go | 225 ++++++++++++++++++++++++---------------- cli/show.go | 2 +- cmd/coder/main.go | 16 ++- go.sum | 8 +- 8 files changed, 189 insertions(+), 115 deletions(-) diff --git a/cli/clibase/cmd.go b/cli/clibase/cmd.go index 93730f5aadbd7..806e3cb49f6c5 100644 --- a/cli/clibase/cmd.go +++ b/cli/clibase/cmd.go @@ -25,7 +25,7 @@ type Cmd struct { // Long is a detailed description of the command, // presented on its help page. It may contain examples. Long string - Options *OptionSet + Options OptionSet Annotations Annotations // Middleware is called before the Handler. @@ -35,6 +35,14 @@ type Cmd struct { HelpHandler HandlerFunc } +// Walk calls fn for the command and all its children. +func (c *Command) Walk(fn func(*Command)) { + fn(c) + for _, child := range c.Children { + child.Walk(fn) + } +} + // Name returns the first word in the Use string. func (c *Cmd) Name() string { return strings.Split(c.Use, " ")[0] @@ -70,12 +78,12 @@ type Invokation struct { ctx context.Context Command *Cmd Args []string - // Env is a list of environment variables. Use EnvsWithPrefix to parse + // Environ is a list of environment variables. Use EnvsWithPrefix to parse // os.Environ. - Env []EnvVar - Stdout io.Writer - Stderr io.Writer - Stdin io.Reader + Environ Environ + Stdout io.Writer + Stderr io.Writer + Stdin io.Reader } func (i *Invokation) Context() context.Context { @@ -122,7 +130,7 @@ func (i *Invokation) run(allArgs []string, flagSet *pflag.FlagSet) error { } } - err = i.Command.Options.ParseEnv(i.Env) + err = i.Command.Options.ParseEnv(i.Environ) if err != nil { return xerrors.Errorf("parsing env: %w", err) } @@ -160,6 +168,7 @@ func stripFlags(args []string) []string { } // Run executes the command. +// If two command share a flag name, the deepest command wins. // //nolint:revive func (i *Invokation) Run() error { diff --git a/cli/clibase/cmd_test.go b/cli/clibase/cmd_test.go index e0ed7f5b41ea4..1bb88b0d006bd 100644 --- a/cli/clibase/cmd_test.go +++ b/cli/clibase/cmd_test.go @@ -20,7 +20,7 @@ func TestCommand_ToUpper(t *testing.T) { ) return &clibase.Cmd{ Use: "root [subcommand]", - Options: &clibase.OptionSet{ + Options: clibase.OptionSet{ clibase.Option{ Name: "verbose", Flag: "verbose", diff --git a/cli/clibase/env.go b/cli/clibase/env.go index dc11c930c97e3..43019c7a1661d 100644 --- a/cli/clibase/env.go +++ b/cli/clibase/env.go @@ -25,9 +25,19 @@ type EnvVar struct { Value string } +type Environ []EnvVar + +func (e Environ) ToOS() []string { + var env []string + for _, v := range e { + env = append(env, v.Name+"="+v.Value) + } + return env +} + // ParseEnviron returns all environment variables starting with // prefix without said prefix. -func ParseEnviron(environ []string, prefix string) []EnvVar { +func ParseEnviron(environ []string, prefix string) Environ { var filtered []EnvVar for _, line := range environ { name := envName(line) diff --git a/cli/gitaskpass.go b/cli/gitaskpass.go index 4c78c47728db3..a4df87f4f45b0 100644 --- a/cli/gitaskpass.go +++ b/cli/gitaskpass.go @@ -7,9 +7,9 @@ import ( "os/signal" "time" - "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/gitauth" "github.com/coder/coder/codersdk" @@ -18,18 +18,20 @@ import ( // gitAskpass is used by the Coder agent to automatically authenticate // with Git providers based on a hostname. -func gitAskpass() *cobra.Command { - return &cobra.Command{ +func gitAskpass() *clibase.Command { + return &clibase.Command{ Use: "gitaskpass", Hidden: true, - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() + Middleware: clibase.Chain( + clibase.RequireNArgs(1), + ), + Handler: func(i *clibase.Invokation) error { + ctx := i.Context() ctx, stop := signal.NotifyContext(ctx, InterruptSignals...) defer stop() - user, host, err := gitauth.ParseAskpass(args[0]) + user, host, err := gitauth.ParseAskpass(i.Args[0]) if err != nil { return xerrors.Errorf("parse host: %w", err) } diff --git a/cli/root.go b/cli/root.go index e5d3c6411b77c..0e5aebebb4034 100644 --- a/cli/root.go +++ b/cli/root.go @@ -73,7 +73,7 @@ func init() { } func Core() []*clibase.Command { - r := &rootCmd{} + r := &RootCmd{} // Please re-sort this list alphabetically if you change it! return []*clibase.Command{ show(r), @@ -88,35 +88,12 @@ func AGPL() []*clibase.Command { return all } -func Root(subcommands []*cobra.Command) *cobra.Command { - // The GIT_ASKPASS environment variable must point at - // a binary with no arguments. To prevent writing - // cross-platform scripts to invoke the Coder binary - // with a `gitaskpass` subcommand, we override the entrypoint - // to check if the command was invoked. - isGitAskpass := false - +func (r *RootCmd) Command(subcommands []*clibase.Command) *clibase.Command { fmtLong := `Coder %s — A tool for provisioning self-hosted development environments with Terraform. ` - cmd := &cobra.Command{ - Use: "coder", - SilenceErrors: true, - SilenceUsage: true, - Long: fmt.Sprintf(fmtLong, buildinfo.Version()), - Args: func(cmd *cobra.Command, args []string) error { - if gitauth.CheckCommand(args, os.Environ()) { - isGitAskpass = true - return nil - } - return cobra.NoArgs(cmd, args) - }, - RunE: func(cmd *cobra.Command, args []string) error { - if isGitAskpass { - return gitAskpass().RunE(cmd, args) - } - return cmd.Help() - }, - Example: formatExamples( + cmd := &clibase.Command{ + Use: "coder", + Long: fmt.Sprintf(fmtLong, buildinfo.Version()) + formatExamples( example{ Description: "Start a Coder server", Command: "coder server", @@ -126,28 +103,116 @@ func Root(subcommands []*cobra.Command) *cobra.Command { Command: "coder templates init", }, ), + Middleware: clibase.Chain( + clibase.RequireNArgs(0), + ), + Handler: func(i *clibase.Invokation) error { + // The GIT_ASKPASS environment variable must point at + // a binary with no arguments. To prevent writing + // cross-platform scripts to invoke the Coder binary + // with a `gitaskpass` subcommand, we override the entrypoint + // to check if the command was invoked. + if gitauth.CheckCommand(i.Args, i.Environ.ToOS()) { + return gitAskpass().Handler(i) + } + return i.Command.HelpHandler(i) + }, + Children: subcommands, } - cmd.AddCommand(subcommands...) - fixUnknownSubcommandError(cmd.Commands()) - - cmd.SetUsageTemplate(usageTemplateCobra()) + // Set default help handler for all commands. + cmd.Walk(func(c *clibase.Command) { + if c.HelpHandler == nil { + c.HelpHandler = func(i *clibase.Invokation) error { + usageFn(i.Stderr, c)() + return nil + } + } + }) - cliflag.String(cmd.PersistentFlags(), varURL, "", envURL, "", "URL to a deployment.") - cliflag.Bool(cmd.PersistentFlags(), varNoVersionCheck, "", envNoVersionCheck, false, "Suppress warning when client and server versions do not match.") - cliflag.Bool(cmd.PersistentFlags(), varNoFeatureWarning, "", envNoFeatureWarning, false, "Suppress warnings about unlicensed features.") - cliflag.String(cmd.PersistentFlags(), varToken, "", envSessionToken, "", fmt.Sprintf("Specify an authentication token. For security reasons setting %s is preferred.", envSessionToken)) - cliflag.String(cmd.PersistentFlags(), varAgentToken, "", "CODER_AGENT_TOKEN", "", "An agent authentication token.") - _ = cmd.PersistentFlags().MarkHidden(varAgentToken) - cliflag.String(cmd.PersistentFlags(), varAgentURL, "", "CODER_AGENT_URL", "", "URL for an agent to access your deployment.") - _ = cmd.PersistentFlags().MarkHidden(varAgentURL) - cliflag.String(cmd.PersistentFlags(), config.FlagName, "", "CODER_CONFIG_DIR", config.DefaultDir(), "Path to the global `coder` config directory.") - cliflag.StringArray(cmd.PersistentFlags(), varHeader, "", "CODER_HEADER", []string{}, "HTTP headers added to all requests. Provide as \"Key=Value\"") - cmd.PersistentFlags().Bool(varForceTty, false, "Force the `coder` command to run as if connected to a TTY.") - _ = cmd.PersistentFlags().MarkHidden(varForceTty) - cmd.PersistentFlags().Bool(varNoOpen, false, "Block automatically opening URLs in the browser.") - _ = cmd.PersistentFlags().MarkHidden(varNoOpen) - cliflag.Bool(cmd.PersistentFlags(), varVerbose, "v", "CODER_VERBOSE", false, "Enable verbose output.") + cmd.Options = []clibase.Option{ + { + Name: varURL, + Flag: varURL, + Env: envURL, + Description: "URL to a deployment.", + Value: &r.clientURL, + }, + { + Name: varToken, + Flag: varToken, + Env: envSessionToken, + Description: fmt.Sprintf("Specify an authentication token. For security reasons setting %s is preferred.", envSessionToken), + Value: &r.token, + }, + { + Name: varAgentToken, + Flag: varAgentToken, + Description: "An agent authentication token.", + Value: &r.agentToken, + Hidden: true, + }, + { + Name: varAgentURL, + Flag: varAgentURL, + Env: "CODER_AGENT_URL", + Description: "URL for an agent to access your deployment", + Value: &r.agentURL, + Hidden: true, + }, + { + Name: varNoVersionCheck, + Flag: varNoVersionCheck, + Env: envNoVersionCheck, + Description: "Suppress warning when client and server versions do not match.", + Value: &r.noVersionCheck, + }, + { + Name: varNoFeatureWarning, + Flag: varNoFeatureWarning, + Env: envNoFeatureWarning, + Description: "Suppress warnings about unlicensed features.", + Value: &r.noFeatureWarning, + }, + { + Name: varHeader, + Flag: varHeader, + Env: "CODER_HEADER", + Description: "Additional HTTP headers to send to the server.", + Value: &r.header, + }, + { + Name: varNoOpen, + Flag: varNoOpen, + Env: "CODER_NO_OPEN", + Description: "Suppress opening the browser after logging in.", + Value: &r.noOpen, + Hidden: true, + }, + { + Name: varForceTty, + Flag: varForceTty, + Env: "CODER_FORCE_TTY", + Hidden: true, + Description: "Force the use of a TTY.", + Value: &r.forceTTY, + }, + { + Name: varVerbose, + Flag: varVerbose, + FlagShorthand: "v", + Env: "CODER_VERBOSE", + Description: "Enable verbose logging.", + Value: &r.verbose, + }, + { + Name: config.FlagName, + Flag: config.FlagName, + Env: "CODER_CONFIG_DIR", + Description: "Path to the global `coder` config directory.", + Value: &r.globalConfig, + }, + } return cmd } @@ -167,35 +232,6 @@ func LoggerFromContext(ctx context.Context) (slog.Logger, bool) { return l, ok } -// fixUnknownSubcommandError modifies the provided commands so that the -// ones with subcommands output the correct error message when an -// unknown subcommand is invoked. -// -// Example: -// -// unknown command "bad" for "coder templates" -func fixUnknownSubcommandError(commands []*cobra.Command) { - for _, sc := range commands { - if sc.HasSubCommands() { - if sc.Run == nil && sc.RunE == nil { - if sc.Args != nil { - // In case the developer does not know about this - // behavior in Cobra they must verify correct - // behavior. For instance, settings Args to - // `cobra.ExactArgs(0)` will not give the same - // message as `cobra.NoArgs`. Likewise, omitting the - // run function will not give the wanted error. - panic("developer error: subcommand has subcommands and Args but no Run or RunE") - } - sc.Args = cobra.NoArgs - sc.Run = func(*cobra.Command, []string) {} - } - - fixUnknownSubcommandError(sc.Commands()) - } - } -} - // versionCmd prints the coder version func versionCmd() *cobra.Command { return &cobra.Command{ @@ -230,26 +266,31 @@ func isTest() bool { return flag.Lookup("test.v") != nil } -type rootCmd struct { - clientURL *url.URL - token string - globalConfig string - header []string +type RootCmd struct { + clientURL clibase.URL + token clibase.String + globalConfig clibase.String + header clibase.Strings + agentToken clibase.String + agentURL clibase.URL + forceTTY clibase.Bool + noOpen clibase.Bool + verbose clibase.Bool - noVersionCheck bool - noFeatureWarning bool + noVersionCheck clibase.Bool + noFeatureWarning clibase.Bool } // useClient returns a new client from the command context. // It reads from global configuration files if flags are not set. -func (r *rootCmd) useClient(c *codersdk.Client) clibase.MiddlewareFunc { +func (r *RootCmd) useClient(c *codersdk.Client) clibase.MiddlewareFunc { return func(next clibase.HandlerFunc) clibase.HandlerFunc { return clibase.HandlerFunc( func(i *clibase.Invokation) error { root := r.createConfig() - clientURL := r.clientURL + var clientURL *url.URL var err error - if clientURL == nil { + if clientURL.String() == "" { rawURL, err := root.URL().Read() // If the configuration files are absent, the user is logged out if os.IsNotExist(err) { @@ -263,9 +304,11 @@ func (r *rootCmd) useClient(c *codersdk.Client) clibase.MiddlewareFunc { if err != nil { return err } + } else { + clientURL = r.clientURL.Value() } - token := r.token + token := r.token.Value() if token == "" { token, err = root.Session().Read() // If the configuration files are absent, the user is logged out @@ -321,7 +364,7 @@ func (r *rootCmd) useClient(c *codersdk.Client) clibase.MiddlewareFunc { } } -func (r *rootCmd) createUnauthenticatedClient(serverURL *url.URL) (*codersdk.Client, error) { +func (r *RootCmd) createUnauthenticatedClient(serverURL *url.URL) (*codersdk.Client, error) { client := codersdk.New(serverURL) transport := &headerTransport{ transport: http.DefaultTransport, @@ -391,7 +434,7 @@ func namedWorkspace(ctx context.Context, client *codersdk.Client, identifier str } // createConfig consumes the global configuration flag to produce a config root. -func (r *rootCmd) createConfig() config.Root { +func (r *RootCmd) createConfig() config.Root { return config.Root(r.globalConfig) } @@ -585,7 +628,7 @@ func FormatCobraError(err error, cmd *cobra.Command) string { return cliui.Styles.Error.Render(output.String()) } -func (r *rootCmd) checkVersions(i *clibase.Invokation, client *codersdk.Client) error { +func (r *RootCmd) checkVersions(i *clibase.Invokation, client *codersdk.Client) error { if r.noVersionCheck { return nil } @@ -623,7 +666,7 @@ func (r *rootCmd) checkVersions(i *clibase.Invokation, client *codersdk.Client) return nil } -func (r *rootCmd) checkWarnings(i *clibase.Invokation, client *codersdk.Client) error { +func (r *RootCmd) checkWarnings(i *clibase.Invokation, client *codersdk.Client) error { if r.noFeatureWarning { return nil } diff --git a/cli/show.go b/cli/show.go index c000132ebf442..55fe473b54071 100644 --- a/cli/show.go +++ b/cli/show.go @@ -8,7 +8,7 @@ import ( "github.com/coder/coder/codersdk" ) -func show(root *rootCmd) *clibase.Command { +func show(root *RootCmd) *clibase.Command { var client *codersdk.Client return &clibase.Command{ Use: "show ", diff --git a/cmd/coder/main.go b/cmd/coder/main.go index 177b3a469a21c..ed89ad08e1724 100644 --- a/cmd/coder/main.go +++ b/cmd/coder/main.go @@ -9,19 +9,29 @@ import ( _ "time/tzdata" "github.com/coder/coder/cli" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" ) func main() { rand.Seed(time.Now().UnixMicro()) - cmd, err := cli.Root(cli.AGPL()).ExecuteC() + var cmd cli.RootCmd + i := clibase.Invokation{ + Args: os.Args[1:], + Command: cmd.Command(cli.AGPL()), + Environ: clibase.ParseEnviron(os.Environ(), ""), + Stdout: os.Stdout, + Stderr: os.Stderr, + Stdin: os.Stdin, + } + + err := i.Run() if err != nil { if errors.Is(err, cliui.Canceled) { os.Exit(1) } - cobraErr := cli.FormatCobraError(err, cmd) - _, _ = fmt.Fprintln(os.Stderr, cobraErr) + _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } } diff --git a/go.sum b/go.sum index 66da404954be1..c8ecccdab4ca9 100644 --- a/go.sum +++ b/go.sum @@ -376,10 +376,10 @@ github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d h1:09JG37IgTB6n3ouX9 github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d/go.mod h1:r+1J5i/989wt6CUeNSuvFKKA9hHuKKPMxdzDbTuvwwk= github.com/coder/ssh v0.0.0-20220811105153-fcea99919338 h1:tN5GKFT68YLVzJoA8AHuiMNJ0qlhoD3pGN3JY9gxSko= github.com/coder/ssh v0.0.0-20220811105153-fcea99919338/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= -github.com/coder/tailscale v1.1.1-0.20230307022319-1e5e724a3949 h1:8WfMfRTDaEpnmhCJWfFQ7JHz19GyP+EgFgLGu5ngdek= -github.com/coder/tailscale v1.1.1-0.20230307022319-1e5e724a3949/go.mod h1:jpg+77g19FpXL43U1VoIqoSg1K/Vh5CVxycGldQ8KhA= -github.com/coder/terraform-provider-coder v0.6.15 h1:Llvh4RwxSQ/goy7ToTOeHf3tdEz+79qbyOh61hNnJs0= -github.com/coder/terraform-provider-coder v0.6.15/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= +github.com/coder/tailscale v1.1.1-0.20230301203426-fb16ae7c5bba h1:JOD5pqNtiz9lkSX74PY2BJOyNqsBmvGUjFGIuECtG+o= +github.com/coder/tailscale v1.1.1-0.20230301203426-fb16ae7c5bba/go.mod h1:jpg+77g19FpXL43U1VoIqoSg1K/Vh5CVxycGldQ8KhA= +github.com/coder/terraform-provider-coder v0.6.14 h1:NsJ1mo0MN1x/VyNLYmsgPUYn2JgzdVNZBqnj9OSIDgY= +github.com/coder/terraform-provider-coder v0.6.14/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= From 518b51d9cca0258f3781e99940c52bd223454a9a Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Tue, 7 Mar 2023 18:23:49 +0000 Subject: [PATCH 005/175] 486 problems left --- cli/agent_test.go | 72 +++++++----------------------- cli/clibase/cmd_test.go | 2 +- cli/clitest/clitest.go | 33 +++++++------- cli/clitest/clitest_test.go | 8 ++-- cli/cliui/agent_test.go | 35 ++++++++------- cli/cliui/gitauth_test.go | 2 +- cli/cliui/prompt_test.go | 4 +- cli/cliui/provisionerjob_test.go | 2 +- cli/cliui/select_test.go | 4 +- cli/configssh_test.go | 36 ++++++--------- cli/create_test.go | 26 +++++------ cli/delete_test.go | 8 ++-- cli/dotfiles_test.go | 8 ++-- cli/gitaskpass_test.go | 8 ++-- cli/gitssh_test.go | 8 ++-- cli/list_test.go | 4 +- cli/ping_test.go | 2 +- cli/portforward_test.go | 10 ++--- cli/publickey_test.go | 2 +- cli/rename_test.go | 2 +- cli/resetpassword_test.go | 4 +- cli/restart_test.go | 2 +- cli/root_test.go | 16 +++---- cli/scaletest_test.go | 4 +- cli/schedule_test.go | 22 ++++----- cli/show_test.go | 2 +- cli/speedtest_test.go | 2 +- cli/ssh_test.go | 10 ++--- cli/state_test.go | 8 ++-- cli/templatecreate_test.go | 22 ++++----- cli/templatedelete_test.go | 8 ++-- cli/templateedit_test.go | 10 ++--- cli/templateinit_test.go | 2 +- cli/templatelist_test.go | 6 +-- cli/templatepull_test.go | 8 ++-- cli/templatepush_test.go | 20 ++++----- cli/templateversions_test.go | 2 +- cli/tokens_test.go | 10 ++--- cli/update_test.go | 26 +++++------ cli/usercreate_test.go | 2 +- cli/userlist_test.go | 12 ++--- cli/userstatus_test.go | 6 +-- cli/vscodessh_test.go | 2 +- enterprise/cli/features_test.go | 4 +- enterprise/cli/groupcreate_test.go | 2 +- enterprise/cli/groupdelete_test.go | 4 +- enterprise/cli/groupedit_test.go | 6 +-- enterprise/cli/grouplist_test.go | 4 +- enterprise/cli/licenses_test.go | 20 ++++----- 49 files changed, 239 insertions(+), 283 deletions(-) diff --git a/cli/agent_test.go b/cli/agent_test.go index 9f5537aca9d2a..dae176d82844c 100644 --- a/cli/agent_test.go +++ b/cli/agent_test.go @@ -16,7 +16,6 @@ import ( "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/provisioner/echo" "github.com/coder/coder/provisionersdk/proto" - "github.com/coder/coder/testutil" ) func TestWorkspaceAgent(t *testing.T) { @@ -56,24 +55,16 @@ func TestWorkspaceAgent(t *testing.T) { coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) logDir := t.TempDir() - cmd, _ := clitest.New(t, + inv, _ := clitest.New(t, "agent", "--auth", "token", "--agent-token", authToken, "--agent-url", client.URL.String(), "--log-dir", logDir, ) - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium) - defer cancel() - errC := make(chan error, 1) - go func() { - errC <- cmd.ExecuteContext(ctx) - }() - coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) - cancel() - err := <-errC - require.NoError(t, err) + clitest.Start(t, inv) + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) info, err := os.Stat(filepath.Join(logDir, "coder-agent.log")) require.NoError(t, err) @@ -83,7 +74,7 @@ func TestWorkspaceAgent(t *testing.T) { t.Run("Azure", func(t *testing.T) { t.Parallel() instanceID := "instanceidentifier" - certificates, metadataClient := coderdtest.NewAzureInstanceIdentity(t, instanceID) + certificates, _ := coderdtest.NewAzureInstanceIdentity(t, instanceID) client := coderdtest.New(t, &coderdtest.Options{ AzureCertificates: certificates, IncludeProvisionerDaemon: true, @@ -112,16 +103,10 @@ func TestWorkspaceAgent(t *testing.T) { workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - cmd, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--agent-url", client.URL.String()) + inv, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--agent-url", client.URL.String()) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() - errC := make(chan error) - go func() { - // A linting error occurs for weakly typing the context value here. - //nolint // The above seems reasonable for a one-off test. - ctx := context.WithValue(ctx, "azure-client", metadataClient) - errC <- cmd.ExecuteContext(ctx) - }() + clitest.Start(t, inv) coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) @@ -133,15 +118,12 @@ func TestWorkspaceAgent(t *testing.T) { require.NoError(t, err) defer dialer.Close() require.True(t, dialer.AwaitReachable(context.Background())) - cancelFunc() - err = <-errC - require.NoError(t, err) }) t.Run("AWS", func(t *testing.T) { t.Parallel() instanceID := "instanceidentifier" - certificates, metadataClient := coderdtest.NewAWSInstanceIdentity(t, instanceID) + certificates, _ := coderdtest.NewAWSInstanceIdentity(t, instanceID) client := coderdtest.New(t, &coderdtest.Options{ AWSCertificates: certificates, IncludeProvisionerDaemon: true, @@ -170,36 +152,25 @@ func TestWorkspaceAgent(t *testing.T) { workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - cmd, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--agent-url", client.URL.String()) - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - errC := make(chan error) - go func() { - // A linting error occurs for weakly typing the context value here. - //nolint // The above seems reasonable for a one-off test. - ctx := context.WithValue(ctx, "aws-client", metadataClient) - errC <- cmd.ExecuteContext(ctx) - }() + inv, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--agent-url", client.URL.String()) + clitest.Start(t, inv) coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) - workspace, err := client.Workspace(ctx, workspace.ID) + workspace, err := client.Workspace(inv.Context(), workspace.ID) require.NoError(t, err) resources := workspace.LatestBuild.Resources if assert.NotEmpty(t, resources) && assert.NotEmpty(t, resources[0].Agents) { assert.NotEmpty(t, resources[0].Agents[0].Version) } - dialer, err := client.DialWorkspaceAgent(ctx, resources[0].Agents[0].ID, nil) + dialer, err := client.DialWorkspaceAgent(inv.Context(), resources[0].Agents[0].ID, nil) require.NoError(t, err) defer dialer.Close() require.True(t, dialer.AwaitReachable(context.Background())) - cancelFunc() - err = <-errC - require.NoError(t, err) }) t.Run("GoogleCloud", func(t *testing.T) { t.Parallel() instanceID := "instanceidentifier" - validator, metadata := coderdtest.NewGoogleInstanceIdentity(t, instanceID, false) + validator, _ := coderdtest.NewGoogleInstanceIdentity(t, instanceID, false) client := coderdtest.New(t, &coderdtest.Options{ GoogleTokenValidator: validator, IncludeProvisionerDaemon: true, @@ -228,16 +199,11 @@ func TestWorkspaceAgent(t *testing.T) { workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - cmd, _ := clitest.New(t, "agent", "--auth", "google-instance-identity", "--agent-url", client.URL.String()) - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - errC := make(chan error) - go func() { - // A linting error occurs for weakly typing the context value here. - //nolint // The above seems reasonable for a one-off test. - ctx := context.WithValue(ctx, "gcp-client", metadata) - errC <- cmd.ExecuteContext(ctx) - }() + inv, _ := clitest.New(t, "agent", "--auth", "google-instance-identity", "--agent-url", client.URL.String()) + clitest.Start(t, inv) + + ctx := inv.Context() + coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) workspace, err := client.Workspace(ctx, workspace.ID) require.NoError(t, err) @@ -264,9 +230,5 @@ func TestWorkspaceAgent(t *testing.T) { require.NoError(t, err) _, err = uuid.Parse(strings.TrimSpace(string(token))) require.NoError(t, err) - - cancelFunc() - err = <-errC - require.NoError(t, err) }) } diff --git a/cli/clibase/cmd_test.go b/cli/clibase/cmd_test.go index 1bb88b0d006bd..94a1c0cb4fe14 100644 --- a/cli/clibase/cmd_test.go +++ b/cli/clibase/cmd_test.go @@ -34,7 +34,7 @@ func TestCommand_ToUpper(t *testing.T) { Middleware: clibase.Chain( clibase.RequireNArgs(1), ), - Options: &clibase.OptionSet{ + Options: clibase.OptionSet{ clibase.Option{ Name: "lower", Flag: "lower", diff --git a/cli/clitest/clitest.go b/cli/clitest/clitest.go index d866ab54234e0..8319d19ced1f0 100644 --- a/cli/clitest/clitest.go +++ b/cli/clitest/clitest.go @@ -13,7 +13,6 @@ import ( "testing" "time" - "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -27,7 +26,7 @@ import ( // New creates a CLI instance with a configuration pointed to a // temporary testing directory. -func New(t *testing.T, args ...string) (*clibase.Command, config.Root) { +func New(t *testing.T, args ...string) (*clibase.Invokation, config.Root) { return NewWithSubcommands(t, cli.AGPL(), args...) } @@ -48,18 +47,20 @@ func (l *logWriter) Write(p []byte) (n int, err error) { } func NewWithSubcommands( - t *testing.T, subcommands []*cobra.Command, args ...string, -) (*cobra.Command, config.Root) { - cmd := cli.Root(subcommands) - dir := t.TempDir() - root := config.Root(dir) - cmd.SetArgs(append([]string{"--global-config", dir}, args...)) - + t *testing.T, subcommands []*clibase.Command, args ...string, +) (*clibase.Invokation, config.Root) { + var root cli.RootCmd + cmd := root.Command(subcommands) + + configDir := config.Root(t.TempDir()) + i := &clibase.Invokation{ + Command: cmd, + Args: append([]string{"--global-config", string(configDir)}, args...), + Stdout: (&logWriter{prefix: "stdout", t: t}), + Stderr: (&logWriter{prefix: "stderr", t: t}), + } // These can be overridden by the test. - cmd.SetOut(&logWriter{prefix: "stdout", t: t}) - cmd.SetErr(&logWriter{prefix: "stderr", t: t}) - - return cmd, root + return i, configDir } // SetupConfig applies the URL and SessionToken of the client to the config. @@ -121,11 +122,13 @@ func extractTar(t *testing.T, data []byte, directory string) { // Start runs the command in a goroutine and cleans it up when // the test completed. -func Start(ctx context.Context, t *testing.T, cmd *cobra.Command) { +func Start(t *testing.T, inv *clibase.Invokation) { t.Helper() closeCh := make(chan struct{}) + ctx := inv.Context() + deadline, hasDeadline := ctx.Deadline() if !hasDeadline { // We don't want to wait the full 5 minutes for a test to time out. @@ -137,7 +140,7 @@ func Start(ctx context.Context, t *testing.T, cmd *cobra.Command) { go func() { defer cancel() defer close(closeCh) - err := cmd.ExecuteContext(ctx) + err := inv.Run() if ctx.Err() == nil { assert.NoError(t, err) } diff --git a/cli/clitest/clitest_test.go b/cli/clitest/clitest_test.go index 441b84048d05e..89be133e87198 100644 --- a/cli/clitest/clitest_test.go +++ b/cli/clitest/clitest_test.go @@ -18,13 +18,13 @@ func TestCli(t *testing.T) { t.Parallel() clitest.CreateTemplateVersionSource(t, nil) client := coderdtest.New(t, nil) - cmd, config := clitest.New(t) + i, config := clitest.New(t) clitest.SetupConfig(t, client, config) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + i.Stdin = pty.Input() + i.Stdout = pty.Output() go func() { - _ = cmd.Execute() + _ = i.Run() }() pty.ExpectMatch("coder") } diff --git a/cli/cliui/agent_test.go b/cli/cliui/agent_test.go index 5122baaa755a1..01567548742b4 100644 --- a/cli/cliui/agent_test.go +++ b/cli/cliui/agent_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/atomic" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" "github.com/coder/coder/pty/ptytest" @@ -24,9 +25,9 @@ func TestAgent(t *testing.T) { var disconnected atomic.Bool ptty := ptytest.New(t) - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, _ []string) error { - err := cliui.Agent(cmd.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { + err := cliui.Agent(inv.Context(), inv.Stdout, cliui.AgentOptions{ WorkspaceName: "example", Fetch: func(_ context.Context) (codersdk.WorkspaceAgent, error) { agent := codersdk.WorkspaceAgent{ @@ -49,7 +50,7 @@ func TestAgent(t *testing.T) { done := make(chan struct{}) go func() { defer close(done) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() ptty.ExpectMatchContext(ctx, "lost connection") @@ -95,7 +96,7 @@ func TestAgent_TimeoutWithTroubleshootingURL(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.ExecuteContext(ctx) + done <- cmd.RunContext(ctx) }() ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") timeout.Store(true) @@ -148,7 +149,7 @@ func TestAgent_StartupTimeout(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.ExecuteContext(ctx) + done <- cmd.RunContext(ctx) }() setStatus(codersdk.WorkspaceAgentConnecting) ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") @@ -206,7 +207,7 @@ func TestAgent_StartErrorExit(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.ExecuteContext(ctx) + done <- cmd.RunContext(ctx) }() setStatus(codersdk.WorkspaceAgentConnected) setState(codersdk.WorkspaceAgentLifecycleStarting) @@ -261,7 +262,7 @@ func TestAgent_NoWait(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.ExecuteContext(ctx) + done <- cmd.RunContext(ctx) }() setStatus(codersdk.WorkspaceAgentConnecting) ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") @@ -270,19 +271,19 @@ func TestAgent_NoWait(t *testing.T) { require.NoError(t, <-done, "created - should exit early") setState(codersdk.WorkspaceAgentLifecycleStarting) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "starting - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartTimeout) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "start timeout - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartError) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "start error - should exit early") setState(codersdk.WorkspaceAgentLifecycleReady) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "ready - should exit early") } @@ -330,7 +331,7 @@ func TestAgent_LoginBeforeReadyEnabled(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.ExecuteContext(ctx) + done <- cmd.RunContext(ctx) }() setStatus(codersdk.WorkspaceAgentConnecting) ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") @@ -339,18 +340,18 @@ func TestAgent_LoginBeforeReadyEnabled(t *testing.T) { require.NoError(t, <-done, "created - should exit early") setState(codersdk.WorkspaceAgentLifecycleStarting) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "starting - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartTimeout) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "start timeout - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartError) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "start error - should exit early") setState(codersdk.WorkspaceAgentLifecycleReady) - go func() { done <- cmd.ExecuteContext(ctx) }() + go func() { done <- cmd.RunContext(ctx) }() require.NoError(t, <-done, "ready - should exit early") } diff --git a/cli/cliui/gitauth_test.go b/cli/cliui/gitauth_test.go index de2198798e8d3..96b615b4d9c9b 100644 --- a/cli/cliui/gitauth_test.go +++ b/cli/cliui/gitauth_test.go @@ -45,7 +45,7 @@ func TestGitAuth(t *testing.T) { done := make(chan struct{}) go func() { defer close(done) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() ptty.ExpectMatchContext(ctx, "You must authenticate with") diff --git a/cli/cliui/prompt_test.go b/cli/cliui/prompt_test.go index 6c7f233c872e6..dfea75b1dd347 100644 --- a/cli/cliui/prompt_test.go +++ b/cli/cliui/prompt_test.go @@ -161,7 +161,7 @@ func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions, cmdOpt func(cmd *cob cmd.SetOut(ptty.Output()) cmd.SetErr(ptty.Output()) cmd.SetIn(ptty.Input()) - return value, cmd.ExecuteContext(context.Background()) + return value, cmd.RunContext(context.Background()) } func TestPasswordTerminalState(t *testing.T) { @@ -216,5 +216,5 @@ func passwordHelper() { }) }, } - cmd.ExecuteContext(context.Background()) + cmd.RunContext(context.Background()) } diff --git a/cli/cliui/provisionerjob_test.go b/cli/cliui/provisionerjob_test.go index 122ff513dd79e..5009f074577d0 100644 --- a/cli/cliui/provisionerjob_test.go +++ b/cli/cliui/provisionerjob_test.go @@ -151,7 +151,7 @@ func newProvisionerJob(t *testing.T) provisionerJobTest { done := make(chan struct{}) go func() { defer close(done) - err := cmd.ExecuteContext(context.Background()) + err := cmd.RunContext(context.Background()) if err != nil { assert.ErrorIs(t, err, cliui.Canceled) } diff --git a/cli/cliui/select_test.go b/cli/cliui/select_test.go index 4a7cede5cf92a..4c05cab7aa1e5 100644 --- a/cli/cliui/select_test.go +++ b/cli/cliui/select_test.go @@ -41,7 +41,7 @@ func newSelect(ptty *ptytest.PTY, opts cliui.SelectOptions) (string, error) { } cmd.SetOutput(ptty.Output()) cmd.SetIn(ptty.Input()) - return value, cmd.ExecuteContext(context.Background()) + return value, cmd.RunContext(context.Background()) } func TestRichSelect(t *testing.T) { @@ -84,5 +84,5 @@ func newRichSelect(ptty *ptytest.PTY, opts cliui.RichSelectOptions) (string, err } cmd.SetOutput(ptty.Output()) cmd.SetIn(ptty.Input()) - return value, cmd.ExecuteContext(context.Background()) + return value, cmd.RunContext(context.Background()) } diff --git a/cli/configssh_test.go b/cli/configssh_test.go index 343a6af43dc58..56c5fab136be4 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -153,21 +153,17 @@ func TestConfigSSH(t *testing.T) { tcpAddr, valid := listener.Addr().(*net.TCPAddr) require.True(t, valid) - cmd, root := clitest.New(t, "config-ssh", + inv, root := clitest.New(t, "config-ssh", "--ssh-option", "HostName "+tcpAddr.IP.String(), "--ssh-option", "Port "+strconv.Itoa(tcpAddr.Port), "--ssh-config-file", sshConfigFile, "--skip-proxy-command") 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) - }() + inv.Stdin = pty.Input() + inv.Stdout = pty.Output() + + clitest.Start(t, inv) matches := []struct { match, write string @@ -179,8 +175,6 @@ func TestConfigSSH(t *testing.T) { pty.WriteLine(m.write) } - <-doneChan - home := filepath.Dir(filepath.Dir(sshConfigFile)) // #nosec sshCmd := exec.Command("ssh", "-F", sshConfigFile, "coder."+workspace.Name, "echo", "test") @@ -586,14 +580,14 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) { "--ssh-config-file", sshConfigName, } args = append(args, tt.args...) - cmd, root := clitest.New(t, args...) + inv, root := clitest.New(t, args...) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + inv.Stdin = pty.Input() + inv.Stdout = pty.Output() done := tGo(t, func() { - err := cmd.Execute() + err := inv.Run() if !tt.wantErr { assert.NoError(t, err) } else { @@ -703,17 +697,13 @@ func TestConfigSSH_Hostnames(t *testing.T) { sshConfigFile := sshConfigFileName(t) - cmd, root := clitest.New(t, "config-ssh", "--ssh-config-file", sshConfigFile) + inv, root := clitest.New(t, "config-ssh", "--ssh-config-file", sshConfigFile) 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) - }() + inv.Stdin = pty.Input() + inv.Stdout = pty.Output() + clitest.Start(t, inv) matches := []struct { match, write string diff --git a/cli/create_test.go b/cli/create_test.go index 0cdbf45839bcf..dabfeba5aa634 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -53,7 +53,7 @@ func TestCreate(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() matches := []struct { @@ -98,7 +98,7 @@ func TestCreate(t *testing.T) { cmdCtx, done := context.WithTimeout(context.Background(), testutil.WaitLong) go func() { defer done() - err := cmd.ExecuteContext(cmdCtx) + err := cmd.RunContext(cmdCtx) assert.NoError(t, err) }() // No pty interaction needed since we use the -y skip prompt flag @@ -121,7 +121,7 @@ func TestCreate(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() matches := []string{ @@ -165,7 +165,7 @@ func TestCreate(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -210,7 +210,7 @@ func TestCreate(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -255,7 +255,7 @@ func TestCreate(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() matches := []struct { @@ -321,7 +321,7 @@ func TestCreate(t *testing.T) { cmd.SetIn(pty.Input()) cmd.SetOut(pty.Output()) - err = cmd.Execute() + err = cmd.Run() require.Error(t, err) require.ErrorContains(t, err, "dry-run workspace") }) @@ -384,7 +384,7 @@ func TestCreateWithRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -429,7 +429,7 @@ func TestCreateWithRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -512,7 +512,7 @@ func TestCreateValidateRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -549,7 +549,7 @@ func TestCreateValidateRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -589,7 +589,7 @@ func TestCreateValidateRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -651,7 +651,7 @@ func TestCreateWithGitAuth(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() diff --git a/cli/delete_test.go b/cli/delete_test.go index 2f2cf404fc6ab..ac3af8d9c5f83 100644 --- a/cli/delete_test.go +++ b/cli/delete_test.go @@ -33,7 +33,7 @@ func TestDelete(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() // When running with the race detector on, we sometimes get an EOF. if err != nil { assert.ErrorIs(t, err, io.EOF) @@ -62,7 +62,7 @@ func TestDelete(t *testing.T) { cmd.SetErr(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() // When running with the race detector on, we sometimes get an EOF. if err != nil { assert.ErrorIs(t, err, io.EOF) @@ -95,7 +95,7 @@ func TestDelete(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() // When running with the race detector on, we sometimes get an EOF. if err != nil { assert.ErrorIs(t, err, io.EOF) @@ -117,7 +117,7 @@ func TestDelete(t *testing.T) { doneChan := make(chan struct{}) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.ErrorContains(t, err, "invalid workspace name: \"a/b/c\"") }() <-doneChan diff --git a/cli/dotfiles_test.go b/cli/dotfiles_test.go index 479baf3f9a05a..9b80906b176a7 100644 --- a/cli/dotfiles_test.go +++ b/cli/dotfiles_test.go @@ -19,7 +19,7 @@ import ( func TestDotfiles(t *testing.T) { t.Run("MissingArg", func(t *testing.T) { cmd, _ := clitest.New(t, "dotfiles") - err := cmd.Execute() + err := cmd.Run() require.Error(t, err) }) t.Run("NoInstallScript", func(t *testing.T) { @@ -41,7 +41,7 @@ func TestDotfiles(t *testing.T) { require.NoError(t, err, string(out)) cmd, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) b, err := os.ReadFile(filepath.Join(string(root), ".bashrc")) @@ -70,7 +70,7 @@ func TestDotfiles(t *testing.T) { require.NoError(t, err) cmd, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) b, err := os.ReadFile(filepath.Join(string(root), ".bashrc")) @@ -101,7 +101,7 @@ func TestDotfiles(t *testing.T) { require.NoError(t, err, string(out)) cmd, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) b, err := os.ReadFile(filepath.Join(string(root), ".bashrc")) diff --git a/cli/gitaskpass_test.go b/cli/gitaskpass_test.go index 2e3bdc88505e7..961845cdb5336 100644 --- a/cli/gitaskpass_test.go +++ b/cli/gitaskpass_test.go @@ -33,14 +33,14 @@ func TestGitAskpass(t *testing.T) { cmd, _ := clitest.New(t, "--agent-url", url, "Username for 'https://github.com':") pty := ptytest.New(t) cmd.SetOutput(pty.Output()) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) pty.ExpectMatch("something") cmd, _ = clitest.New(t, "--agent-url", url, "Password for 'https://potato@github.com':") pty = ptytest.New(t) cmd.SetOutput(pty.Output()) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) pty.ExpectMatch("bananas") }) @@ -56,7 +56,7 @@ func TestGitAskpass(t *testing.T) { cmd, _ := clitest.New(t, "--agent-url", url, "--no-open", "Username for 'https://github.com':") pty := ptytest.New(t) cmd.SetOutput(pty.Output()) - err := cmd.Execute() + err := cmd.Run() require.ErrorIs(t, err, cliui.Canceled) pty.ExpectMatch("Nope!") }) @@ -85,7 +85,7 @@ func TestGitAskpass(t *testing.T) { pty := ptytest.New(t) cmd.SetOutput(pty.Output()) go func() { - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() <-poll diff --git a/cli/gitssh_test.go b/cli/gitssh_test.go index 8d7420b9b0d89..328939a1155b2 100644 --- a/cli/gitssh_test.go +++ b/cli/gitssh_test.go @@ -78,7 +78,7 @@ func prepareTestGitSSH(ctx context.Context, t *testing.T) (*codersdk.Client, str errC := make(chan error, 1) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() t.Cleanup(func() { require.NoError(t, <-errC) }) coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) @@ -166,7 +166,7 @@ func TestGitSSH(t *testing.T) { "-o", "IdentitiesOnly=yes", "127.0.0.1", ) - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) require.NoError(t, err) require.EqualValues(t, 1, inc) @@ -231,7 +231,7 @@ func TestGitSSH(t *testing.T) { cmd, _ := clitest.New(t, cmdArgs...) cmd.SetOut(pty.Output()) cmd.SetErr(pty.Output()) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) select { case key := <-authkey: @@ -248,7 +248,7 @@ func TestGitSSH(t *testing.T) { cmd, _ = clitest.New(t, cmdArgs...) cmd.SetOut(pty.Output()) cmd.SetErr(pty.Output()) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) select { case key := <-authkey: diff --git a/cli/list_test.go b/cli/list_test.go index 19b265724b817..7186530ef233e 100644 --- a/cli/list_test.go +++ b/cli/list_test.go @@ -37,7 +37,7 @@ func TestList(t *testing.T) { defer cancelFunc() done := make(chan any) go func() { - errC := cmd.ExecuteContext(ctx) + errC := cmd.RunContext(ctx) assert.NoError(t, errC) close(done) }() @@ -65,7 +65,7 @@ func TestList(t *testing.T) { out := bytes.NewBuffer(nil) cmd.SetOut(out) - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) require.NoError(t, err) var templates []codersdk.Workspace diff --git a/cli/ping_test.go b/cli/ping_test.go index f599e38b4cd8c..996bd995c4d88 100644 --- a/cli/ping_test.go +++ b/cli/ping_test.go @@ -43,7 +43,7 @@ func TestPing(t *testing.T) { defer cancel() cmdDone := tGo(t, func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err) }) diff --git a/cli/portforward_test.go b/cli/portforward_test.go index 133bbf1f9a431..22d3aef3410cd 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -39,7 +39,7 @@ func TestPortForward(t *testing.T) { cmd.SetOut(pty.Output()) cmd.SetErr(pty.Output()) - err := cmd.Execute() + err := cmd.Run() require.Error(t, err) require.ErrorContains(t, err, "no port-forwards") @@ -144,7 +144,7 @@ func TestPortForward(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() pty.ExpectMatch("Ready!") @@ -192,7 +192,7 @@ func TestPortForward(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() pty.ExpectMatch("Ready!") @@ -249,7 +249,7 @@ func TestPortForward(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() pty.ExpectMatch("Ready!") @@ -333,7 +333,7 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) codersdk. require.NoError(t, err) }) go func() { - errC <- cmd.ExecuteContext(agentCtx) + errC <- cmd.RunContext(agentCtx) }() coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) diff --git a/cli/publickey_test.go b/cli/publickey_test.go index f0bef2c65359e..c38c7f9dac329 100644 --- a/cli/publickey_test.go +++ b/cli/publickey_test.go @@ -20,7 +20,7 @@ func TestPublicKey(t *testing.T) { clitest.SetupConfig(t, client, root) buf := new(bytes.Buffer) cmd.SetOut(buf) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) publicKey := buf.String() require.NotEmpty(t, publicKey) diff --git a/cli/rename_test.go b/cli/rename_test.go index f965bfa3e3636..5e1927d51257b 100644 --- a/cli/rename_test.go +++ b/cli/rename_test.go @@ -38,7 +38,7 @@ func TestRename(t *testing.T) { errC := make(chan error, 1) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() pty.ExpectMatch("confirm rename:") diff --git a/cli/resetpassword_test.go b/cli/resetpassword_test.go index 3bf45c271b758..b871f25564e99 100644 --- a/cli/resetpassword_test.go +++ b/cli/resetpassword_test.go @@ -46,7 +46,7 @@ func TestResetPassword(t *testing.T) { ) go func() { defer close(serverDone) - err = serverCmd.ExecuteContext(ctx) + err = servercmd.RunContext(ctx) assert.NoError(t, err) }() var rawURL string @@ -75,7 +75,7 @@ func TestResetPassword(t *testing.T) { resetCmd.SetOut(pty.Output()) go func() { defer close(cmdDone) - err = resetCmd.Execute() + err = resetcmd.Run() assert.NoError(t, err) }() diff --git a/cli/restart_test.go b/cli/restart_test.go index 9ad55a05137da..0cca73bb4861c 100644 --- a/cli/restart_test.go +++ b/cli/restart_test.go @@ -36,7 +36,7 @@ func TestRestart(t *testing.T) { done := make(chan error, 1) go func() { - done <- cmd.ExecuteContext(ctx) + done <- cmd.RunContext(ctx) }() pty.ExpectMatch("Stopping workspace") pty.ExpectMatch("Starting workspace") diff --git a/cli/root_test.go b/cli/root_test.go index 0f76782707723..b2eb783091787 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -132,7 +132,7 @@ ExtractCommandPathsLoop: clitest.SetupConfig(t, rootClient, cfg) cmd.SetOut(&buf) assert.NoError(t, err) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) err2 := os.Chdir(wd) require.NoError(t, err) require.NoError(t, err2) @@ -249,7 +249,7 @@ func TestRoot(t *testing.T) { cmd, _ := clitest.New(t, "delete") - cmd, err := cmd.ExecuteC() + cmd, err := cmd.RunC() errStr := cli.FormatCobraError(err, cmd) require.Contains(t, errStr, "Run 'coder delete --help' for usage.") }) @@ -276,7 +276,7 @@ func TestRoot(t *testing.T) { return err } - cmd, err := cmd.ExecuteC() + cmd, err := cmd.RunC() errStr := cli.FormatCobraError(err, cmd) require.Contains(t, errStr, "This is a message. Try this instead.") require.NotContains(t, errStr, err.Error()) @@ -293,7 +293,7 @@ func TestRoot(t *testing.T) { return xerrors.Errorf("this is a non-codersdk error: %w", xerrors.Errorf("a wrapped error")) } - cmd, err := cmd.ExecuteC() + cmd, err := cmd.RunC() errStr := cli.FormatCobraError(err, cmd) require.Contains(t, errStr, err.Error()) }) @@ -318,7 +318,7 @@ func TestRoot(t *testing.T) { return err } - cmd, err := cmd.ExecuteC() + cmd, err := cmd.RunC() errStr := cli.FormatCobraError(err, cmd) require.Contains(t, errStr, "This is a message. Try this instead.") require.Contains(t, errStr, err.Error()) @@ -334,7 +334,7 @@ func TestRoot(t *testing.T) { return xerrors.Errorf("this is a non-codersdk error: %w", xerrors.Errorf("a wrapped error")) } - cmd, err := cmd.ExecuteC() + cmd, err := cmd.RunC() errStr := cli.FormatCobraError(err, cmd) require.Contains(t, errStr, err.Error()) }) @@ -347,7 +347,7 @@ func TestRoot(t *testing.T) { buf := new(bytes.Buffer) cmd, _ := clitest.New(t, "version") cmd.SetOut(buf) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) output := buf.String() @@ -373,6 +373,6 @@ func TestRoot(t *testing.T) { cmd, _ := clitest.New(t, "--header", "X-Testing=wow", "login", srv.URL) cmd.SetOut(buf) // This won't succeed, because we're using the login cmd to assert requests. - _ = cmd.Execute() + _ = cmd.Run() }) } diff --git a/cli/scaletest_test.go b/cli/scaletest_test.go index 4052d4f0e4d15..914e74ec44038 100644 --- a/cli/scaletest_test.go +++ b/cli/scaletest_test.go @@ -82,7 +82,7 @@ param3: 1 done := make(chan any) go func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err) close(done) }() @@ -160,7 +160,7 @@ param3: 1 done = make(chan any) go func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err) close(done) }() diff --git a/cli/schedule_test.go b/cli/schedule_test.go index cd30de7d7f551..3daab5cf177df 100644 --- a/cli/schedule_test.go +++ b/cli/schedule_test.go @@ -46,7 +46,7 @@ func TestScheduleShow(t *testing.T) { clitest.SetupConfig(t, client, root) cmd.SetOut(stdoutBuf) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err, "unexpected error") lines := strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if assert.Len(t, lines, 4) { @@ -83,7 +83,7 @@ func TestScheduleShow(t *testing.T) { clitest.SetupConfig(t, client, root) cmd.SetOut(stdoutBuf) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err, "unexpected error") lines := strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if assert.Len(t, lines, 4) { @@ -107,7 +107,7 @@ func TestScheduleShow(t *testing.T) { cmd, root := clitest.New(t, "schedule", "show", "doesnotexist") clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.ErrorContains(t, err, "status code 404", "unexpected error") }) } @@ -136,7 +136,7 @@ func TestScheduleStart(t *testing.T) { clitest.SetupConfig(t, client, root) cmd.SetOut(stdoutBuf) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err, "unexpected error") lines := strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if assert.Len(t, lines, 4) { @@ -161,7 +161,7 @@ func TestScheduleStart(t *testing.T) { clitest.SetupConfig(t, client, root) cmd.SetOut(stdoutBuf) - err = cmd.Execute() + err = cmd.Run() assert.NoError(t, err, "unexpected error") lines = strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if assert.Len(t, lines, 4) { @@ -190,7 +190,7 @@ func TestScheduleStop(t *testing.T) { clitest.SetupConfig(t, client, root) cmd.SetOut(stdoutBuf) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err, "unexpected error") lines := strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if assert.Len(t, lines, 4) { @@ -207,7 +207,7 @@ func TestScheduleStop(t *testing.T) { clitest.SetupConfig(t, client, root) cmd.SetOut(stdoutBuf) - err = cmd.Execute() + err = cmd.Run() assert.NoError(t, err, "unexpected error") lines = strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if assert.Len(t, lines, 4) { @@ -252,7 +252,7 @@ func TestScheduleOverride(t *testing.T) { cmd.SetOut(stdoutBuf) // When: we execute `coder schedule override workspace ` - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) // Then: the deadline of the latest build is updated assuming the units are minutes @@ -292,7 +292,7 @@ func TestScheduleOverride(t *testing.T) { cmd.SetOut(stdoutBuf) // When: we execute `coder bump workspace ` - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) // Then: the command fails require.ErrorContains(t, err, "invalid duration") }) @@ -344,7 +344,7 @@ func TestScheduleOverride(t *testing.T) { cmd.SetOut(stdoutBuf) // When: we execute `coder bump workspace`` - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.Error(t, err) // Then: nothing happens and the deadline remains unset @@ -374,7 +374,7 @@ func TestScheduleStartDefaults(t *testing.T) { clitest.SetupConfig(t, client, root) cmd.SetOut(stdoutBuf) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err, "unexpected error") lines := strings.Split(strings.TrimSpace(stdoutBuf.String()), "\n") if assert.Len(t, lines, 4) { diff --git a/cli/show_test.go b/cli/show_test.go index 088c0c21e60d8..2709cc189d8f0 100644 --- a/cli/show_test.go +++ b/cli/show_test.go @@ -39,7 +39,7 @@ func TestShow(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() matches := []struct { diff --git a/cli/speedtest_test.go b/cli/speedtest_test.go index 3cb2956975525..9851dbeaee5e6 100644 --- a/cli/speedtest_test.go +++ b/cli/speedtest_test.go @@ -59,7 +59,7 @@ func TestSpeedtest(t *testing.T) { ctx = cli.ContextWithLogger(ctx, slogtest.Make(t, nil).Named("speedtest").Leveled(slog.LevelDebug)) cmdDone := tGo(t, func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err) }) <-cmdDone diff --git a/cli/ssh_test.go b/cli/ssh_test.go index 1fb13c0593d87..652adc3b48f42 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -98,7 +98,7 @@ func TestSSH(t *testing.T) { defer cancel() cmdDone := tGo(t, func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err) }) pty.ExpectMatch("Waiting") @@ -139,7 +139,7 @@ func TestSSH(t *testing.T) { defer cancel() cmdDone := tGo(t, func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.ErrorIs(t, err, cliui.Canceled) }) pty.ExpectMatch(wantURL) @@ -179,7 +179,7 @@ func TestSSH(t *testing.T) { cmd.SetOut(serverInput) cmd.SetErr(io.Discard) cmdDone := tGo(t, func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err) }) @@ -274,7 +274,7 @@ func TestSSH(t *testing.T) { cmd.SetOut(pty.Output()) cmd.SetErr(pty.Output()) cmdDone := tGo(t, func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err, "ssh command failed") }) @@ -477,7 +477,7 @@ Expire-Date: 0 cmd.SetOut(tpty.Output()) cmd.SetErr(tpty.Output()) cmdDone := tGo(t, func() { - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) assert.NoError(t, err, "ssh command failed") }) // Prevent the test from hanging if the asserts below kill the test diff --git a/cli/state_test.go b/cli/state_test.go index 5d05313eb5414..3eb79e31bf5e0 100644 --- a/cli/state_test.go +++ b/cli/state_test.go @@ -40,7 +40,7 @@ func TestStatePull(t *testing.T) { statefilePath := filepath.Join(t.TempDir(), "state") cmd, root := clitest.New(t, "state", "pull", workspace.Name, statefilePath) clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) gotState, err := os.ReadFile(statefilePath) require.NoError(t, err) @@ -69,7 +69,7 @@ func TestStatePull(t *testing.T) { var gotState bytes.Buffer cmd.SetOut(&gotState) clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) require.Equal(t, wantState, bytes.TrimSpace(gotState.Bytes())) }) @@ -98,7 +98,7 @@ func TestStatePush(t *testing.T) { require.NoError(t, err) cmd, root := clitest.New(t, "state", "push", workspace.Name, stateFile.Name()) clitest.SetupConfig(t, client, root) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) }) @@ -117,7 +117,7 @@ func TestStatePush(t *testing.T) { cmd, root := clitest.New(t, "state", "push", "--build", strconv.Itoa(int(workspace.LatestBuild.BuildNumber)), workspace.Name, "-") clitest.SetupConfig(t, client, root) cmd.SetIn(strings.NewReader("some magic state")) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) }) } diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index b9308854dc868..d2ddb1501dd53 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -63,7 +63,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -111,7 +111,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() require.NoError(t, <-execDone) @@ -134,7 +134,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -174,7 +174,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -213,7 +213,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -262,7 +262,7 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, args...) clitest.SetupConfig(t, client, root) - return cmd.Execute() + return cmd.Run() } del := func() error { args := []string{ @@ -274,7 +274,7 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, args...) clitest.SetupConfig(t, client, root) - return cmd.Execute() + return cmd.Run() } err := create() @@ -294,7 +294,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() require.EqualError(t, <-execDone, "Template name must be less than 32 characters") @@ -337,7 +337,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -393,7 +393,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -437,7 +437,7 @@ func TestTemplateCreate(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { diff --git a/cli/templatedelete_test.go b/cli/templatedelete_test.go index e2e404cf82a26..76c71fa4dc34d 100644 --- a/cli/templatedelete_test.go +++ b/cli/templatedelete_test.go @@ -36,7 +36,7 @@ func TestTemplateDelete(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(template.Name))) @@ -67,7 +67,7 @@ func TestTemplateDelete(t *testing.T) { cmd, root := clitest.New(t, append([]string{"templates", "delete", "--yes"}, templateNames...)...) clitest.SetupConfig(t, client, root) - require.NoError(t, cmd.Execute()) + require.NoError(t, cmd.Run()) for _, template := range templates { _, err := client.Template(context.Background(), template.ID) @@ -100,7 +100,7 @@ func TestTemplateDelete(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(strings.Join(templateNames, ", ")))) @@ -132,7 +132,7 @@ func TestTemplateDelete(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() pty.WriteLine("yes") diff --git a/cli/templateedit_test.go b/cli/templateedit_test.go index aa29aa2c3ea14..53414cf2ab8c8 100644 --- a/cli/templateedit_test.go +++ b/cli/templateedit_test.go @@ -59,7 +59,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) require.NoError(t, err) @@ -96,7 +96,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) require.ErrorContains(t, err, "not modified") @@ -129,7 +129,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) require.Error(t, err, "client call must fail") _, isSdkError := codersdk.AsError(err) @@ -179,7 +179,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) @@ -225,7 +225,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) diff --git a/cli/templateinit_test.go b/cli/templateinit_test.go index 46969ea7c287a..eb92e92e2a069 100644 --- a/cli/templateinit_test.go +++ b/cli/templateinit_test.go @@ -19,7 +19,7 @@ func TestTemplateInit(t *testing.T) { pty := ptytest.New(t) cmd.SetIn(pty.Input()) cmd.SetOut(pty.Output()) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) files, err := os.ReadDir(tempDir) require.NoError(t, err) diff --git a/cli/templatelist_test.go b/cli/templatelist_test.go index 841b1f0e2e15f..27b119b764922 100644 --- a/cli/templatelist_test.go +++ b/cli/templatelist_test.go @@ -42,7 +42,7 @@ func TestTemplateList(t *testing.T) { errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() // expect that templates are listed alphabetically @@ -75,7 +75,7 @@ func TestTemplateList(t *testing.T) { out := bytes.NewBuffer(nil) cmd.SetOut(out) - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) require.NoError(t, err) var templates []codersdk.Template @@ -99,7 +99,7 @@ func TestTemplateList(t *testing.T) { errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() require.NoError(t, <-errC) diff --git a/cli/templatepull_test.go b/cli/templatepull_test.go index 1fe1631d2328b..b3416491f24e6 100644 --- a/cli/templatepull_test.go +++ b/cli/templatepull_test.go @@ -47,7 +47,7 @@ func TestTemplatePull(t *testing.T) { t.Parallel() cmd, _ := clitest.New(t, "templates", "pull") - err := cmd.Execute() + err := cmd.Run() require.Error(t, err) }) @@ -83,7 +83,7 @@ func TestTemplatePull(t *testing.T) { var buf bytes.Buffer cmd.SetOut(&buf) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) require.True(t, bytes.Equal(expected, buf.Bytes()), "tar files differ") @@ -134,7 +134,7 @@ func TestTemplatePull(t *testing.T) { errChan := make(chan error) go func() { defer close(errChan) - errChan <- cmd.Execute() + errChan <- cmd.Run() }() require.NoError(t, <-errChan) @@ -200,7 +200,7 @@ func TestTemplatePull(t *testing.T) { errChan := make(chan error) go func() { defer close(errChan) - errChan <- cmd.Execute() + errChan <- cmd.Run() }() pty.ExpectMatch("not empty") diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go index 90af2d90ad75a..82db13d97f1bb 100644 --- a/cli/templatepush_test.go +++ b/cli/templatepush_test.go @@ -54,7 +54,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -82,7 +82,7 @@ func TestTemplatePush(t *testing.T) { cmd, root = clitest.New(t, "templates", "push", template.Name, "-y", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho)) clitest.SetupConfig(t, client, root) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() require.NoError(t, <-execDone) @@ -101,7 +101,7 @@ func TestTemplatePush(t *testing.T) { cmd, root = clitest.New(t, "templates", "push", template.Name, "-y", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho)) clitest.SetupConfig(t, client, root) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() require.NoError(t, <-execDone) // Assert template version changed and the param was removed @@ -133,7 +133,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -187,7 +187,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -239,7 +239,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() require.NoError(t, <-execDone) @@ -298,7 +298,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -357,7 +357,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -404,7 +404,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { @@ -464,7 +464,7 @@ func TestTemplatePush(t *testing.T) { execDone := make(chan error) go func() { - execDone <- cmd.Execute() + execDone <- cmd.Run() }() matches := []struct { diff --git a/cli/templateversions_test.go b/cli/templateversions_test.go index 750c718591788..50d993c5d8bda 100644 --- a/cli/templateversions_test.go +++ b/cli/templateversions_test.go @@ -29,7 +29,7 @@ func TestTemplateVersions(t *testing.T) { errC := make(chan error) go func() { - errC <- cmd.Execute() + errC <- cmd.Run() }() require.NoError(t, <-errC) diff --git a/cli/tokens_test.go b/cli/tokens_test.go index aaeacc75edfbd..52981b98cf5b7 100644 --- a/cli/tokens_test.go +++ b/cli/tokens_test.go @@ -28,7 +28,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf := new(bytes.Buffer) cmd.SetOut(buf) - err := cmd.ExecuteContext(ctx) + err := cmd.RunContext(ctx) require.NoError(t, err) res := buf.String() require.Contains(t, res, "tokens found") @@ -37,7 +37,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) res = buf.String() require.NotEmpty(t, res) @@ -51,7 +51,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) res = buf.String() require.NotEmpty(t, res) @@ -65,7 +65,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) var tokens []codersdk.APIKey @@ -77,7 +77,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.ExecuteContext(ctx) + err = cmd.RunContext(ctx) require.NoError(t, err) res = buf.String() require.NotEmpty(t, res) diff --git a/cli/update_test.go b/cli/update_test.go index ea57507f16f68..30cf9aec116ef 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -25,7 +25,7 @@ func TestUpdate(t *testing.T) { t.Parallel() cmd, _ := clitest.New(t, "update") - err := cmd.Execute() + err := cmd.Run() require.Error(t, err) }) @@ -46,7 +46,7 @@ func TestUpdate(t *testing.T) { ) clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) ws, err := client.WorkspaceByOwnerAndName(context.Background(), "testuser", "my-workspace", codersdk.WorkspaceOptions{}) @@ -68,7 +68,7 @@ func TestUpdate(t *testing.T) { cmd, root = clitest.New(t, "update", ws.Name) clitest.SetupConfig(t, client, root) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) ws, err = client.WorkspaceByOwnerAndName(context.Background(), "testuser", "my-workspace", codersdk.WorkspaceOptions{}) @@ -93,7 +93,7 @@ func TestUpdate(t *testing.T) { ) clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) ws, err := client.WorkspaceByOwnerAndName(context.Background(), "testuser", "my-workspace", codersdk.WorkspaceOptions{}) @@ -123,7 +123,7 @@ func TestUpdate(t *testing.T) { doneChan := make(chan struct{}) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -201,7 +201,7 @@ func TestUpdateWithRichParameters(t *testing.T) { cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y") clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) cmd, root = clitest.New(t, "update", "my-workspace", "--always-prompt") @@ -213,7 +213,7 @@ func TestUpdateWithRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -299,7 +299,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y") clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) cmd, root = clitest.New(t, "update", "my-workspace", "--always-prompt") @@ -310,7 +310,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -346,7 +346,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y") clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) cmd, root = clitest.New(t, "update", "my-workspace", "--always-prompt") @@ -357,7 +357,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -396,7 +396,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y") clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) cmd, root = clitest.New(t, "update", "my-workspace", "--always-prompt") @@ -407,7 +407,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() diff --git a/cli/usercreate_test.go b/cli/usercreate_test.go index 2bb0923b9fda9..cd3a8c820ab70 100644 --- a/cli/usercreate_test.go +++ b/cli/usercreate_test.go @@ -24,7 +24,7 @@ func TestUserCreate(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() matches := []string{ diff --git a/cli/userlist_test.go b/cli/userlist_test.go index 36cf17b188ac3..09d06e1f5f795 100644 --- a/cli/userlist_test.go +++ b/cli/userlist_test.go @@ -28,7 +28,7 @@ func TestUserList(t *testing.T) { cmd.SetOut(pty.Output()) errC := make(chan error) go func() { - errC <- cmd.Execute() + errC <- cmd.Run() }() require.NoError(t, <-errC) pty.ExpectMatch("coder.com") @@ -46,7 +46,7 @@ func TestUserList(t *testing.T) { cmd.SetOut(buf) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -63,7 +63,7 @@ func TestUserList(t *testing.T) { cmd, _ := clitest.New(t, "users", "list") - _, err := cmd.ExecuteC() + _, err := cmd.RunC() require.Contains(t, err.Error(), "Try logging in using 'coder login '.") }) @@ -74,7 +74,7 @@ func TestUserList(t *testing.T) { cmd, root := clitest.New(t, "users", "list") clitest.SetupConfig(t, client, root) - _, err := cmd.ExecuteC() + _, err := cmd.RunC() var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -98,7 +98,7 @@ func TestUserShow(t *testing.T) { cmd.SetOut(pty.Output()) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() pty.ExpectMatch(otherUser.Email) @@ -122,7 +122,7 @@ func TestUserShow(t *testing.T) { cmd.SetOut(buf) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() diff --git a/cli/userstatus_test.go b/cli/userstatus_test.go index 430fa501a6ee0..1c180a85f6462 100644 --- a/cli/userstatus_test.go +++ b/cli/userstatus_test.go @@ -26,7 +26,7 @@ func TestUserStatus(t *testing.T) { clitest.SetupConfig(t, client, root) // Yes to the prompt cmd.SetIn(bytes.NewReader([]byte("yes\n"))) - err := cmd.Execute() + err := cmd.Run() // Expect an error, as you cannot suspend yourself require.Error(t, err) require.ErrorContains(t, err, "cannot suspend yourself") @@ -39,7 +39,7 @@ func TestUserStatus(t *testing.T) { clitest.SetupConfig(t, client, root) // Yes to the prompt cmd.SetIn(bytes.NewReader([]byte("yes\n"))) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err, "suspend user") // Check the user status @@ -52,7 +52,7 @@ func TestUserStatus(t *testing.T) { clitest.SetupConfig(t, client, root) // Yes to the prompt cmd.SetIn(bytes.NewReader([]byte("yes\n"))) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err, "suspend user") // Check the user status diff --git a/cli/vscodessh_test.go b/cli/vscodessh_test.go index 605ce6a8234e0..3c27c2b57698e 100644 --- a/cli/vscodessh_test.go +++ b/cli/vscodessh_test.go @@ -56,7 +56,7 @@ func TestVSCodeSSH(t *testing.T) { done := make(chan struct{}) go func() { //nolint // The above seems reasonable for a one-off test. - err := cmd.ExecuteContext(context.WithValue(ctx, "fs", fs)) + err := cmd.RunContext(context.WithValue(ctx, "fs", fs)) if err != nil { assert.ErrorIs(t, err, context.Canceled) } diff --git a/enterprise/cli/features_test.go b/enterprise/cli/features_test.go index 1679ae86fffec..3aecd90460748 100644 --- a/enterprise/cli/features_test.go +++ b/enterprise/cli/features_test.go @@ -29,7 +29,7 @@ func TestFeaturesList(t *testing.T) { cmd.SetOut(pty.Output()) errC := make(chan error) go func() { - errC <- cmd.Execute() + errC <- cmd.Run() }() require.NoError(t, <-errC) pty.ExpectMatch("user_limit") @@ -48,7 +48,7 @@ func TestFeaturesList(t *testing.T) { cmd.SetOut(buf) go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() diff --git a/enterprise/cli/groupcreate_test.go b/enterprise/cli/groupcreate_test.go index 166214901b908..8de0843793adc 100644 --- a/enterprise/cli/groupcreate_test.go +++ b/enterprise/cli/groupcreate_test.go @@ -44,7 +44,7 @@ func TestCreateGroup(t *testing.T) { cmd.SetOut(pty.Output()) clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) pty.ExpectMatch(fmt.Sprintf("Successfully created group %s!", cliui.Styles.Keyword.Render(groupName))) diff --git a/enterprise/cli/groupdelete_test.go b/enterprise/cli/groupdelete_test.go index a997af603f5f4..4f5d819fdec29 100644 --- a/enterprise/cli/groupdelete_test.go +++ b/enterprise/cli/groupdelete_test.go @@ -47,7 +47,7 @@ func TestGroupDelete(t *testing.T) { cmd.SetOut(pty.Output()) clitest.SetupConfig(t, client, root) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) pty.ExpectMatch(fmt.Sprintf("Successfully deleted group %s", cliui.Styles.Keyword.Render(group.Name))) @@ -70,7 +70,7 @@ func TestGroupDelete(t *testing.T) { clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.Error(t, err) }) } diff --git a/enterprise/cli/groupedit_test.go b/enterprise/cli/groupedit_test.go index 61e06af8ba4c0..e452de66e9c81 100644 --- a/enterprise/cli/groupedit_test.go +++ b/enterprise/cli/groupedit_test.go @@ -65,7 +65,7 @@ func TestGroupEdit(t *testing.T) { cmd.SetOut(pty.Output()) clitest.SetupConfig(t, client, root) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) pty.ExpectMatch(fmt.Sprintf("Successfully patched group %s", cliui.Styles.Keyword.Render(expectedName))) @@ -97,7 +97,7 @@ func TestGroupEdit(t *testing.T) { clitest.SetupConfig(t, client, root) - err = cmd.Execute() + err = cmd.Run() require.Error(t, err) require.Contains(t, err.Error(), "must be a valid UUID or email address") }) @@ -118,7 +118,7 @@ func TestGroupEdit(t *testing.T) { clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.Error(t, err) }) } diff --git a/enterprise/cli/grouplist_test.go b/enterprise/cli/grouplist_test.go index e831ee938d0af..29dcbe659b5a9 100644 --- a/enterprise/cli/grouplist_test.go +++ b/enterprise/cli/grouplist_test.go @@ -64,7 +64,7 @@ func TestGroupList(t *testing.T) { cmd.SetOut(pty.Output()) clitest.SetupConfig(t, client, root) - err = cmd.Execute() + err = cmd.Run() require.NoError(t, err) matches := []string{ @@ -97,7 +97,7 @@ func TestGroupList(t *testing.T) { cmd.SetErr(pty.Output()) clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) pty.ExpectMatch("No groups found") diff --git a/enterprise/cli/licenses_test.go b/enterprise/cli/licenses_test.go index 47393406d2c3e..e1f1f8ee9c4ab 100644 --- a/enterprise/cli/licenses_test.go +++ b/enterprise/cli/licenses_test.go @@ -45,7 +45,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() require.NoError(t, <-errC) pty.ExpectMatch("License with ID 1 added") @@ -58,7 +58,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() pty.ExpectMatch("Paste license:") pty.WriteLine(fakeLicenseJWT) @@ -77,7 +77,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() require.NoError(t, <-errC) pty.ExpectMatch("License with ID 1 added") @@ -93,7 +93,7 @@ func TestLicensesAddFake(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() _, err := w.Write([]byte(fakeLicenseJWT)) require.NoError(t, err) @@ -115,7 +115,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() require.NoError(t, <-errC) pty.ExpectMatch("\"f2\": 2") @@ -136,7 +136,7 @@ func TestLicensesAddReal(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() err := <-errC var coderError *codersdk.Error @@ -159,7 +159,7 @@ func TestLicensesListFake(t *testing.T) { cmd.SetOut(stdout) errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() require.NoError(t, <-errC) var licenses []codersdk.License @@ -190,7 +190,7 @@ func TestLicensesListReal(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() require.NoError(t, <-errC) assert.Equal(t, "[]\n", stdout.String()) @@ -210,7 +210,7 @@ func TestLicensesDeleteFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() require.NoError(t, <-errC) pty.ExpectMatch("License with ID 55 deleted") @@ -230,7 +230,7 @@ func TestLicensesDeleteReal(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.ExecuteContext(ctx) + errC <- cmd.RunContext(ctx) }() err := <-errC var coderError *codersdk.Error From c9820fb5c2a17ce50cda2b5553a8187ea925bbac Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Tue, 7 Mar 2023 18:29:41 +0000 Subject: [PATCH 006/175] go mod tidy --- go.mod | 6 ++++++ go.sum | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 31fa7acc133f0..b4c58af803526 100644 --- a/go.mod +++ b/go.mod @@ -134,6 +134,7 @@ require ( github.com/spf13/afero v1.9.3 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.9.0 github.com/stretchr/testify v1.8.1 github.com/swaggo/http-swagger v1.3.3 github.com/swaggo/swag v1.8.6 @@ -181,15 +182,20 @@ require ( require ( github.com/dgraph-io/badger/v3 v3.2103.5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/google/flatbuffers v23.1.21+incompatible // indirect github.com/h2non/filetype v1.1.3 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/juju/errors v1.0.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-sqlite3 v1.14.15 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + gopkg.in/ini.v1 v1.66.2 // indirect ) require ( diff --git a/go.sum b/go.sum index c8ecccdab4ca9..a3f46088b7d3d 100644 --- a/go.sum +++ b/go.sum @@ -376,10 +376,10 @@ github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d h1:09JG37IgTB6n3ouX9 github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d/go.mod h1:r+1J5i/989wt6CUeNSuvFKKA9hHuKKPMxdzDbTuvwwk= github.com/coder/ssh v0.0.0-20220811105153-fcea99919338 h1:tN5GKFT68YLVzJoA8AHuiMNJ0qlhoD3pGN3JY9gxSko= github.com/coder/ssh v0.0.0-20220811105153-fcea99919338/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= -github.com/coder/tailscale v1.1.1-0.20230301203426-fb16ae7c5bba h1:JOD5pqNtiz9lkSX74PY2BJOyNqsBmvGUjFGIuECtG+o= -github.com/coder/tailscale v1.1.1-0.20230301203426-fb16ae7c5bba/go.mod h1:jpg+77g19FpXL43U1VoIqoSg1K/Vh5CVxycGldQ8KhA= -github.com/coder/terraform-provider-coder v0.6.14 h1:NsJ1mo0MN1x/VyNLYmsgPUYn2JgzdVNZBqnj9OSIDgY= -github.com/coder/terraform-provider-coder v0.6.14/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= +github.com/coder/tailscale v1.1.1-0.20230307022319-1e5e724a3949 h1:8WfMfRTDaEpnmhCJWfFQ7JHz19GyP+EgFgLGu5ngdek= +github.com/coder/tailscale v1.1.1-0.20230307022319-1e5e724a3949/go.mod h1:jpg+77g19FpXL43U1VoIqoSg1K/Vh5CVxycGldQ8KhA= +github.com/coder/terraform-provider-coder v0.6.15 h1:Llvh4RwxSQ/goy7ToTOeHf3tdEz+79qbyOh61hNnJs0= +github.com/coder/terraform-provider-coder v0.6.15/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -626,6 +626,8 @@ github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0X github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= @@ -1303,6 +1305,7 @@ github.com/mafredri/udp v0.1.2-0.20220805105907-b2872e92e98d h1:E+lU8/1jcUd3guqa github.com/mafredri/udp v0.1.2-0.20220805105907-b2872e92e98d/go.mod h1:GUd681aT3Tj7pdNkUtqBz5pp/GLMGIaMI9Obq6+ob48= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -1571,6 +1574,7 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= @@ -1770,6 +1774,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk= github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= @@ -1796,6 +1801,7 @@ github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggest/assertjson v1.7.0 h1:SKw5Rn0LQs6UvmGrIdaKQbMR1R3ncXm5KNon+QJ7jtw= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc= @@ -2421,6 +2427,7 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= @@ -2833,6 +2840,8 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= From 32a175998bc9775df25d5ba5bc6208854f24509f Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Tue, 7 Mar 2023 18:44:26 +0000 Subject: [PATCH 007/175] 330 problems left... * RunContext -> WithContext * Stdin/Stdout wiring --- cli/cliui/agent_test.go | 26 ++++++++-------- cli/create_test.go | 50 +++++++++++++++--------------- cli/delete_test.go | 12 +++---- cli/gitssh_test.go | 12 +++---- cli/list_test.go | 8 ++--- cli/ping_test.go | 6 ++-- cli/portforward_test.go | 28 ++++++++--------- cli/rename_test.go | 6 ++-- cli/resetpassword_test.go | 6 ++-- cli/restart_test.go | 6 ++-- cli/root_test.go | 2 +- cli/scaletest_test.go | 8 ++--- cli/schedule_test.go | 6 ++-- cli/show_test.go | 4 +-- cli/speedtest_test.go | 4 +-- cli/ssh_test.go | 22 ++++++------- cli/templatecreate_test.go | 30 +++++++++--------- cli/templatedelete_test.go | 12 +++---- cli/templateedit_test.go | 10 +++--- cli/templateinit_test.go | 4 +-- cli/templatelist_test.go | 12 +++---- cli/templatepull_test.go | 8 ++--- cli/templatepush_test.go | 30 +++++++++--------- cli/templateversions_test.go | 4 +-- cli/tokens_test.go | 10 +++--- cli/update_test.go | 28 ++++++++--------- cli/usercreate_test.go | 4 +-- cli/userlist_test.go | 8 ++--- enterprise/cli/features_test.go | 4 +-- enterprise/cli/groupcreate_test.go | 2 +- enterprise/cli/groupdelete_test.go | 2 +- enterprise/cli/groupedit_test.go | 2 +- enterprise/cli/grouplist_test.go | 2 +- enterprise/cli/licenses_test.go | 24 +++++++------- 34 files changed, 201 insertions(+), 201 deletions(-) diff --git a/cli/cliui/agent_test.go b/cli/cliui/agent_test.go index 01567548742b4..10ca945a07ee9 100644 --- a/cli/cliui/agent_test.go +++ b/cli/cliui/agent_test.go @@ -96,7 +96,7 @@ func TestAgent_TimeoutWithTroubleshootingURL(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.RunContext(ctx) + done <- cmd.WithContext(ctx).Run() }() ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") timeout.Store(true) @@ -149,7 +149,7 @@ func TestAgent_StartupTimeout(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.RunContext(ctx) + done <- cmd.WithContext(ctx).Run() }() setStatus(codersdk.WorkspaceAgentConnecting) ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") @@ -207,7 +207,7 @@ func TestAgent_StartErrorExit(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.RunContext(ctx) + done <- cmd.WithContext(ctx).Run() }() setStatus(codersdk.WorkspaceAgentConnected) setState(codersdk.WorkspaceAgentLifecycleStarting) @@ -262,7 +262,7 @@ func TestAgent_NoWait(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.RunContext(ctx) + done <- cmd.WithContext(ctx).Run() }() setStatus(codersdk.WorkspaceAgentConnecting) ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") @@ -271,19 +271,19 @@ func TestAgent_NoWait(t *testing.T) { require.NoError(t, <-done, "created - should exit early") setState(codersdk.WorkspaceAgentLifecycleStarting) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "starting - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartTimeout) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "start timeout - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartError) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "start error - should exit early") setState(codersdk.WorkspaceAgentLifecycleReady) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "ready - should exit early") } @@ -331,7 +331,7 @@ func TestAgent_LoginBeforeReadyEnabled(t *testing.T) { cmd.SetIn(ptty.Input()) done := make(chan error, 1) go func() { - done <- cmd.RunContext(ctx) + done <- cmd.WithContext(ctx).Run() }() setStatus(codersdk.WorkspaceAgentConnecting) ptty.ExpectMatchContext(ctx, "Don't panic, your workspace is booting") @@ -340,18 +340,18 @@ func TestAgent_LoginBeforeReadyEnabled(t *testing.T) { require.NoError(t, <-done, "created - should exit early") setState(codersdk.WorkspaceAgentLifecycleStarting) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "starting - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartTimeout) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "start timeout - should exit early") setState(codersdk.WorkspaceAgentLifecycleStartError) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "start error - should exit early") setState(codersdk.WorkspaceAgentLifecycleReady) - go func() { done <- cmd.RunContext(ctx) }() + go func() { done <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-done, "ready - should exit early") } diff --git a/cli/create_test.go b/cli/create_test.go index dabfeba5aa634..836815212d06e 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -49,8 +49,8 @@ func TestCreate(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -98,7 +98,7 @@ func TestCreate(t *testing.T) { cmdCtx, done := context.WithTimeout(context.Background(), testutil.WaitLong) go func() { defer done() - err := cmd.RunContext(cmdCtx) + err := cmd.WithContext(cmdCtx).Run() assert.NoError(t, err) }() // No pty interaction needed since we use the -y skip prompt flag @@ -117,8 +117,8 @@ func TestCreate(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -161,8 +161,8 @@ func TestCreate(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -206,8 +206,8 @@ func TestCreate(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -251,8 +251,8 @@ func TestCreate(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -318,8 +318,8 @@ func TestCreate(t *testing.T) { cmd, root := clitest.New(t, "create", "test", "--parameter-file", parameterFile.Name()) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() err = cmd.Run() require.Error(t, err) @@ -380,8 +380,8 @@ func TestCreateWithRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -425,8 +425,8 @@ func TestCreateWithRichParameters(t *testing.T) { doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -508,8 +508,8 @@ func TestCreateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -545,8 +545,8 @@ func TestCreateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -585,8 +585,8 @@ func TestCreateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -647,8 +647,8 @@ func TestCreateWithGitAuth(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() diff --git a/cli/delete_test.go b/cli/delete_test.go index ac3af8d9c5f83..dacf55e9bd488 100644 --- a/cli/delete_test.go +++ b/cli/delete_test.go @@ -29,8 +29,8 @@ func TestDelete(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -57,8 +57,8 @@ func TestDelete(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) go func() { defer close(doneChan) @@ -91,8 +91,8 @@ func TestDelete(t *testing.T) { clitest.SetupConfig(t, adminClient, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() diff --git a/cli/gitssh_test.go b/cli/gitssh_test.go index 328939a1155b2..bc499c9ced628 100644 --- a/cli/gitssh_test.go +++ b/cli/gitssh_test.go @@ -78,7 +78,7 @@ func prepareTestGitSSH(ctx context.Context, t *testing.T) (*codersdk.Client, str errC := make(chan error, 1) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() t.Cleanup(func() { require.NoError(t, <-errC) }) coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) @@ -166,7 +166,7 @@ func TestGitSSH(t *testing.T) { "-o", "IdentitiesOnly=yes", "127.0.0.1", ) - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() require.NoError(t, err) require.EqualValues(t, 1, inc) @@ -229,9 +229,9 @@ func TestGitSSH(t *testing.T) { } // Test authentication via local private key. cmd, _ := clitest.New(t, cmdArgs...) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) select { case key := <-authkey: @@ -246,9 +246,9 @@ func TestGitSSH(t *testing.T) { // With the local file deleted, the coder key should be used. cmd, _ = clitest.New(t, cmdArgs...) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) select { case key := <-authkey: diff --git a/cli/list_test.go b/cli/list_test.go index 7186530ef233e..9876439be6429 100644 --- a/cli/list_test.go +++ b/cli/list_test.go @@ -30,14 +30,14 @@ func TestList(t *testing.T) { cmd, root := clitest.New(t, "ls") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancelFunc() done := make(chan any) go func() { - errC := cmd.RunContext(ctx) + errC := cmd.WithContext(ctx).Run() assert.NoError(t, errC) close(done) }() @@ -65,7 +65,7 @@ func TestList(t *testing.T) { out := bytes.NewBuffer(nil) cmd.SetOut(out) - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() require.NoError(t, err) var templates []codersdk.Workspace diff --git a/cli/ping_test.go b/cli/ping_test.go index 996bd995c4d88..b1fd995551844 100644 --- a/cli/ping_test.go +++ b/cli/ping_test.go @@ -25,9 +25,9 @@ func TestPing(t *testing.T) { cmd, root := clitest.New(t, "ping", workspace.Name) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) + cmd.Stdin = pty.Input() cmd.SetErr(pty.Output()) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() agentClient := agentsdk.New(client.URL) agentClient.SetSessionToken(agentToken) @@ -43,7 +43,7 @@ func TestPing(t *testing.T) { defer cancel() cmdDone := tGo(t, func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err) }) diff --git a/cli/portforward_test.go b/cli/portforward_test.go index 22d3aef3410cd..0ee5e0bbe1f94 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -35,8 +35,8 @@ func TestPortForward(t *testing.T) { cmd, root := clitest.New(t, "port-forward", "blah") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) err := cmd.Run() @@ -137,14 +137,14 @@ func TestPortForward(t *testing.T) { cmd, root := clitest.New(t, "-v", "port-forward", workspace.Name, flag) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) ctx, cancel := context.WithCancel(context.Background()) defer cancel() errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() pty.ExpectMatch("Ready!") @@ -185,14 +185,14 @@ func TestPortForward(t *testing.T) { cmd, root := clitest.New(t, "-v", "port-forward", workspace.Name, flag1, flag2) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) ctx, cancel := context.WithCancel(context.Background()) defer cancel() errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() pty.ExpectMatch("Ready!") @@ -242,14 +242,14 @@ func TestPortForward(t *testing.T) { cmd, root := clitest.New(t, append([]string{"-v", "port-forward", workspace.Name}, flags...)...) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) ctx, cancel := context.WithCancel(context.Background()) defer cancel() errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() pty.ExpectMatch("Ready!") @@ -322,8 +322,8 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) codersdk. cmd, root := clitest.New(t, "agent", "--agent-token", agentToken, "--agent-url", client.URL.String()) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) errC := make(chan error) agentCtx, agentCancel := context.WithCancel(ctx) @@ -333,7 +333,7 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) codersdk. require.NoError(t, err) }) go func() { - errC <- cmd.RunContext(agentCtx) + errC <- cmd.WithContext(agentCtx).Run() }() coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) diff --git a/cli/rename_test.go b/cli/rename_test.go index 5e1927d51257b..2b43a16901055 100644 --- a/cli/rename_test.go +++ b/cli/rename_test.go @@ -33,12 +33,12 @@ func TestRename(t *testing.T) { cmd, root := clitest.New(t, "rename", workspace.Name, want, "--yes") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() errC := make(chan error, 1) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() pty.ExpectMatch("confirm rename:") diff --git a/cli/resetpassword_test.go b/cli/resetpassword_test.go index b871f25564e99..ecd16676623b5 100644 --- a/cli/resetpassword_test.go +++ b/cli/resetpassword_test.go @@ -46,7 +46,7 @@ func TestResetPassword(t *testing.T) { ) go func() { defer close(serverDone) - err = servercmd.RunContext(ctx) + err = servercmd.WithContext(ctx).Run() assert.NoError(t, err) }() var rawURL string @@ -71,8 +71,8 @@ func TestResetPassword(t *testing.T) { clitest.SetupConfig(t, client, cmdCfg) cmdDone := make(chan struct{}) pty := ptytest.New(t) - resetCmd.SetIn(pty.Input()) - resetCmd.SetOut(pty.Output()) + resetcmd.Stdin = pty.Input() + resetcmd.Stdout = pty.Output() go func() { defer close(cmdDone) err = resetcmd.Run() diff --git a/cli/restart_test.go b/cli/restart_test.go index 0cca73bb4861c..714aa915abc4f 100644 --- a/cli/restart_test.go +++ b/cli/restart_test.go @@ -31,12 +31,12 @@ func TestRestart(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() done := make(chan error, 1) go func() { - done <- cmd.RunContext(ctx) + done <- cmd.WithContext(ctx).Run() }() pty.ExpectMatch("Stopping workspace") pty.ExpectMatch("Starting workspace") diff --git a/cli/root_test.go b/cli/root_test.go index b2eb783091787..897e60043a08c 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -132,7 +132,7 @@ ExtractCommandPathsLoop: clitest.SetupConfig(t, rootClient, cfg) cmd.SetOut(&buf) assert.NoError(t, err) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() err2 := os.Chdir(wd) require.NoError(t, err) require.NoError(t, err2) diff --git a/cli/scaletest_test.go b/cli/scaletest_test.go index 914e74ec44038..9069be8ca53a6 100644 --- a/cli/scaletest_test.go +++ b/cli/scaletest_test.go @@ -77,12 +77,12 @@ param3: 1 ) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) done := make(chan any) go func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err) close(done) }() @@ -155,12 +155,12 @@ param3: 1 ) clitest.SetupConfig(t, client, root) pty = ptytest.New(t) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) done = make(chan any) go func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err) close(done) }() diff --git a/cli/schedule_test.go b/cli/schedule_test.go index 3daab5cf177df..6bcdd249e8140 100644 --- a/cli/schedule_test.go +++ b/cli/schedule_test.go @@ -252,7 +252,7 @@ func TestScheduleOverride(t *testing.T) { cmd.SetOut(stdoutBuf) // When: we execute `coder schedule override workspace ` - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) // Then: the deadline of the latest build is updated assuming the units are minutes @@ -292,7 +292,7 @@ func TestScheduleOverride(t *testing.T) { cmd.SetOut(stdoutBuf) // When: we execute `coder bump workspace ` - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() // Then: the command fails require.ErrorContains(t, err, "invalid duration") }) @@ -344,7 +344,7 @@ func TestScheduleOverride(t *testing.T) { cmd.SetOut(stdoutBuf) // When: we execute `coder bump workspace`` - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.Error(t, err) // Then: nothing happens and the deadline remains unset diff --git a/cli/show_test.go b/cli/show_test.go index 2709cc189d8f0..dcf2a9a27436b 100644 --- a/cli/show_test.go +++ b/cli/show_test.go @@ -35,8 +35,8 @@ func TestShow(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() diff --git a/cli/speedtest_test.go b/cli/speedtest_test.go index 9851dbeaee5e6..15c521df48d50 100644 --- a/cli/speedtest_test.go +++ b/cli/speedtest_test.go @@ -51,7 +51,7 @@ func TestSpeedtest(t *testing.T) { cmd, root := clitest.New(t, "speedtest", workspace.Name) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) ctx, cancel = context.WithTimeout(context.Background(), testutil.WaitLong) @@ -59,7 +59,7 @@ func TestSpeedtest(t *testing.T) { ctx = cli.ContextWithLogger(ctx, slogtest.Make(t, nil).Named("speedtest").Leveled(slog.LevelDebug)) cmdDone := tGo(t, func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err) }) <-cmdDone diff --git a/cli/ssh_test.go b/cli/ssh_test.go index 652adc3b48f42..45fd82ac66111 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -90,15 +90,15 @@ func TestSSH(t *testing.T) { cmd, root := clitest.New(t, "ssh", workspace.Name) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) + cmd.Stdin = pty.Input() cmd.SetErr(pty.Output()) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() cmdDone := tGo(t, func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err) }) pty.ExpectMatch("Waiting") @@ -131,15 +131,15 @@ func TestSSH(t *testing.T) { cmd, root := clitest.New(t, "ssh", workspace.Name) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) + cmd.Stdin = pty.Input() cmd.SetErr(pty.Output()) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() cmdDone := tGo(t, func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.ErrorIs(t, err, cliui.Canceled) }) pty.ExpectMatch(wantURL) @@ -179,7 +179,7 @@ func TestSSH(t *testing.T) { cmd.SetOut(serverInput) cmd.SetErr(io.Discard) cmdDone := tGo(t, func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err) }) @@ -270,11 +270,11 @@ func TestSSH(t *testing.T) { ) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() cmd.SetErr(pty.Output()) cmdDone := tGo(t, func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err, "ssh command failed") }) @@ -477,7 +477,7 @@ Expire-Date: 0 cmd.SetOut(tpty.Output()) cmd.SetErr(tpty.Output()) cmdDone := tGo(t, func() { - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() assert.NoError(t, err, "ssh command failed") }) // Prevent the test from hanging if the asserts below kill the test diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index d2ddb1501dd53..7294fcb4fb8c0 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -58,8 +58,8 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, args...) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -107,7 +107,7 @@ func TestTemplateCreate(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) cmd.SetIn(bytes.NewReader(source)) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -129,8 +129,8 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, "templates", "create", "my-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho)) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -169,8 +169,8 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, "templates", "create", "my-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--parameter-file", parameterFile.Name()) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -208,8 +208,8 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, "templates", "create", "my-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--parameter-file", parameterFile.Name()) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -332,8 +332,8 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, "templates", "create", "my-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--variables-file", variablesFile.Name()) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -388,8 +388,8 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, "templates", "create", "my-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--variables-file", variablesFile.Name()) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -432,8 +432,8 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, "templates", "create", "my-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--variable", "first_variable=foobar") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { diff --git a/cli/templatedelete_test.go b/cli/templatedelete_test.go index 76c71fa4dc34d..9ebb078d5eaba 100644 --- a/cli/templatedelete_test.go +++ b/cli/templatedelete_test.go @@ -31,8 +31,8 @@ func TestTemplateDelete(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -95,8 +95,8 @@ func TestTemplateDelete(t *testing.T) { cmd, root := clitest.New(t, append([]string{"templates", "delete"}, templateNames...)...) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -127,8 +127,8 @@ func TestTemplateDelete(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { diff --git a/cli/templateedit_test.go b/cli/templateedit_test.go index 53414cf2ab8c8..a3c9a00c07e97 100644 --- a/cli/templateedit_test.go +++ b/cli/templateedit_test.go @@ -59,7 +59,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() require.NoError(t, err) @@ -96,7 +96,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() require.ErrorContains(t, err, "not modified") @@ -129,7 +129,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() require.Error(t, err, "client call must fail") _, isSdkError := codersdk.AsError(err) @@ -179,7 +179,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) @@ -225,7 +225,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) diff --git a/cli/templateinit_test.go b/cli/templateinit_test.go index eb92e92e2a069..7f5ab19b59056 100644 --- a/cli/templateinit_test.go +++ b/cli/templateinit_test.go @@ -17,8 +17,8 @@ func TestTemplateInit(t *testing.T) { tempDir := t.TempDir() cmd, _ := clitest.New(t, "templates", "init", tempDir) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() err := cmd.Run() require.NoError(t, err) files, err := os.ReadDir(tempDir) diff --git a/cli/templatelist_test.go b/cli/templatelist_test.go index 27b119b764922..ab5c1d784aa1d 100644 --- a/cli/templatelist_test.go +++ b/cli/templatelist_test.go @@ -34,15 +34,15 @@ func TestTemplateList(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancelFunc() errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() // expect that templates are listed alphabetically @@ -75,7 +75,7 @@ func TestTemplateList(t *testing.T) { out := bytes.NewBuffer(nil) cmd.SetOut(out) - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() require.NoError(t, err) var templates []codersdk.Template @@ -91,7 +91,7 @@ func TestTemplateList(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) + cmd.Stdin = pty.Input() cmd.SetErr(pty.Output()) ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -99,7 +99,7 @@ func TestTemplateList(t *testing.T) { errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-errC) diff --git a/cli/templatepull_test.go b/cli/templatepull_test.go index b3416491f24e6..6a47640c00cb8 100644 --- a/cli/templatepull_test.go +++ b/cli/templatepull_test.go @@ -128,8 +128,8 @@ func TestTemplatePull(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() errChan := make(chan error) go func() { @@ -194,8 +194,8 @@ func TestTemplatePull(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() errChan := make(chan error) go func() { diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go index 82db13d97f1bb..3ccd9a94a3c30 100644 --- a/cli/templatepush_test.go +++ b/cli/templatepush_test.go @@ -49,8 +49,8 @@ func TestTemplatePush(t *testing.T) { cmd, root := clitest.New(t, "templates", "push", template.Name, "-y", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho)) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -128,8 +128,8 @@ func TestTemplatePush(t *testing.T) { cmd, root := clitest.New(t, "templates", "push", template.Name, "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -182,8 +182,8 @@ func TestTemplatePush(t *testing.T) { cmd, root := clitest.New(t, "templates", "push", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho)) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -235,7 +235,7 @@ func TestTemplatePush(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) cmd.SetIn(bytes.NewReader(source)) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -293,8 +293,8 @@ func TestTemplatePush(t *testing.T) { cmd, root := clitest.New(t, "templates", "push", template.Name, "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example", "--variables-file", variablesFile.Name()) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -352,8 +352,8 @@ func TestTemplatePush(t *testing.T) { cmd, root := clitest.New(t, "templates", "push", template.Name, "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -399,8 +399,8 @@ func TestTemplatePush(t *testing.T) { cmd, root := clitest.New(t, "templates", "push", template.Name, "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { @@ -459,8 +459,8 @@ func TestTemplatePush(t *testing.T) { cmd, root := clitest.New(t, "templates", "push", template.Name, "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example", "--variable", "second_variable=foobar") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() execDone := make(chan error) go func() { diff --git a/cli/templateversions_test.go b/cli/templateversions_test.go index 50d993c5d8bda..9778d721c5fb6 100644 --- a/cli/templateversions_test.go +++ b/cli/templateversions_test.go @@ -24,8 +24,8 @@ func TestTemplateVersions(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() errC := make(chan error) go func() { diff --git a/cli/tokens_test.go b/cli/tokens_test.go index 52981b98cf5b7..41e5b6342c498 100644 --- a/cli/tokens_test.go +++ b/cli/tokens_test.go @@ -28,7 +28,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf := new(bytes.Buffer) cmd.SetOut(buf) - err := cmd.RunContext(ctx) + err := cmd.WithContext(ctx).Run() require.NoError(t, err) res := buf.String() require.Contains(t, res, "tokens found") @@ -37,7 +37,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) res = buf.String() require.NotEmpty(t, res) @@ -51,7 +51,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) res = buf.String() require.NotEmpty(t, res) @@ -65,7 +65,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) var tokens []codersdk.APIKey @@ -77,7 +77,7 @@ func TestTokens(t *testing.T) { clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) cmd.SetOut(buf) - err = cmd.RunContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) res = buf.String() require.NotEmpty(t, res) diff --git a/cli/update_test.go b/cli/update_test.go index 30cf9aec116ef..27028baf6a121 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -117,8 +117,8 @@ func TestUpdate(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() doneChan := make(chan struct{}) go func() { @@ -209,8 +209,8 @@ func TestUpdateWithRichParameters(t *testing.T) { doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -306,8 +306,8 @@ func TestUpdateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -353,8 +353,8 @@ func TestUpdateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -403,8 +403,8 @@ func TestUpdateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() @@ -471,8 +471,8 @@ func TestUpdateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Execute() @@ -542,8 +542,8 @@ func TestUpdateValidateRichParameters(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Execute() diff --git a/cli/usercreate_test.go b/cli/usercreate_test.go index cd3a8c820ab70..df74072c21015 100644 --- a/cli/usercreate_test.go +++ b/cli/usercreate_test.go @@ -20,8 +20,8 @@ func TestUserCreate(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() diff --git a/cli/userlist_test.go b/cli/userlist_test.go index 09d06e1f5f795..f96f15459528c 100644 --- a/cli/userlist_test.go +++ b/cli/userlist_test.go @@ -24,8 +24,8 @@ func TestUserList(t *testing.T) { cmd, root := clitest.New(t, "users", "list") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() errC := make(chan error) go func() { errC <- cmd.Run() @@ -94,8 +94,8 @@ func TestUserShow(t *testing.T) { clitest.SetupConfig(t, client, root) doneChan := make(chan struct{}) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() go func() { defer close(doneChan) err := cmd.Run() diff --git a/enterprise/cli/features_test.go b/enterprise/cli/features_test.go index 3aecd90460748..eeb663e997495 100644 --- a/enterprise/cli/features_test.go +++ b/enterprise/cli/features_test.go @@ -25,8 +25,8 @@ func TestFeaturesList(t *testing.T) { cmd, root := clitest.NewWithSubcommands(t, cli.EnterpriseSubcommands(), "features", "list") clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() errC := make(chan error) go func() { errC <- cmd.Run() diff --git a/enterprise/cli/groupcreate_test.go b/enterprise/cli/groupcreate_test.go index 8de0843793adc..99edbeb3bcfcf 100644 --- a/enterprise/cli/groupcreate_test.go +++ b/enterprise/cli/groupcreate_test.go @@ -41,7 +41,7 @@ func TestCreateGroup(t *testing.T) { ) pty := ptytest.New(t) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() clitest.SetupConfig(t, client, root) err := cmd.Run() diff --git a/enterprise/cli/groupdelete_test.go b/enterprise/cli/groupdelete_test.go index 4f5d819fdec29..218e594686b9c 100644 --- a/enterprise/cli/groupdelete_test.go +++ b/enterprise/cli/groupdelete_test.go @@ -44,7 +44,7 @@ func TestGroupDelete(t *testing.T) { pty := ptytest.New(t) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() clitest.SetupConfig(t, client, root) err = cmd.Run() diff --git a/enterprise/cli/groupedit_test.go b/enterprise/cli/groupedit_test.go index e452de66e9c81..a5cb2444ec8d7 100644 --- a/enterprise/cli/groupedit_test.go +++ b/enterprise/cli/groupedit_test.go @@ -62,7 +62,7 @@ func TestGroupEdit(t *testing.T) { pty := ptytest.New(t) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() clitest.SetupConfig(t, client, root) err = cmd.Run() diff --git a/enterprise/cli/grouplist_test.go b/enterprise/cli/grouplist_test.go index 29dcbe659b5a9..959613711410a 100644 --- a/enterprise/cli/grouplist_test.go +++ b/enterprise/cli/grouplist_test.go @@ -61,7 +61,7 @@ func TestGroupList(t *testing.T) { pty := ptytest.New(t) - cmd.SetOut(pty.Output()) + cmd.Stdout = pty.Output() clitest.SetupConfig(t, client, root) err = cmd.Run() diff --git a/enterprise/cli/licenses_test.go b/enterprise/cli/licenses_test.go index e1f1f8ee9c4ab..556dd7224700e 100644 --- a/enterprise/cli/licenses_test.go +++ b/enterprise/cli/licenses_test.go @@ -45,7 +45,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-errC) pty.ExpectMatch("License with ID 1 added") @@ -58,7 +58,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() pty.ExpectMatch("Paste license:") pty.WriteLine(fakeLicenseJWT) @@ -77,7 +77,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-errC) pty.ExpectMatch("License with ID 1 added") @@ -93,7 +93,7 @@ func TestLicensesAddFake(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() _, err := w.Write([]byte(fakeLicenseJWT)) require.NoError(t, err) @@ -115,7 +115,7 @@ func TestLicensesAddFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-errC) pty.ExpectMatch("\"f2\": 2") @@ -136,7 +136,7 @@ func TestLicensesAddReal(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() err := <-errC var coderError *codersdk.Error @@ -159,7 +159,7 @@ func TestLicensesListFake(t *testing.T) { cmd.SetOut(stdout) errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-errC) var licenses []codersdk.License @@ -190,7 +190,7 @@ func TestLicensesListReal(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-errC) assert.Equal(t, "[]\n", stdout.String()) @@ -210,7 +210,7 @@ func TestLicensesDeleteFake(t *testing.T) { pty := attachPty(t, cmd) errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() require.NoError(t, <-errC) pty.ExpectMatch("License with ID 55 deleted") @@ -230,7 +230,7 @@ func TestLicensesDeleteReal(t *testing.T) { defer cancel() errC := make(chan error) go func() { - errC <- cmd.RunContext(ctx) + errC <- cmd.WithContext(ctx).Run() }() err := <-errC var coderError *codersdk.Error @@ -254,8 +254,8 @@ func setupFakeLicenseServerTest(t *testing.T, args ...string) *cobra.Command { func attachPty(t *testing.T, cmd *cobra.Command) *ptytest.PTY { pty := ptytest.New(t) - cmd.SetIn(pty.Input()) - cmd.SetOut(pty.Output()) + cmd.Stdin = pty.Input() + cmd.Stdout = pty.Output() return pty } From 5af114242eb7c147e3300a9b3a77f15d9b2d4a4b Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Tue, 7 Mar 2023 18:50:29 +0000 Subject: [PATCH 008/175] 208 problems left... * More stdio wiring --- cli/cliui/agent_test.go | 12 ++--- cli/cliui/gitauth_test.go | 2 +- cli/cliui/prompt_test.go | 6 +-- cli/cliui/provisionerjob_test.go | 2 +- cli/cliui/select_test.go | 4 +- cli/delete_test.go | 2 +- cli/gitssh_test.go | 4 +- cli/list_test.go | 2 +- cli/login_test.go | 42 +++++++++--------- cli/logout_test.go | 36 +++++++-------- cli/ping_test.go | 2 +- cli/portforward_test.go | 10 ++--- cli/publickey_test.go | 2 +- cli/root_test.go | 6 +-- cli/scaletest_test.go | 4 +- cli/schedule_test.go | 20 ++++----- cli/server_createadminuser_test.go | 16 +++---- cli/server_test.go | 70 +++++++++++++++--------------- cli/speedtest_test.go | 2 +- cli/ssh_test.go | 18 ++++---- cli/state_test.go | 4 +- cli/templatecreate_test.go | 2 +- cli/templateedit_test.go | 6 +-- cli/templatelist_test.go | 4 +- cli/templatepull_test.go | 2 +- cli/templatepush_test.go | 2 +- cli/tokens_test.go | 10 ++--- cli/update_test.go | 8 ++-- cli/userlist_test.go | 4 +- cli/userstatus_test.go | 6 +-- enterprise/cli/features_test.go | 2 +- enterprise/cli/grouplist_test.go | 2 +- enterprise/cli/licenses_test.go | 10 ++--- 33 files changed, 162 insertions(+), 162 deletions(-) diff --git a/cli/cliui/agent_test.go b/cli/cliui/agent_test.go index 10ca945a07ee9..181809f4a2a9d 100644 --- a/cli/cliui/agent_test.go +++ b/cli/cliui/agent_test.go @@ -46,7 +46,7 @@ func TestAgent(t *testing.T) { }, } cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan struct{}) go func() { defer close(done) @@ -93,7 +93,7 @@ func TestAgent_TimeoutWithTroubleshootingURL(t *testing.T) { } ptty := ptytest.New(t) cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { done <- cmd.WithContext(ctx).Run() @@ -146,7 +146,7 @@ func TestAgent_StartupTimeout(t *testing.T) { ptty := ptytest.New(t) cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { done <- cmd.WithContext(ctx).Run() @@ -204,7 +204,7 @@ func TestAgent_StartErrorExit(t *testing.T) { ptty := ptytest.New(t) cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { done <- cmd.WithContext(ctx).Run() @@ -259,7 +259,7 @@ func TestAgent_NoWait(t *testing.T) { ptty := ptytest.New(t) cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { done <- cmd.WithContext(ctx).Run() @@ -328,7 +328,7 @@ func TestAgent_LoginBeforeReadyEnabled(t *testing.T) { ptty := ptytest.New(t) cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { done <- cmd.WithContext(ctx).Run() diff --git a/cli/cliui/gitauth_test.go b/cli/cliui/gitauth_test.go index 96b615b4d9c9b..3b59077588d71 100644 --- a/cli/cliui/gitauth_test.go +++ b/cli/cliui/gitauth_test.go @@ -41,7 +41,7 @@ func TestGitAuth(t *testing.T) { }, } cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan struct{}) go func() { defer close(done) diff --git a/cli/cliui/prompt_test.go b/cli/cliui/prompt_test.go index dfea75b1dd347..6ed029d4bd646 100644 --- a/cli/cliui/prompt_test.go +++ b/cli/cliui/prompt_test.go @@ -158,9 +158,9 @@ func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions, cmdOpt func(cmd *cob if cmdOpt != nil { cmdOpt(cmd) } - cmd.SetOut(ptty.Output()) - cmd.SetErr(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdout = ptty.Output() + cmd.Stderr = ptty.Output() + cmd.Stdin = ptty.Input() return value, cmd.RunContext(context.Background()) } diff --git a/cli/cliui/provisionerjob_test.go b/cli/cliui/provisionerjob_test.go index 5009f074577d0..4082c63e713a1 100644 --- a/cli/cliui/provisionerjob_test.go +++ b/cli/cliui/provisionerjob_test.go @@ -147,7 +147,7 @@ func newProvisionerJob(t *testing.T) provisionerJobTest { } ptty := ptytest.New(t) cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() done := make(chan struct{}) go func() { defer close(done) diff --git a/cli/cliui/select_test.go b/cli/cliui/select_test.go index 4c05cab7aa1e5..5760055777ce6 100644 --- a/cli/cliui/select_test.go +++ b/cli/cliui/select_test.go @@ -40,7 +40,7 @@ func newSelect(ptty *ptytest.PTY, opts cliui.SelectOptions) (string, error) { }, } cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() return value, cmd.RunContext(context.Background()) } @@ -83,6 +83,6 @@ func newRichSelect(ptty *ptytest.PTY, opts cliui.RichSelectOptions) (string, err }, } cmd.SetOutput(ptty.Output()) - cmd.SetIn(ptty.Input()) + cmd.Stdin = ptty.Input() return value, cmd.RunContext(context.Background()) } diff --git a/cli/delete_test.go b/cli/delete_test.go index dacf55e9bd488..caece5446e1c2 100644 --- a/cli/delete_test.go +++ b/cli/delete_test.go @@ -59,7 +59,7 @@ func TestDelete(t *testing.T) { pty := ptytest.New(t) cmd.Stdin = pty.Input() cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() go func() { defer close(doneChan) err := cmd.Run() diff --git a/cli/gitssh_test.go b/cli/gitssh_test.go index bc499c9ced628..d5e7fdc83301c 100644 --- a/cli/gitssh_test.go +++ b/cli/gitssh_test.go @@ -230,7 +230,7 @@ func TestGitSSH(t *testing.T) { // Test authentication via local private key. cmd, _ := clitest.New(t, cmdArgs...) cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() err = cmd.WithContext(ctx).Run() require.NoError(t, err) select { @@ -247,7 +247,7 @@ func TestGitSSH(t *testing.T) { // With the local file deleted, the coder key should be used. cmd, _ = clitest.New(t, cmdArgs...) cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() err = cmd.WithContext(ctx).Run() require.NoError(t, err) select { diff --git a/cli/list_test.go b/cli/list_test.go index 9876439be6429..58fc5f7efbd8a 100644 --- a/cli/list_test.go +++ b/cli/list_test.go @@ -64,7 +64,7 @@ func TestList(t *testing.T) { defer cancelFunc() out := bytes.NewBuffer(nil) - cmd.SetOut(out) + cmd.Stdout = out err := cmd.WithContext(ctx).Run() require.NoError(t, err) diff --git a/cli/login_test.go b/cli/login_test.go index 14f9208360002..16255df95f776 100644 --- a/cli/login_test.go +++ b/cli/login_test.go @@ -20,7 +20,7 @@ func TestLogin(t *testing.T) { t.Parallel() client := coderdtest.New(t, nil) root, _ := clitest.New(t, "login", client.URL.String()) - err := root.Execute() + err := root.Run() require.Error(t, err) }) @@ -28,7 +28,7 @@ func TestLogin(t *testing.T) { t.Parallel() badLoginURL := "https://fcca2077f06e68aaf9" root, _ := clitest.New(t, "login", badLoginURL) - err := root.Execute() + err := root.Run() errMsg := fmt.Sprintf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser?", badLoginURL) require.ErrorContains(t, err, errMsg) }) @@ -42,11 +42,11 @@ func TestLogin(t *testing.T) { doneChan := make(chan struct{}) root, _ := clitest.New(t, "login", "--force-tty", client.URL.String()) pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() go func() { defer close(doneChan) - err := root.Execute() + err := root.Run() assert.NoError(t, err) }() @@ -77,11 +77,11 @@ func TestLogin(t *testing.T) { doneChan := make(chan struct{}) root, _ := clitest.New(t, "--url", client.URL.String(), "login", "--force-tty") pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() go func() { defer close(doneChan) - err := root.Execute() + err := root.Run() assert.NoError(t, err) }() @@ -109,11 +109,11 @@ func TestLogin(t *testing.T) { doneChan := make(chan struct{}) root, _ := clitest.New(t, "login", client.URL.String(), "--first-user-username", "testuser", "--first-user-email", "user@coder.com", "--first-user-password", "SomeSecurePassword!", "--first-user-trial") pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() go func() { defer close(doneChan) - err := root.Execute() + err := root.Run() assert.NoError(t, err) }() pty.ExpectMatch("Welcome to Coder") @@ -131,11 +131,11 @@ func TestLogin(t *testing.T) { doneChan := make(chan struct{}) root, _ := clitest.New(t, "login", "--force-tty", client.URL.String()) pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() go func() { defer close(doneChan) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() assert.NoError(t, err) }() @@ -174,11 +174,11 @@ func TestLogin(t *testing.T) { doneChan := make(chan struct{}) root, _ := clitest.New(t, "login", "--force-tty", client.URL.String(), "--no-open") pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() go func() { defer close(doneChan) - err := root.Execute() + err := root.Run() assert.NoError(t, err) }() @@ -198,11 +198,11 @@ func TestLogin(t *testing.T) { doneChan := make(chan struct{}) root, _ := clitest.New(t, "login", client.URL.String(), "--no-open") pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() go func() { defer close(doneChan) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() // An error is expected in this case, since the login wasn't successful: assert.Error(t, err) }() @@ -219,7 +219,7 @@ func TestLogin(t *testing.T) { client := coderdtest.New(t, nil) coderdtest.CreateFirstUser(t, client) root, cfg := clitest.New(t, "login", client.URL.String(), "--token", client.SessionToken()) - err := root.Execute() + err := root.Run() require.NoError(t, err) sessionFile, err := cfg.Session().Read() require.NoError(t, err) diff --git a/cli/logout_test.go b/cli/logout_test.go index dea70710baf97..857320f3966d8 100644 --- a/cli/logout_test.go +++ b/cli/logout_test.go @@ -30,12 +30,12 @@ func TestLogout(t *testing.T) { logoutChan := make(chan struct{}) logout, _ := clitest.New(t, "logout", "--global-config", string(config)) - logout.SetIn(pty.Input()) - logout.SetOut(pty.Output()) + logout.Stdin = pty.Input() + logout.Stdout = pty.Output() go func() { defer close(logoutChan) - err := logout.Execute() + err := logout.Run() assert.NoError(t, err) assert.NoFileExists(t, string(config.URL())) assert.NoFileExists(t, string(config.Session())) @@ -58,12 +58,12 @@ func TestLogout(t *testing.T) { logoutChan := make(chan struct{}) logout, _ := clitest.New(t, "logout", "--global-config", string(config), "-y") - logout.SetIn(pty.Input()) - logout.SetOut(pty.Output()) + logout.Stdin = pty.Input() + logout.Stdout = pty.Output() go func() { defer close(logoutChan) - err := logout.Execute() + err := logout.Run() assert.NoError(t, err) assert.NoFileExists(t, string(config.URL())) assert.NoFileExists(t, string(config.Session())) @@ -88,12 +88,12 @@ func TestLogout(t *testing.T) { logoutChan := make(chan struct{}) logout, _ := clitest.New(t, "logout", "--global-config", string(config)) - logout.SetIn(pty.Input()) - logout.SetOut(pty.Output()) + logout.Stdin = pty.Input() + logout.Stdout = pty.Output() go func() { defer close(logoutChan) - err := logout.Execute() + err := logout.Run() assert.EqualError(t, err, "You are not logged in. Try logging in using 'coder login '.") }() @@ -115,12 +115,12 @@ func TestLogout(t *testing.T) { logoutChan := make(chan struct{}) logout, _ := clitest.New(t, "logout", "--global-config", string(config)) - logout.SetIn(pty.Input()) - logout.SetOut(pty.Output()) + logout.Stdin = pty.Input() + logout.Stdout = pty.Output() go func() { defer close(logoutChan) - err = logout.Execute() + err = logout.Run() assert.EqualError(t, err, "You are not logged in. Try logging in using 'coder login '.") }() @@ -169,12 +169,12 @@ func TestLogout(t *testing.T) { logoutChan := make(chan struct{}) logout, _ := clitest.New(t, "logout", "--global-config", string(config)) - logout.SetIn(pty.Input()) - logout.SetOut(pty.Output()) + logout.Stdin = pty.Input() + logout.Stdout = pty.Output() go func() { defer close(logoutChan) - err := logout.Execute() + err := logout.Run() assert.NotNil(t, err) var errorMessage string if runtime.GOOS == "windows" { @@ -200,11 +200,11 @@ func login(t *testing.T, pty *ptytest.PTY) config.Root { doneChan := make(chan struct{}) root, cfg := clitest.New(t, "login", "--force-tty", client.URL.String(), "--no-open") - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() go func() { defer close(doneChan) - err := root.Execute() + err := root.Run() assert.NoError(t, err) }() diff --git a/cli/ping_test.go b/cli/ping_test.go index b1fd995551844..5f159c5963f72 100644 --- a/cli/ping_test.go +++ b/cli/ping_test.go @@ -26,7 +26,7 @@ func TestPing(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) cmd.Stdin = pty.Input() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() cmd.Stdout = pty.Output() agentClient := agentsdk.New(client.URL) diff --git a/cli/portforward_test.go b/cli/portforward_test.go index 0ee5e0bbe1f94..9e9042fb5c611 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -37,7 +37,7 @@ func TestPortForward(t *testing.T) { pty := ptytest.New(t) cmd.Stdin = pty.Input() cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() err := cmd.Run() require.Error(t, err) @@ -139,7 +139,7 @@ func TestPortForward(t *testing.T) { pty := ptytest.New(t) cmd.Stdin = pty.Input() cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() ctx, cancel := context.WithCancel(context.Background()) defer cancel() errC := make(chan error) @@ -187,7 +187,7 @@ func TestPortForward(t *testing.T) { pty := ptytest.New(t) cmd.Stdin = pty.Input() cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() ctx, cancel := context.WithCancel(context.Background()) defer cancel() errC := make(chan error) @@ -244,7 +244,7 @@ func TestPortForward(t *testing.T) { pty := ptytest.New(t) cmd.Stdin = pty.Input() cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() ctx, cancel := context.WithCancel(context.Background()) defer cancel() errC := make(chan error) @@ -324,7 +324,7 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) codersdk. pty := ptytest.New(t) cmd.Stdin = pty.Input() cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() errC := make(chan error) agentCtx, agentCancel := context.WithCancel(ctx) t.Cleanup(func() { diff --git a/cli/publickey_test.go b/cli/publickey_test.go index c38c7f9dac329..e02977ab8ed84 100644 --- a/cli/publickey_test.go +++ b/cli/publickey_test.go @@ -19,7 +19,7 @@ func TestPublicKey(t *testing.T) { cmd, root := clitest.New(t, "publickey") clitest.SetupConfig(t, client, root) buf := new(bytes.Buffer) - cmd.SetOut(buf) + cmd.Stdout = buf err := cmd.Run() require.NoError(t, err) publicKey := buf.String() diff --git a/cli/root_test.go b/cli/root_test.go index 897e60043a08c..f2acbaa0299b0 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -130,7 +130,7 @@ ExtractCommandPathsLoop: var buf bytes.Buffer cmd, cfg := clitest.New(t, tt.cmd...) clitest.SetupConfig(t, rootClient, cfg) - cmd.SetOut(&buf) + cmd.Stdout = &buf assert.NoError(t, err) err = cmd.WithContext(ctx).Run() err2 := os.Chdir(wd) @@ -346,7 +346,7 @@ func TestRoot(t *testing.T) { buf := new(bytes.Buffer) cmd, _ := clitest.New(t, "version") - cmd.SetOut(buf) + cmd.Stdout = buf err := cmd.Run() require.NoError(t, err) @@ -371,7 +371,7 @@ func TestRoot(t *testing.T) { defer srv.Close() buf := new(bytes.Buffer) cmd, _ := clitest.New(t, "--header", "X-Testing=wow", "login", srv.URL) - cmd.SetOut(buf) + cmd.Stdout = buf // This won't succeed, because we're using the login cmd to assert requests. _ = cmd.Run() }) diff --git a/cli/scaletest_test.go b/cli/scaletest_test.go index 9069be8ca53a6..8628f05536c2b 100644 --- a/cli/scaletest_test.go +++ b/cli/scaletest_test.go @@ -78,7 +78,7 @@ param3: 1 clitest.SetupConfig(t, client, root) pty := ptytest.New(t) cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() done := make(chan any) go func() { @@ -156,7 +156,7 @@ param3: 1 clitest.SetupConfig(t, client, root) pty = ptytest.New(t) cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() done = make(chan any) go func() { diff --git a/cli/schedule_test.go b/cli/schedule_test.go index 6bcdd249e8140..85a40106ce22a 100644 --- a/cli/schedule_test.go +++ b/cli/schedule_test.go @@ -44,7 +44,7 @@ func TestScheduleShow(t *testing.T) { cmd, root := clitest.New(t, cmdArgs...) clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf err := cmd.Run() require.NoError(t, err, "unexpected error") @@ -81,7 +81,7 @@ func TestScheduleShow(t *testing.T) { cmd, root := clitest.New(t, cmdArgs...) clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf err := cmd.Run() require.NoError(t, err, "unexpected error") @@ -134,7 +134,7 @@ func TestScheduleStart(t *testing.T) { // Set a well-specified autostart schedule cmd, root := clitest.New(t, "schedule", "start", workspace.Name, "9:30AM", "Mon-Fri", tz) clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf err := cmd.Run() assert.NoError(t, err, "unexpected error") @@ -159,7 +159,7 @@ func TestScheduleStart(t *testing.T) { // unset schedule cmd, root = clitest.New(t, "schedule", "start", workspace.Name, "manual") clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf err = cmd.Run() assert.NoError(t, err, "unexpected error") @@ -188,7 +188,7 @@ func TestScheduleStop(t *testing.T) { // Set the workspace TTL cmd, root := clitest.New(t, "schedule", "stop", workspace.Name, ttl.String()) clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf err := cmd.Run() assert.NoError(t, err, "unexpected error") @@ -205,7 +205,7 @@ func TestScheduleStop(t *testing.T) { // Unset the workspace TTL cmd, root = clitest.New(t, "schedule", "stop", workspace.Name, "manual") clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf err = cmd.Run() assert.NoError(t, err, "unexpected error") @@ -249,7 +249,7 @@ func TestScheduleOverride(t *testing.T) { cmd, root := clitest.New(t, cmdArgs...) clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf // When: we execute `coder schedule override workspace ` err = cmd.WithContext(ctx).Run() @@ -289,7 +289,7 @@ func TestScheduleOverride(t *testing.T) { cmd, root := clitest.New(t, cmdArgs...) clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf // When: we execute `coder bump workspace ` err = cmd.WithContext(ctx).Run() @@ -341,7 +341,7 @@ func TestScheduleOverride(t *testing.T) { cmd, root := clitest.New(t, cmdArgs...) clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf // When: we execute `coder bump workspace`` err = cmd.WithContext(ctx).Run() @@ -372,7 +372,7 @@ func TestScheduleStartDefaults(t *testing.T) { // Set an underspecified schedule cmd, root := clitest.New(t, "schedule", "start", workspace.Name, "9:30AM") clitest.SetupConfig(t, client, root) - cmd.SetOut(stdoutBuf) + cmd.Stdout = stdoutBuf err := cmd.Run() require.NoError(t, err, "unexpected error") diff --git a/cli/server_createadminuser_test.go b/cli/server_createadminuser_test.go index d222d122bff50..64a5628633841 100644 --- a/cli/server_createadminuser_test.go +++ b/cli/server_createadminuser_test.go @@ -133,8 +133,8 @@ func TestServerCreateAdminUser(t *testing.T) { root.SetErr(pty.Output()) errC := make(chan error, 1) go func() { - err := root.ExecuteContext(ctx) - t.Log("root.ExecuteContext() returned:", err) + err := root.WithContext(ctx).Run() + t.Log("root.WithContext() returned:", err).Run() errC <- err }() @@ -179,8 +179,8 @@ func TestServerCreateAdminUser(t *testing.T) { root.SetErr(pty.Output()) errC := make(chan error, 1) go func() { - err := root.ExecuteContext(ctx) - t.Log("root.ExecuteContext() returned:", err) + err := root.WithContext(ctx).Run() + t.Log("root.WithContext() returned:", err).Run() errC <- err }() @@ -216,13 +216,13 @@ func TestServerCreateAdminUser(t *testing.T) { "--ssh-keygen-algorithm", "ed25519", ) pty := ptytest.New(t) - root.SetIn(pty.Input()) + root.Stdin = pty.Input() root.SetOutput(pty.Output()) root.SetErr(pty.Output()) errC := make(chan error, 1) go func() { - err := root.ExecuteContext(ctx) - t.Log("root.ExecuteContext() returned:", err) + err := root.WithContext(ctx).Run() + t.Log("root.WithContext() returned:", err).Run() errC <- err }() @@ -270,7 +270,7 @@ func TestServerCreateAdminUser(t *testing.T) { root.SetOutput(pty.Output()) root.SetErr(pty.Output()) - err = root.ExecuteContext(ctx) + err = root.WithContext(ctx).Run() require.Error(t, err) require.ErrorContains(t, err, "'email' failed on the 'email' tag") require.ErrorContains(t, err, "'username' failed on the 'username' tag") diff --git a/cli/server_test.go b/cli/server_test.go index cd887c502cd19..30f45cf14a3e2 100644 --- a/cli/server_test.go +++ b/cli/server_test.go @@ -123,7 +123,7 @@ func TestServer(t *testing.T) { root.SetErr(pty.Output()) errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() accessURL := waitAccessURL(t, cfg) client := codersdk.New(accessURL) @@ -152,7 +152,7 @@ func TestServer(t *testing.T) { root.SetErr(pty.Output()) errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() //nolint:gocritic // Embedded postgres take a while to fire up. require.Eventually(t, func() bool { @@ -167,7 +167,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", "postgres-builtin-url") pty := ptytest.New(t) root.SetOutput(pty.Output()) - err := root.Execute() + err := root.Run() require.NoError(t, err) pty.ExpectMatch("psql") @@ -179,7 +179,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", "postgres-builtin-url", "--raw-url") pty := ptytest.New(t) root.SetOutput(pty.Output()) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() require.NoError(t, err) got := pty.ReadLine(ctx) @@ -203,11 +203,11 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() // Just wait for startup @@ -235,11 +235,11 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() // Just wait for startup @@ -265,11 +265,11 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetIn(pty.Input()) - root.SetOut(pty.Output()) + root.Stdin = pty.Input() + root.Stdout = pty.Output() errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() // Just wait for startup @@ -293,7 +293,7 @@ func TestServer(t *testing.T) { "--access-url", "google.com", "--cache-dir", t.TempDir(), ) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() require.Error(t, err) }) @@ -312,7 +312,7 @@ func TestServer(t *testing.T) { "--tls-min-version", "tls9", "--cache-dir", t.TempDir(), ) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() require.Error(t, err) }) t.Run("TLSBadClientAuth", func(t *testing.T) { @@ -330,7 +330,7 @@ func TestServer(t *testing.T) { "--tls-client-auth", "something", "--cache-dir", t.TempDir(), ) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() require.Error(t, err) }) t.Run("TLSInvalid", func(t *testing.T) { @@ -382,7 +382,7 @@ func TestServer(t *testing.T) { } args = append(args, c.args...) root, _ := clitest.New(t, args...) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() require.Error(t, err) t.Logf("args: %v", args) require.ErrorContains(t, err, c.errContains) @@ -445,7 +445,7 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetOut(pty.Output()) + root.Stdout = pty.Output() clitest.Start(ctx, t, root) accessURL := waitAccessURL(t, cfg) @@ -529,7 +529,7 @@ func TestServer(t *testing.T) { errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() // We can't use waitAccessURL as it will only return the HTTP URL. @@ -677,7 +677,7 @@ func TestServer(t *testing.T) { errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() var ( @@ -766,7 +766,7 @@ func TestServer(t *testing.T) { root.SetErr(pty.Output()) serverStop := make(chan error, 1) go func() { - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() if err != nil { t.Error(err) } @@ -796,7 +796,7 @@ func TestServer(t *testing.T) { root.SetErr(pty.Output()) serverClose := make(chan struct{}, 1) go func() { - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() if err != nil { t.Error(err) } @@ -821,7 +821,7 @@ func TestServer(t *testing.T) { "--tls-enable=false", "--tls-address", "", ) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() require.Error(t, err) require.ErrorContains(t, err, "tls-address") }) @@ -837,7 +837,7 @@ func TestServer(t *testing.T) { "--tls-enable=true", "--tls-address", "", ) - err := root.ExecuteContext(ctx) + err := root.WithContext(ctx).Run() require.Error(t, err) require.ErrorContains(t, err, "must not be empty") }) @@ -935,7 +935,7 @@ func TestServer(t *testing.T) { ) serverErr := make(chan error, 1) go func() { - serverErr <- root.ExecuteContext(ctx) + serverErr <- root.WithContext(ctx).Run() }() _ = waitAccessURL(t, cfg) currentProcess, err := os.FindProcess(os.Getpid()) @@ -962,7 +962,7 @@ func TestServer(t *testing.T) { ) errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() cancelFunc() require.NoError(t, <-errC) @@ -1001,7 +1001,7 @@ func TestServer(t *testing.T) { ) errC := make(chan error, 1) go func() { - errC <- root.ExecuteContext(ctx) + errC <- root.WithContext(ctx).Run() }() <-deployment @@ -1033,7 +1033,7 @@ func TestServer(t *testing.T) { ) serverErr := make(chan error, 1) go func() { - serverErr <- root.ExecuteContext(ctx) + serverErr <- root.WithContext(ctx).Run() }() _ = waitAccessURL(t, cfg) @@ -1086,7 +1086,7 @@ func TestServer(t *testing.T) { ) serverErr := make(chan error, 1) go func() { - serverErr <- root.ExecuteContext(ctx) + serverErr <- root.WithContext(ctx).Run() }() accessURL := waitAccessURL(t, cfg) client := codersdk.New(accessURL) @@ -1123,7 +1123,7 @@ func TestServer(t *testing.T) { ) serverErr := make(chan error, 1) go func() { - serverErr <- root.ExecuteContext(ctx) + serverErr <- root.WithContext(ctx).Run() }() accessURL := waitAccessURL(t, cfg) client := codersdk.New(accessURL) @@ -1152,7 +1152,7 @@ func TestServer(t *testing.T) { ) serverErr := make(chan error, 1) go func() { - serverErr <- root.ExecuteContext(ctx) + serverErr <- root.WithContext(ctx).Run() }() accessURL := waitAccessURL(t, cfg) client := codersdk.New(accessURL) @@ -1180,7 +1180,7 @@ func TestServer(t *testing.T) { ) serverErr := make(chan error, 1) go func() { - serverErr <- root.ExecuteContext(ctx) + serverErr <- root.WithContext(ctx).Run() }() accessURL := waitAccessURL(t, cfg) client := codersdk.New(accessURL) @@ -1287,12 +1287,12 @@ func TestServer(t *testing.T) { // Attach pty so we get debug output from the command if this test // fails. pty := ptytest.New(t) - root.SetOut(pty.Output()) + root.Stdout = pty.Output() root.SetErr(pty.Output()) serverErr := make(chan error, 1) go func() { - serverErr <- root.ExecuteContext(ctx) + serverErr <- root.WithContext(ctx).Run() }() defer func() { cancelFunc() @@ -1332,7 +1332,7 @@ func TestServer(t *testing.T) { // Attach pty so we get debug output from the command if this test // fails. pty := ptytest.New(t) - root.SetOut(pty.Output()) + root.Stdout = pty.Output() root.SetErr(pty.Output()) clitest.Start(ctx, t, root) diff --git a/cli/speedtest_test.go b/cli/speedtest_test.go index 15c521df48d50..622e2ef6135dc 100644 --- a/cli/speedtest_test.go +++ b/cli/speedtest_test.go @@ -52,7 +52,7 @@ func TestSpeedtest(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() ctx, cancel = context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() diff --git a/cli/ssh_test.go b/cli/ssh_test.go index 45fd82ac66111..57d5d78cf3015 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -91,7 +91,7 @@ func TestSSH(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) cmd.Stdin = pty.Input() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() cmd.Stdout = pty.Output() ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -132,7 +132,7 @@ func TestSSH(t *testing.T) { clitest.SetupConfig(t, client, root) pty := ptytest.New(t) cmd.Stdin = pty.Input() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() cmd.Stdout = pty.Output() ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -175,9 +175,9 @@ func TestSSH(t *testing.T) { cmd, root := clitest.New(t, "ssh", "--stdio", workspace.Name) clitest.SetupConfig(t, client, root) - cmd.SetIn(clientOutput) - cmd.SetOut(serverInput) - cmd.SetErr(io.Discard) + cmd.Stdin = clientOutput + cmd.Stdout = serverInput + cmd.Stderr = io.Discard cmdDone := tGo(t, func() { err := cmd.WithContext(ctx).Run() assert.NoError(t, err) @@ -272,7 +272,7 @@ func TestSSH(t *testing.T) { pty := ptytest.New(t) cmd.Stdin = pty.Input() cmd.Stdout = pty.Output() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() cmdDone := tGo(t, func() { err := cmd.WithContext(ctx).Run() assert.NoError(t, err, "ssh command failed") @@ -473,9 +473,9 @@ Expire-Date: 0 ) clitest.SetupConfig(t, client, root) tpty := ptytest.New(t) - cmd.SetIn(tpty.Input()) - cmd.SetOut(tpty.Output()) - cmd.SetErr(tpty.Output()) + cmd.Stdin = tpty.Input() + cmd.Stdout = tpty.Output() + cmd.Stderr = tpty.Output() cmdDone := tGo(t, func() { err := cmd.WithContext(ctx).Run() assert.NoError(t, err, "ssh command failed") diff --git a/cli/state_test.go b/cli/state_test.go index 3eb79e31bf5e0..cccbf91c5971f 100644 --- a/cli/state_test.go +++ b/cli/state_test.go @@ -67,7 +67,7 @@ func TestStatePull(t *testing.T) { coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) cmd, root := clitest.New(t, "state", "pull", workspace.Name) var gotState bytes.Buffer - cmd.SetOut(&gotState) + cmd.Stdout = &gotState clitest.SetupConfig(t, client, root) err := cmd.Run() require.NoError(t, err) @@ -116,7 +116,7 @@ func TestStatePush(t *testing.T) { coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) cmd, root := clitest.New(t, "state", "push", "--build", strconv.Itoa(int(workspace.LatestBuild.BuildNumber)), workspace.Name, "-") clitest.SetupConfig(t, client, root) - cmd.SetIn(strings.NewReader("some magic state")) + cmd.Stdin = strings.NewReader("some magic state") err := cmd.Run() require.NoError(t, err) }) diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index 7294fcb4fb8c0..3e0fc8d26e90b 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -106,7 +106,7 @@ func TestTemplateCreate(t *testing.T) { cmd, root := clitest.New(t, args...) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(bytes.NewReader(source)) + cmd.Stdin = bytes.NewReader(source) cmd.Stdout = pty.Output() execDone := make(chan error) diff --git a/cli/templateedit_test.go b/cli/templateedit_test.go index a3c9a00c07e97..af55b2ae8751d 100644 --- a/cli/templateedit_test.go +++ b/cli/templateedit_test.go @@ -264,7 +264,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, client, root) ctx, _ := testutil.Context(t) - err := cmd.ExecuteContext(ctx) + err := cmd.WithContext(ctx).Run() require.Error(t, err) require.ErrorContains(t, err, "appears to be an AGPL deployment") @@ -336,7 +336,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, proxyClient, root) ctx, _ := testutil.Context(t) - err = cmd.ExecuteContext(ctx) + err = cmd.WithContext(ctx).Run() require.Error(t, err) require.ErrorContains(t, err, "license is not entitled") @@ -423,7 +423,7 @@ func TestTemplateEdit(t *testing.T) { clitest.SetupConfig(t, proxyClient, root) ctx, _ := testutil.Context(t) - err = cmd.ExecuteContext(ctx) + err = cmd.WithContext(ctx).Run() require.NoError(t, err) require.EqualValues(t, 1, atomic.LoadInt64(&updateTemplateCalled)) diff --git a/cli/templatelist_test.go b/cli/templatelist_test.go index ab5c1d784aa1d..7c434f9ae5e7c 100644 --- a/cli/templatelist_test.go +++ b/cli/templatelist_test.go @@ -74,7 +74,7 @@ func TestTemplateList(t *testing.T) { defer cancelFunc() out := bytes.NewBuffer(nil) - cmd.SetOut(out) + cmd.Stdout = out err := cmd.WithContext(ctx).Run() require.NoError(t, err) @@ -92,7 +92,7 @@ func TestTemplateList(t *testing.T) { pty := ptytest.New(t) cmd.Stdin = pty.Input() - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancelFunc() diff --git a/cli/templatepull_test.go b/cli/templatepull_test.go index 6a47640c00cb8..dbbf5f929a6cc 100644 --- a/cli/templatepull_test.go +++ b/cli/templatepull_test.go @@ -81,7 +81,7 @@ func TestTemplatePull(t *testing.T) { clitest.SetupConfig(t, client, root) var buf bytes.Buffer - cmd.SetOut(&buf) + cmd.Stdout = &buf err = cmd.Run() require.NoError(t, err) diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go index 3ccd9a94a3c30..a015a714989d7 100644 --- a/cli/templatepush_test.go +++ b/cli/templatepush_test.go @@ -234,7 +234,7 @@ func TestTemplatePush(t *testing.T) { ) clitest.SetupConfig(t, client, root) pty := ptytest.New(t) - cmd.SetIn(bytes.NewReader(source)) + cmd.Stdin = bytes.NewReader(source) cmd.Stdout = pty.Output() execDone := make(chan error) diff --git a/cli/tokens_test.go b/cli/tokens_test.go index 41e5b6342c498..915b1e75459ff 100644 --- a/cli/tokens_test.go +++ b/cli/tokens_test.go @@ -27,7 +27,7 @@ func TestTokens(t *testing.T) { cmd, root := clitest.New(t, "tokens", "ls") clitest.SetupConfig(t, client, root) buf := new(bytes.Buffer) - cmd.SetOut(buf) + cmd.Stdout = buf err := cmd.WithContext(ctx).Run() require.NoError(t, err) res := buf.String() @@ -36,7 +36,7 @@ func TestTokens(t *testing.T) { cmd, root = clitest.New(t, "tokens", "create", "--name", "token-one") clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) - cmd.SetOut(buf) + cmd.Stdout = buf err = cmd.WithContext(ctx).Run() require.NoError(t, err) res = buf.String() @@ -50,7 +50,7 @@ func TestTokens(t *testing.T) { cmd, root = clitest.New(t, "tokens", "ls") clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) - cmd.SetOut(buf) + cmd.Stdout = buf err = cmd.WithContext(ctx).Run() require.NoError(t, err) res = buf.String() @@ -64,7 +64,7 @@ func TestTokens(t *testing.T) { cmd, root = clitest.New(t, "tokens", "ls", "--output=json") clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) - cmd.SetOut(buf) + cmd.Stdout = buf err = cmd.WithContext(ctx).Run() require.NoError(t, err) @@ -76,7 +76,7 @@ func TestTokens(t *testing.T) { cmd, root = clitest.New(t, "tokens", "rm", "token-one") clitest.SetupConfig(t, client, root) buf = new(bytes.Buffer) - cmd.SetOut(buf) + cmd.Stdout = buf err = cmd.WithContext(ctx).Run() require.NoError(t, err) res = buf.String() diff --git a/cli/update_test.go b/cli/update_test.go index 27028baf6a121..30abca2746dad 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -445,7 +445,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { // Create workspace cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y") clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) // Modify template @@ -475,7 +475,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd.Stdout = pty.Output() go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() @@ -515,7 +515,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { // Create workspace cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y") clitest.SetupConfig(t, client, root) - err := cmd.Execute() + err := cmd.Run() require.NoError(t, err) // Modify template @@ -546,7 +546,7 @@ func TestUpdateValidateRichParameters(t *testing.T) { cmd.Stdout = pty.Output() go func() { defer close(doneChan) - err := cmd.Execute() + err := cmd.Run() assert.NoError(t, err) }() diff --git a/cli/userlist_test.go b/cli/userlist_test.go index f96f15459528c..76812833ba9c2 100644 --- a/cli/userlist_test.go +++ b/cli/userlist_test.go @@ -43,7 +43,7 @@ func TestUserList(t *testing.T) { doneChan := make(chan struct{}) buf := bytes.NewBuffer(nil) - cmd.SetOut(buf) + cmd.Stdout = buf go func() { defer close(doneChan) err := cmd.Run() @@ -119,7 +119,7 @@ func TestUserShow(t *testing.T) { doneChan := make(chan struct{}) buf := bytes.NewBuffer(nil) - cmd.SetOut(buf) + cmd.Stdout = buf go func() { defer close(doneChan) err := cmd.Run() diff --git a/cli/userstatus_test.go b/cli/userstatus_test.go index 1c180a85f6462..adbe024176d93 100644 --- a/cli/userstatus_test.go +++ b/cli/userstatus_test.go @@ -25,7 +25,7 @@ func TestUserStatus(t *testing.T) { cmd, root := clitest.New(t, "users", "suspend", "me") clitest.SetupConfig(t, client, root) // Yes to the prompt - cmd.SetIn(bytes.NewReader([]byte("yes\n"))) + cmd.Stdin = bytes.NewReader([]byte("yes\n")) err := cmd.Run() // Expect an error, as you cannot suspend yourself require.Error(t, err) @@ -38,7 +38,7 @@ func TestUserStatus(t *testing.T) { cmd, root := clitest.New(t, "users", "suspend", otherUser.Username) clitest.SetupConfig(t, client, root) // Yes to the prompt - cmd.SetIn(bytes.NewReader([]byte("yes\n"))) + cmd.Stdin = bytes.NewReader([]byte("yes\n")) err := cmd.Run() require.NoError(t, err, "suspend user") @@ -51,7 +51,7 @@ func TestUserStatus(t *testing.T) { cmd, root = clitest.New(t, "users", "activate", otherUser.ID.String()) clitest.SetupConfig(t, client, root) // Yes to the prompt - cmd.SetIn(bytes.NewReader([]byte("yes\n"))) + cmd.Stdin = bytes.NewReader([]byte("yes\n")) err = cmd.Run() require.NoError(t, err, "suspend user") diff --git a/enterprise/cli/features_test.go b/enterprise/cli/features_test.go index eeb663e997495..758eaf1911364 100644 --- a/enterprise/cli/features_test.go +++ b/enterprise/cli/features_test.go @@ -45,7 +45,7 @@ func TestFeaturesList(t *testing.T) { doneChan := make(chan struct{}) buf := bytes.NewBuffer(nil) - cmd.SetOut(buf) + cmd.Stdout = buf go func() { defer close(doneChan) err := cmd.Run() diff --git a/enterprise/cli/grouplist_test.go b/enterprise/cli/grouplist_test.go index 959613711410a..dfc825aab98bc 100644 --- a/enterprise/cli/grouplist_test.go +++ b/enterprise/cli/grouplist_test.go @@ -94,7 +94,7 @@ func TestGroupList(t *testing.T) { pty := ptytest.New(t) - cmd.SetErr(pty.Output()) + cmd.Stderr = pty.Output() clitest.SetupConfig(t, client, root) err := cmd.Run() diff --git a/enterprise/cli/licenses_test.go b/enterprise/cli/licenses_test.go index 556dd7224700e..fb1e9f8cffbc0 100644 --- a/enterprise/cli/licenses_test.go +++ b/enterprise/cli/licenses_test.go @@ -86,9 +86,9 @@ func TestLicensesAddFake(t *testing.T) { t.Parallel() cmd := setupFakeLicenseServerTest(t, "license", "add", "-f", "-") r, w := io.Pipe() - cmd.SetIn(r) + cmd.Stdin = r stdout := new(bytes.Buffer) - cmd.SetOut(stdout) + cmd.Stdout = stdout errC := make(chan error) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -156,7 +156,7 @@ func TestLicensesListFake(t *testing.T) { defer cancel() cmd := setupFakeLicenseServerTest(t, "licenses", "list") stdout := new(bytes.Buffer) - cmd.SetOut(stdout) + cmd.Stdout = stdout errC := make(chan error) go func() { errC <- cmd.WithContext(ctx).Run() @@ -182,9 +182,9 @@ func TestLicensesListReal(t *testing.T) { cmd, root := clitest.NewWithSubcommands(t, cli.EnterpriseSubcommands(), "licenses", "list") stdout := new(bytes.Buffer) - cmd.SetOut(stdout) + cmd.Stdout = stdout stderr := new(bytes.Buffer) - cmd.SetErr(stderr) + cmd.Stderr = stderr clitest.SetupConfig(t, client, root) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() From 5613d3b7cb466ad1c1db1053e709acb8172b1371 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Tue, 7 Mar 2023 18:54:06 +0000 Subject: [PATCH 009/175] 185 problems left... --- cli/cliui/agent_test.go | 12 ++++----- cli/cliui/gitauth_test.go | 2 +- cli/cliui/provisionerjob_test.go | 2 +- cli/cliui/select_test.go | 4 +-- cli/gitaskpass_test.go | 8 +++--- cli/server_createadminuser_test.go | 16 ++++++------ cli/server_test.go | 40 +++++++++++++++--------------- 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/cli/cliui/agent_test.go b/cli/cliui/agent_test.go index 181809f4a2a9d..45e05a296db81 100644 --- a/cli/cliui/agent_test.go +++ b/cli/cliui/agent_test.go @@ -45,7 +45,7 @@ func TestAgent(t *testing.T) { return err }, } - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan struct{}) go func() { @@ -92,7 +92,7 @@ func TestAgent_TimeoutWithTroubleshootingURL(t *testing.T) { }, } ptty := ptytest.New(t) - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { @@ -145,7 +145,7 @@ func TestAgent_StartupTimeout(t *testing.T) { } ptty := ptytest.New(t) - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { @@ -203,7 +203,7 @@ func TestAgent_StartErrorExit(t *testing.T) { } ptty := ptytest.New(t) - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { @@ -258,7 +258,7 @@ func TestAgent_NoWait(t *testing.T) { } ptty := ptytest.New(t) - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { @@ -327,7 +327,7 @@ func TestAgent_LoginBeforeReadyEnabled(t *testing.T) { } ptty := ptytest.New(t) - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan error, 1) go func() { diff --git a/cli/cliui/gitauth_test.go b/cli/cliui/gitauth_test.go index 3b59077588d71..d214c37d86160 100644 --- a/cli/cliui/gitauth_test.go +++ b/cli/cliui/gitauth_test.go @@ -40,7 +40,7 @@ func TestGitAuth(t *testing.T) { }) }, } - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan struct{}) go func() { diff --git a/cli/cliui/provisionerjob_test.go b/cli/cliui/provisionerjob_test.go index 4082c63e713a1..2fca682859665 100644 --- a/cli/cliui/provisionerjob_test.go +++ b/cli/cliui/provisionerjob_test.go @@ -146,7 +146,7 @@ func newProvisionerJob(t *testing.T) provisionerJobTest { }, } ptty := ptytest.New(t) - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() done := make(chan struct{}) go func() { diff --git a/cli/cliui/select_test.go b/cli/cliui/select_test.go index 5760055777ce6..915afe5bc120d 100644 --- a/cli/cliui/select_test.go +++ b/cli/cliui/select_test.go @@ -39,7 +39,7 @@ func newSelect(ptty *ptytest.PTY, opts cliui.SelectOptions) (string, error) { return err }, } - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() return value, cmd.RunContext(context.Background()) } @@ -82,7 +82,7 @@ func newRichSelect(ptty *ptytest.PTY, opts cliui.RichSelectOptions) (string, err return err }, } - cmd.SetOutput(ptty.Output()) + cmd.Stdout = ptty.Output() cmd.Stdin = ptty.Input() return value, cmd.RunContext(context.Background()) } diff --git a/cli/gitaskpass_test.go b/cli/gitaskpass_test.go index 961845cdb5336..b560ded67e584 100644 --- a/cli/gitaskpass_test.go +++ b/cli/gitaskpass_test.go @@ -32,14 +32,14 @@ func TestGitAskpass(t *testing.T) { url := srv.URL cmd, _ := clitest.New(t, "--agent-url", url, "Username for 'https://github.com':") pty := ptytest.New(t) - cmd.SetOutput(pty.Output()) + cmd.Stdout = pty.Output() err := cmd.Run() require.NoError(t, err) pty.ExpectMatch("something") cmd, _ = clitest.New(t, "--agent-url", url, "Password for 'https://potato@github.com':") pty = ptytest.New(t) - cmd.SetOutput(pty.Output()) + cmd.Stdout = pty.Output() err = cmd.Run() require.NoError(t, err) pty.ExpectMatch("bananas") @@ -55,7 +55,7 @@ func TestGitAskpass(t *testing.T) { url := srv.URL cmd, _ := clitest.New(t, "--agent-url", url, "--no-open", "Username for 'https://github.com':") pty := ptytest.New(t) - cmd.SetOutput(pty.Output()) + cmd.Stdout = pty.Output() err := cmd.Run() require.ErrorIs(t, err, cliui.Canceled) pty.ExpectMatch("Nope!") @@ -83,7 +83,7 @@ func TestGitAskpass(t *testing.T) { cmd, _ := clitest.New(t, "--agent-url", url, "--no-open", "Username for 'https://github.com':") pty := ptytest.New(t) - cmd.SetOutput(pty.Output()) + cmd.Stdout = pty.Output() go func() { err := cmd.Run() assert.NoError(t, err) diff --git a/cli/server_createadminuser_test.go b/cli/server_createadminuser_test.go index 64a5628633841..d6a69d7c9189a 100644 --- a/cli/server_createadminuser_test.go +++ b/cli/server_createadminuser_test.go @@ -129,8 +129,8 @@ func TestServerCreateAdminUser(t *testing.T) { "--password", password, ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() errC := make(chan error, 1) go func() { err := root.WithContext(ctx).Run() @@ -175,8 +175,8 @@ func TestServerCreateAdminUser(t *testing.T) { root, _ := clitest.New(t, "server", "create-admin-user") pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() errC := make(chan error, 1) go func() { err := root.WithContext(ctx).Run() @@ -217,8 +217,8 @@ func TestServerCreateAdminUser(t *testing.T) { ) pty := ptytest.New(t) root.Stdin = pty.Input() - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() errC := make(chan error, 1) go func() { err := root.WithContext(ctx).Run() @@ -267,8 +267,8 @@ func TestServerCreateAdminUser(t *testing.T) { "--password", "x", ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() err = root.WithContext(ctx).Run() require.Error(t, err) diff --git a/cli/server_test.go b/cli/server_test.go index 30f45cf14a3e2..44f000ae2ca17 100644 --- a/cli/server_test.go +++ b/cli/server_test.go @@ -119,8 +119,8 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() errC := make(chan error, 1) go func() { errC <- root.WithContext(ctx).Run() @@ -148,8 +148,8 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() errC := make(chan error, 1) go func() { errC <- root.WithContext(ctx).Run() @@ -166,7 +166,7 @@ func TestServer(t *testing.T) { t.Parallel() root, _ := clitest.New(t, "server", "postgres-builtin-url") pty := ptytest.New(t) - root.SetOutput(pty.Output()) + root.Stdout = pty.Output() err := root.Run() require.NoError(t, err) @@ -178,7 +178,7 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, "server", "postgres-builtin-url", "--raw-url") pty := ptytest.New(t) - root.SetOutput(pty.Output()) + root.Stdout = pty.Output() err := root.WithContext(ctx).Run() require.NoError(t, err) @@ -524,8 +524,8 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() errC := make(chan error, 1) go func() { @@ -672,8 +672,8 @@ func TestServer(t *testing.T) { root, _ := clitest.New(t, flags...) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() errC := make(chan error, 1) go func() { @@ -762,8 +762,8 @@ func TestServer(t *testing.T) { ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() serverStop := make(chan error, 1) go func() { err := root.WithContext(ctx).Run() @@ -792,8 +792,8 @@ func TestServer(t *testing.T) { ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() serverClose := make(chan struct{}, 1) go func() { err := root.WithContext(ctx).Run() @@ -862,8 +862,8 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() clitest.Start(ctx, t, root) pty.ExpectMatch("is deprecated") @@ -892,8 +892,8 @@ func TestServer(t *testing.T) { "--cache-dir", t.TempDir(), ) pty := ptytest.New(t) - root.SetOutput(pty.Output()) - root.SetErr(pty.Output()) + root.Stdout = pty.Output() + root.Stderr = pty.Output() clitest.Start(ctx, t, root) pty.ExpectMatch("is deprecated") @@ -1288,7 +1288,7 @@ func TestServer(t *testing.T) { // fails. pty := ptytest.New(t) root.Stdout = pty.Output() - root.SetErr(pty.Output()) + root.Stderr = pty.Output() serverErr := make(chan error, 1) go func() { @@ -1333,7 +1333,7 @@ func TestServer(t *testing.T) { // fails. pty := ptytest.New(t) root.Stdout = pty.Output() - root.SetErr(pty.Output()) + root.Stderr = pty.Output() clitest.Start(ctx, t, root) From b7133722f4a29eda6fe2637dbeca6efbc21570f9 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Tue, 7 Mar 2023 19:12:48 +0000 Subject: [PATCH 010/175] 359 problems left... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Started refactoring production code too 🥴 --- cli/agent.go | 14 ++++---- cli/cliflag/cliflag.go | 6 ++-- cli/cliui/agent_test.go | 31 +++++++++-------- cli/cliui/gitauth_test.go | 8 ++--- cli/cliui/output.go | 10 +++--- cli/cliui/output_test.go | 10 +++--- cli/cliui/parameter.go | 7 ++-- cli/cliui/prompt.go | 10 +++--- cli/cliui/prompt_test.go | 14 ++++---- cli/cliui/provisionerjob_test.go | 8 ++--- cli/cliui/select.go | 6 ++-- cli/cliui/select_test.go | 10 +++--- cli/configssh.go | 9 ++--- cli/create.go | 38 ++++++++++----------- cli/create_test.go | 2 +- cli/delete.go | 13 ++++---- cli/dotfiles.go | 15 +++++---- cli/gitssh.go | 24 ++++++------- cli/list.go | 21 ++++++------ cli/login.go | 23 +++++++------ cli/logout.go | 10 +++--- cli/parameter.go | 6 ++-- cli/parameters.go | 9 ++--- cli/parameterslist.go | 15 +++++---- cli/ping.go | 9 ++--- cli/portforward.go | 15 +++++---- cli/publickey.go | 12 +++---- cli/rename.go | 9 ++--- cli/resetpassword.go | 11 +++--- cli/restart.go | 9 ++--- cli/root.go | 28 ++++++++-------- cli/root_test.go | 12 +++---- cli/scaletest.go | 50 ++++++++++++++-------------- cli/schedule.go | 37 ++++++++++---------- cli/server.go | 33 +++++++++--------- cli/server_createadminuser.go | 30 ++++++++--------- cli/server_slim.go | 29 ++++++++-------- cli/speedtest.go | 13 ++++---- cli/ssh.go | 21 ++++++------ cli/start.go | 11 +++--- cli/state.go | 29 ++++++++-------- cli/stop.go | 11 +++--- cli/templatecreate.go | 35 +++++++++---------- cli/templatedelete.go | 10 +++--- cli/templateedit.go | 13 ++++---- cli/templateinit.go | 9 +++-- cli/templatelist.go | 16 ++++----- cli/templateplan.go | 7 ++-- cli/templatepull.go | 9 ++--- cli/templatepush.go | 15 +++++---- cli/templates.go | 9 ++--- cli/templateversions.go | 19 ++++++----- cli/tokens.go | 35 +++++++++---------- cli/update.go | 17 +++++----- cli/usercreate.go | 12 +++---- cli/userlist.go | 25 +++++++------- cli/users.go | 10 +++--- cli/userstatus.go | 11 +++--- cli/vscodessh.go | 11 +++--- cmd/cliui/main.go | 28 ++++++++-------- enterprise/cli/features.go | 16 ++++----- enterprise/cli/groupcreate.go | 9 ++--- enterprise/cli/groupdelete.go | 9 ++--- enterprise/cli/groupedit.go | 9 ++--- enterprise/cli/grouplist.go | 15 +++++---- enterprise/cli/groups.go | 8 ++--- enterprise/cli/licenses.go | 31 ++++++++--------- enterprise/cli/licenses_test.go | 6 ++-- enterprise/cli/provisionerdaemons.go | 16 ++++----- enterprise/cli/root.go | 9 +++-- enterprise/cli/server.go | 4 +-- enterprise/cli/server_slim.go | 2 +- pty/ptytest/ptytest_test.go | 6 ++-- scripts/clidocgen/gen.go | 16 ++++----- 74 files changed, 582 insertions(+), 553 deletions(-) diff --git a/cli/agent.go b/cli/agent.go index 97be736abdc52..bc0db0c1880c1 100644 --- a/cli/agent.go +++ b/cli/agent.go @@ -15,7 +15,6 @@ import ( "time" "cloud.google.com/go/compute/metadata" - "github.com/spf13/cobra" "golang.org/x/xerrors" "gopkg.in/natefinch/lumberjack.v2" @@ -24,23 +23,24 @@ import ( "github.com/coder/coder/agent" "github.com/coder/coder/agent/reaper" "github.com/coder/coder/buildinfo" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/codersdk/agentsdk" ) -func workspaceAgent() *cobra.Command { +func workspaceAgent() *clibase.Command { var ( auth string logDir string pprofAddress string noReap bool ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "agent", // This command isn't useful to manually execute. Hidden: true, - RunE: func(cmd *cobra.Command, _ []string) error { - ctx, cancel := context.WithCancel(cmd.Context()) + Handler: func(inv *clibase.Invokation) error { + ctx, cancel := context.WithCancel(inv.Context()) defer cancel() rawURL, err := cmd.Flags().GetString(varAgentURL) @@ -62,7 +62,7 @@ func workspaceAgent() *cobra.Command { MaxSize: 5, // MB } defer logWriter.Close() - logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr()), sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug) + logger := slog.Make(sloghuman.Sink(inv.Stderr), sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug) logger.Info(ctx, "spawning reaper process") // Do not start a reaper on the child process. It's important @@ -104,7 +104,7 @@ func workspaceAgent() *cobra.Command { logWriter := &closeWriter{w: ljLogger} defer logWriter.Close() - logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr()), sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug) + logger := slog.Make(sloghuman.Sink(inv.Stderr), sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug) version := buildinfo.Version() logger.Info(ctx, "starting agent", diff --git a/cli/cliflag/cliflag.go b/cli/cliflag/cliflag.go index 4d93f8a77bc15..27973bcba7e7c 100644 --- a/cli/cliflag/cliflag.go +++ b/cli/cliflag/cliflag.go @@ -16,16 +16,16 @@ import ( "strings" "time" - "github.com/spf13/cobra" "github.com/spf13/pflag" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" ) // IsSetBool returns the value of the boolean flag if it is set. // It returns false if the flag isn't set or if any error occurs attempting // to parse the value of the flag. -func IsSetBool(cmd *cobra.Command, name string) bool { +func IsSetBool(cmd *clibase.Command, name string) bool { val, ok := IsSet(cmd, name) if !ok { return false @@ -36,7 +36,7 @@ func IsSetBool(cmd *cobra.Command, name string) bool { } // IsSet returns the string value of the flag and whether it was set. -func IsSet(cmd *cobra.Command, name string) (string, bool) { +func IsSet(cmd *clibase.Command, name string) (string, bool) { flag := cmd.Flag(name) if flag == nil { return "", false diff --git a/cli/cliui/agent_test.go b/cli/cliui/agent_test.go index 45e05a296db81..498150811b8e6 100644 --- a/cli/cliui/agent_test.go +++ b/cli/cliui/agent_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/atomic" @@ -67,9 +66,9 @@ func TestAgent_TimeoutWithTroubleshootingURL(t *testing.T) { wantURL := "https://coder.com/troubleshoot" var connected, timeout atomic.Bool - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, _ []string) error { - err := cliui.Agent(cmd.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { + err := cliui.Agent(inv.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ WorkspaceName: "example", Fetch: func(_ context.Context) (codersdk.WorkspaceAgent, error) { agent := codersdk.WorkspaceAgent{ @@ -116,9 +115,9 @@ func TestAgent_StartupTimeout(t *testing.T) { var status, state atomic.String setStatus := func(s codersdk.WorkspaceAgentStatus) { status.Store(string(s)) } setState := func(s codersdk.WorkspaceAgentLifecycle) { state.Store(string(s)) } - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, _ []string) error { - err := cliui.Agent(cmd.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { + err := cliui.Agent(inv.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ WorkspaceName: "example", Fetch: func(_ context.Context) (codersdk.WorkspaceAgent, error) { agent := codersdk.WorkspaceAgent{ @@ -174,9 +173,9 @@ func TestAgent_StartErrorExit(t *testing.T) { var status, state atomic.String setStatus := func(s codersdk.WorkspaceAgentStatus) { status.Store(string(s)) } setState := func(s codersdk.WorkspaceAgentLifecycle) { state.Store(string(s)) } - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, _ []string) error { - err := cliui.Agent(cmd.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { + err := cliui.Agent(inv.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ WorkspaceName: "example", Fetch: func(_ context.Context) (codersdk.WorkspaceAgent, error) { agent := codersdk.WorkspaceAgent{ @@ -229,9 +228,9 @@ func TestAgent_NoWait(t *testing.T) { var status, state atomic.String setStatus := func(s codersdk.WorkspaceAgentStatus) { status.Store(string(s)) } setState := func(s codersdk.WorkspaceAgentLifecycle) { state.Store(string(s)) } - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, _ []string) error { - err := cliui.Agent(cmd.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { + err := cliui.Agent(inv.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ WorkspaceName: "example", Fetch: func(_ context.Context) (codersdk.WorkspaceAgent, error) { agent := codersdk.WorkspaceAgent{ @@ -298,9 +297,9 @@ func TestAgent_LoginBeforeReadyEnabled(t *testing.T) { var status, state atomic.String setStatus := func(s codersdk.WorkspaceAgentStatus) { status.Store(string(s)) } setState := func(s codersdk.WorkspaceAgentLifecycle) { state.Store(string(s)) } - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, _ []string) error { - err := cliui.Agent(cmd.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { + err := cliui.Agent(inv.Context(), cmd.OutOrStdout(), cliui.AgentOptions{ WorkspaceName: "example", Fetch: func(_ context.Context) (codersdk.WorkspaceAgent, error) { agent := codersdk.WorkspaceAgent{ diff --git a/cli/cliui/gitauth_test.go b/cli/cliui/gitauth_test.go index d214c37d86160..c4fe726b86a89 100644 --- a/cli/cliui/gitauth_test.go +++ b/cli/cliui/gitauth_test.go @@ -7,9 +7,9 @@ import ( "testing" "time" - "github.com/spf13/cobra" "github.com/stretchr/testify/assert" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" "github.com/coder/coder/pty/ptytest" @@ -23,10 +23,10 @@ func TestGitAuth(t *testing.T) { defer cancel() ptty := ptytest.New(t) - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, args []string) error { + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { var fetched atomic.Bool - return cliui.GitAuth(cmd.Context(), cmd.OutOrStdout(), cliui.GitAuthOptions{ + return cliui.GitAuth(inv.Context(), cmd.OutOrStdout(), cliui.GitAuthOptions{ Fetch: func(ctx context.Context) ([]codersdk.TemplateVersionGitAuth, error) { defer fetched.Store(true) return []codersdk.TemplateVersionGitAuth{{ diff --git a/cli/cliui/output.go b/cli/cliui/output.go index e537e30473da1..440e783b315a2 100644 --- a/cli/cliui/output.go +++ b/cli/cliui/output.go @@ -6,13 +6,13 @@ import ( "reflect" "strings" - "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" "golang.org/x/xerrors" ) type OutputFormat interface { ID() string - AttachFlags(cmd *cobra.Command) + AttachFlags(cmd *clibase.Command) Format(ctx context.Context, data any) (string, error) } @@ -47,7 +47,7 @@ func NewOutputFormatter(formats ...OutputFormat) *OutputFormatter { // AttachFlags attaches the --output flag to the given command, and any // additional flags required by the output formatters. -func (f *OutputFormatter) AttachFlags(cmd *cobra.Command) { +func (f *OutputFormatter) AttachFlags(cmd *clibase.Command) { for _, format := range f.formats { format.AttachFlags(cmd) } @@ -119,7 +119,7 @@ func (*tableFormat) ID() string { } // AttachFlags implements OutputFormat. -func (f *tableFormat) AttachFlags(cmd *cobra.Command) { +func (f *tableFormat) AttachFlags(cmd *clibase.Command) { cmd.Flags().StringSliceVarP(&f.columns, "column", "c", f.defaultColumns, "Columns to display in table output. Available columns: "+strings.Join(f.allColumns, ", ")) } @@ -143,7 +143,7 @@ func (jsonFormat) ID() string { } // AttachFlags implements OutputFormat. -func (jsonFormat) AttachFlags(_ *cobra.Command) {} +func (jsonFormat) AttachFlags(_ *clibase.Command) {} // Format implements OutputFormat. func (jsonFormat) Format(_ context.Context, data any) (string, error) { diff --git a/cli/cliui/output_test.go b/cli/cliui/output_test.go index 7a31df9ab8afd..89a3f8c791cf8 100644 --- a/cli/cliui/output_test.go +++ b/cli/cliui/output_test.go @@ -6,15 +6,15 @@ import ( "sync/atomic" "testing" - "github.com/spf13/cobra" "github.com/stretchr/testify/require" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" ) type format struct { id string - attachFlagsFn func(cmd *cobra.Command) + attachFlagsFn func(cmd *clibase.Command) formatFn func(ctx context.Context, data any) (string, error) } @@ -24,7 +24,7 @@ func (f *format) ID() string { return f.id } -func (f *format) AttachFlags(cmd *cobra.Command) { +func (f *format) AttachFlags(cmd *clibase.Command) { if f.attachFlagsFn != nil { f.attachFlagsFn(cmd) } @@ -82,7 +82,7 @@ func Test_OutputFormatter(t *testing.T) { cliui.JSONFormat(), &format{ id: "foo", - attachFlagsFn: func(cmd *cobra.Command) { + attachFlagsFn: func(cmd *clibase.Command) { cmd.Flags().StringP("foo", "f", "", "foo flag 1234") }, formatFn: func(_ context.Context, _ any) (string, error) { @@ -92,7 +92,7 @@ func Test_OutputFormatter(t *testing.T) { }, ) - cmd := &cobra.Command{} + cmd := &clibase.Command{} f.AttachFlags(cmd) selected, err := cmd.Flags().GetString("output") diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index e8e651a499d37..e1922b664596f 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -4,13 +4,12 @@ import ( "fmt" "strings" - "github.com/spf13/cobra" - + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/coderd/parameter" "github.com/coder/coder/codersdk" ) -func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.ParameterSchema) (string, error) { +func ParameterSchema(cmd *clibase.Command, parameterSchema codersdk.ParameterSchema) (string, error) { _, _ = fmt.Fprintln(cmd.OutOrStdout(), Styles.Bold.Render("var."+parameterSchema.Name)) if parameterSchema.Description != "" { _, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+strings.TrimSpace(strings.Join(strings.Split(parameterSchema.Description, "\n"), "\n "))+"\n") @@ -61,7 +60,7 @@ func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.ParameterSchem return value, nil } -func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.TemplateVersionParameter) (string, error) { +func RichParameter(cmd *clibase.Command, templateVersionParameter codersdk.TemplateVersionParameter) (string, error) { _, _ = fmt.Fprintln(cmd.OutOrStdout(), Styles.Bold.Render(templateVersionParameter.Name)) if templateVersionParameter.DescriptionPlaintext != "" { _, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n") diff --git a/cli/cliui/prompt.go b/cli/cliui/prompt.go index 86c2aa0e506fd..a5e9805663f3d 100644 --- a/cli/cliui/prompt.go +++ b/cli/cliui/prompt.go @@ -10,8 +10,8 @@ import ( "strings" "github.com/bgentry/speakeasy" + "github.com/coder/coder/cli/clibase" "github.com/mattn/go-isatty" - "github.com/spf13/cobra" "golang.org/x/xerrors" ) @@ -26,7 +26,7 @@ type PromptOptions struct { const skipPromptFlag = "yes" -func AllowSkipPrompt(cmd *cobra.Command) { +func AllowSkipPrompt(cmd *clibase.Command) { cmd.Flags().BoolP(skipPromptFlag, "y", false, "Bypass prompts") } @@ -36,7 +36,7 @@ const ( ) // Prompt asks the user for input. -func Prompt(cmd *cobra.Command, opts PromptOptions) (string, error) { +func Prompt(cmd *clibase.Command, opts PromptOptions) (string, error) { // If the cmd has a "yes" flag for skipping confirm prompts, honor it. // If it's not a "Confirm" prompt, then don't skip. As the default value of // "yes" makes no sense. @@ -114,8 +114,8 @@ func Prompt(cmd *cobra.Command, opts PromptOptions) (string, error) { } } return line, nil - case <-cmd.Context().Done(): - return "", cmd.Context().Err() + case <-inv.Context().Done(): + return "", inv.Context().Err() case <-interrupt: // Print a newline so that any further output starts properly on a new line. _, _ = fmt.Fprintln(cmd.OutOrStdout()) diff --git a/cli/cliui/prompt_test.go b/cli/cliui/prompt_test.go index 6ed029d4bd646..4fe742d92e5f5 100644 --- a/cli/cliui/prompt_test.go +++ b/cli/cliui/prompt_test.go @@ -8,10 +8,10 @@ import ( "os/exec" "testing" - "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/pty" "github.com/coder/coder/pty/ptytest" @@ -77,7 +77,7 @@ func TestPrompt(t *testing.T) { resp, err := newPrompt(ptty, cliui.PromptOptions{ Text: "ShouldNotSeeThis", IsConfirm: true, - }, func(cmd *cobra.Command) { + }, func(cmd *clibase.Command) { cliui.AllowSkipPrompt(cmd) cmd.SetArgs([]string{"-y"}) }) @@ -145,10 +145,10 @@ func TestPrompt(t *testing.T) { }) } -func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions, cmdOpt func(cmd *cobra.Command)) (string, error) { +func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions, cmdOpt func(cmd *clibase.Command)) (string, error) { value := "" - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, args []string) error { + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { var err error value, err = cliui.Prompt(cmd, opts) return err @@ -208,8 +208,8 @@ func TestPasswordTerminalState(t *testing.T) { // nolint:unused func passwordHelper() { - cmd := &cobra.Command{ - Run: func(cmd *cobra.Command, args []string) { + cmd := &clibase.Command{ + Run: func(inv *clibase.Invokation) { cliui.Prompt(cmd, cliui.PromptOptions{ Text: "Password:", Secret: true, diff --git a/cli/cliui/provisionerjob_test.go b/cli/cliui/provisionerjob_test.go index 2fca682859665..346a5ee93cfdc 100644 --- a/cli/cliui/provisionerjob_test.go +++ b/cli/cliui/provisionerjob_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" - "github.com/spf13/cobra" "github.com/stretchr/testify/assert" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/database" "github.com/coder/coder/codersdk" @@ -125,9 +125,9 @@ func newProvisionerJob(t *testing.T) provisionerJobTest { } jobLock := sync.Mutex{} logs := make(chan codersdk.ProvisionerJobLog, 1) - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, args []string) error { - return cliui.ProvisionerJob(cmd.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { + return cliui.ProvisionerJob(inv.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ FetchInterval: time.Millisecond, Fetch: func() (codersdk.ProvisionerJob, error) { jobLock.Lock() diff --git a/cli/cliui/select.go b/cli/cliui/select.go index 17c056ae4ac8a..ae87aee5f187f 100644 --- a/cli/cliui/select.go +++ b/cli/cliui/select.go @@ -8,9 +8,9 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2/terminal" - "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/codersdk" ) @@ -53,7 +53,7 @@ type RichSelectOptions struct { } // RichSelect displays a list of user options including name and description. -func RichSelect(cmd *cobra.Command, richOptions RichSelectOptions) (*codersdk.TemplateVersionParameterOption, error) { +func RichSelect(cmd *clibase.Command, richOptions RichSelectOptions) (*codersdk.TemplateVersionParameterOption, error) { opts := make([]string, len(richOptions.Options)) for i, option := range richOptions.Options { line := option.Name @@ -82,7 +82,7 @@ func RichSelect(cmd *cobra.Command, richOptions RichSelectOptions) (*codersdk.Te } // Select displays a list of user options. -func Select(cmd *cobra.Command, opts SelectOptions) (string, error) { +func Select(cmd *clibase.Command, opts SelectOptions) (string, error) { // The survey library used *always* fails when testing on Windows, // as it requires a live TTY (can't be a conpty). We should fork // this library to add a dummy fallback, that simply reads/writes diff --git a/cli/cliui/select_test.go b/cli/cliui/select_test.go index 915afe5bc120d..4c39f881b5983 100644 --- a/cli/cliui/select_test.go +++ b/cli/cliui/select_test.go @@ -4,10 +4,10 @@ import ( "context" "testing" - "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" "github.com/coder/coder/pty/ptytest" @@ -32,8 +32,8 @@ func TestSelect(t *testing.T) { func newSelect(ptty *ptytest.PTY, opts cliui.SelectOptions) (string, error) { value := "" - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, args []string) error { + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { var err error value, err = cliui.Select(cmd, opts) return err @@ -73,8 +73,8 @@ func TestRichSelect(t *testing.T) { func newRichSelect(ptty *ptytest.PTY, opts cliui.RichSelectOptions) (string, error) { value := "" - cmd := &cobra.Command{ - RunE: func(cmd *cobra.Command, args []string) error { + cmd := &clibase.Command{ + Handler: func(inv *clibase.Invokation) error { richOption, err := cliui.RichSelect(cmd, opts) if err == nil { value = richOption.Value diff --git a/cli/configssh.go b/cli/configssh.go index 85efed8d5666c..b46649ca466fc 100644 --- a/cli/configssh.go +++ b/cli/configssh.go @@ -22,6 +22,7 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" @@ -132,7 +133,7 @@ func sshPrepareWorkspaceConfigs(ctx context.Context, client *codersdk.Client) (r } } -func configSSH() *cobra.Command { +func configSSH() *clibase.Command { var ( sshConfigFile string sshConfigOpts sshConfigOptions @@ -140,7 +141,7 @@ func configSSH() *cobra.Command { dryRun bool skipProxyCommand bool ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "config-ssh", Short: "Add an SSH Host entry for your workspaces \"ssh coder.workspace\"", @@ -155,13 +156,13 @@ func configSSH() *cobra.Command { }, ), Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, _ []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err } - recvWorkspaceConfigs := sshPrepareWorkspaceConfigs(cmd.Context(), client) + recvWorkspaceConfigs := sshPrepareWorkspaceConfigs(inv.Context(), client) out := cmd.OutOrStdout() if dryRun { diff --git a/cli/create.go b/cli/create.go index 5c95697db9cde..eab1d96fdd131 100644 --- a/cli/create.go +++ b/cli/create.go @@ -6,17 +6,17 @@ import ( "io" "time" - "github.com/spf13/cobra" "golang.org/x/exp/slices" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) -func create() *cobra.Command { +func create() *clibase.Command { var ( parameterFile string richParameterFile string @@ -25,11 +25,11 @@ func create() *cobra.Command { stopAfter time.Duration workspaceName string ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "create [name]", Short: "Create a workspace", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -48,7 +48,7 @@ func create() *cobra.Command { workspaceName, err = cliui.Prompt(cmd, cliui.PromptOptions{ Text: "Specify a name for your workspace:", Validate: func(workspaceName string) error { - _, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceOptions{}) + _, err = client.WorkspaceByOwnerAndName(inv.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceOptions{}) if err == nil { return xerrors.Errorf("A workspace already exists named %q!", workspaceName) } @@ -60,7 +60,7 @@ func create() *cobra.Command { } } - _, err = client.WorkspaceByOwnerAndName(cmd.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceOptions{}) + _, err = client.WorkspaceByOwnerAndName(inv.Context(), codersdk.Me, workspaceName, codersdk.WorkspaceOptions{}) if err == nil { return xerrors.Errorf("A workspace already exists named %q!", workspaceName) } @@ -69,7 +69,7 @@ func create() *cobra.Command { if templateName == "" { _, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Wrap.Render("Select a template below to preview the provisioned infrastructure:")) - templates, err := client.TemplatesByOrganization(cmd.Context(), organization.ID) + templates, err := client.TemplatesByOrganization(inv.Context(), organization.ID) if err != nil { return err } @@ -108,7 +108,7 @@ func create() *cobra.Command { template = templateByName[option] } else { - template, err = client.TemplateByName(cmd.Context(), organization.ID, templateName) + template, err = client.TemplateByName(inv.Context(), organization.ID, templateName) if err != nil { return xerrors.Errorf("get template by name: %w", err) } @@ -142,7 +142,7 @@ func create() *cobra.Command { return err } - workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.Me, codersdk.CreateWorkspaceRequest{ + workspace, err := client.CreateWorkspace(inv.Context(), organization.ID, codersdk.Me, codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: workspaceName, AutostartSchedule: schedSpec, @@ -154,7 +154,7 @@ func create() *cobra.Command { return err } - err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, workspace.LatestBuild.ID) + err = cliui.WorkspaceBuild(inv.Context(), cmd.OutOrStdout(), client, workspace.LatestBuild.ID) if err != nil { return err } @@ -193,8 +193,8 @@ type buildParameters struct { // prepWorkspaceBuild will ensure a workspace build will succeed on the latest template version. // Any missing params will be prompted to the user. It supports legacy and rich parameters. -func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWorkspaceBuildArgs) (*buildParameters, error) { - ctx := cmd.Context() +func prepWorkspaceBuild(cmd *clibase.Command, client *codersdk.Client, args prepWorkspaceBuildArgs) (*buildParameters, error) { + ctx := inv.Context() var useRichParameters bool if len(args.ExistingRichParams) > 0 && len(args.RichParameterFile) > 0 { @@ -273,7 +273,7 @@ PromptParamLoop: } // Rich parameters - templateVersionParameters, err := client.TemplateVersionRichParameters(cmd.Context(), templateVersion.ID) + templateVersionParameters, err := client.TemplateVersionRichParameters(inv.Context(), templateVersion.ID) if err != nil { return nil, xerrors.Errorf("get template version rich parameters: %w", err) } @@ -335,7 +335,7 @@ PromptRichParamLoop: } // Run a dry-run with the given parameters to check correctness - dryRun, err := client.CreateTemplateVersionDryRun(cmd.Context(), templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{ + dryRun, err := client.CreateTemplateVersionDryRun(inv.Context(), templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{ WorkspaceName: args.NewWorkspaceName, ParameterValues: legacyParameters, RichParameterValues: richParameters, @@ -344,15 +344,15 @@ PromptRichParamLoop: return nil, xerrors.Errorf("begin workspace dry-run: %w", err) } _, _ = fmt.Fprintln(cmd.OutOrStdout(), "Planning workspace...") - err = cliui.ProvisionerJob(cmd.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ + err = cliui.ProvisionerJob(inv.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ Fetch: func() (codersdk.ProvisionerJob, error) { - return client.TemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID) + return client.TemplateVersionDryRun(inv.Context(), templateVersion.ID, dryRun.ID) }, Cancel: func() error { - return client.CancelTemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID) + return client.CancelTemplateVersionDryRun(inv.Context(), templateVersion.ID, dryRun.ID) }, Logs: func() (<-chan codersdk.ProvisionerJobLog, io.Closer, error) { - return client.TemplateVersionDryRunLogsAfter(cmd.Context(), templateVersion.ID, dryRun.ID, 0) + return client.TemplateVersionDryRunLogsAfter(inv.Context(), templateVersion.ID, dryRun.ID, 0) }, // Don't show log output for the dry-run unless there's an error. Silent: true, @@ -363,7 +363,7 @@ PromptRichParamLoop: return nil, xerrors.Errorf("dry-run workspace: %w", err) } - resources, err := client.TemplateVersionDryRunResources(cmd.Context(), templateVersion.ID, dryRun.ID) + resources, err := client.TemplateVersionDryRunResources(inv.Context(), templateVersion.ID, dryRun.ID) if err != nil { return nil, xerrors.Errorf("get workspace dry-run resources: %w", err) } diff --git a/cli/create_test.go b/cli/create_test.go index 836815212d06e..dc3a11521217a 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -136,7 +136,7 @@ func TestCreate(t *testing.T) { } <-doneChan - ws, err := client.WorkspaceByOwnerAndName(cmd.Context(), "testuser", "my-workspace", codersdk.WorkspaceOptions{}) + ws, err := client.WorkspaceByOwnerAndName(inv.Context(), "testuser", "my-workspace", codersdk.WorkspaceOptions{}) if assert.NoError(t, err, "expected workspace to be created") { assert.Equal(t, ws.TemplateName, template.Name) assert.Nil(t, ws.AutostartSchedule, "expected workspace autostart schedule to be nil") diff --git a/cli/delete.go b/cli/delete.go index 384d16a273322..d0e80e7fb8d61 100644 --- a/cli/delete.go +++ b/cli/delete.go @@ -6,20 +6,21 @@ import ( "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) // nolint -func deleteWorkspace() *cobra.Command { +func deleteWorkspace() *clibase.Command { var orphan bool - cmd := &cobra.Command{ + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "delete ", Short: "Delete a workspace", Aliases: []string{"rm"}, Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { _, err := cliui.Prompt(cmd, cliui.PromptOptions{ Text: "Confirm delete workspace?", IsConfirm: true, @@ -42,12 +43,12 @@ func deleteWorkspace() *cobra.Command { if orphan { cliui.Warn( - cmd.ErrOrStderr(), + inv.Stderr, "Orphaning workspace requires template edit permission", ) } - build, err := client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + build, err := client.CreateWorkspaceBuild(inv.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ Transition: codersdk.WorkspaceTransitionDelete, ProvisionerState: state, Orphan: orphan, @@ -56,7 +57,7 @@ func deleteWorkspace() *cobra.Command { return err } - err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, build.ID) + err = cliui.WorkspaceBuild(inv.Context(), cmd.OutOrStdout(), client, build.ID) if err != nil { return err } diff --git a/cli/dotfiles.go b/cli/dotfiles.go index 4adb06cc05f9a..1caecd46b15bb 100644 --- a/cli/dotfiles.go +++ b/cli/dotfiles.go @@ -13,13 +13,14 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" ) -func dotfiles() *cobra.Command { +func dotfiles() *clibase.Command { var symlinkDir string - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "dotfiles [git_repo_url]", Args: cobra.ExactArgs(1), Short: "Checkout and install a dotfiles repository from a Git URL", @@ -29,7 +30,7 @@ func dotfiles() *cobra.Command { Command: "coder dotfiles --yes git@github.com:example/dotfiles.git", }, ), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { var ( dotfilesRepoDir = "dotfiles" gitRepo = args[0] @@ -123,11 +124,11 @@ func dotfiles() *cobra.Command { } // clone or pull repo - c := exec.CommandContext(cmd.Context(), "git", subcommands...) + c := exec.CommandContext(inv.Context(), "git", subcommands...) c.Dir = gitCmdDir c.Env = append(os.Environ(), fmt.Sprintf(`GIT_SSH_COMMAND=%s -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no`, gitsshCmd)) c.Stdout = cmd.OutOrStdout() - c.Stderr = cmd.ErrOrStderr() + c.Stderr = inv.Stderr err = c.Run() if err != nil { if !dotfilesExists { @@ -170,10 +171,10 @@ func dotfiles() *cobra.Command { // it is safe to use a variable command here because it's from // a filtered list of pre-approved install scripts // nolint:gosec - scriptCmd := exec.CommandContext(cmd.Context(), filepath.Join(dotfilesDir, script)) + scriptCmd := exec.CommandContext(inv.Context(), filepath.Join(dotfilesDir, script)) scriptCmd.Dir = dotfilesDir scriptCmd.Stdout = cmd.OutOrStdout() - scriptCmd.Stderr = cmd.ErrOrStderr() + scriptCmd.Stderr = inv.Stderr err = scriptCmd.Run() if err != nil { return xerrors.Errorf("running %s: %w", script, err) diff --git a/cli/gitssh.go b/cli/gitssh.go index 02a985abee22f..1c1ad35d542ce 100644 --- a/cli/gitssh.go +++ b/cli/gitssh.go @@ -12,19 +12,19 @@ import ( "path/filepath" "strings" - "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" ) -func gitssh() *cobra.Command { - cmd := &cobra.Command{ +func gitssh() *clibase.Command { + cmd := &clibase.Command{ Use: "gitssh", Hidden: true, Short: `Wraps the "ssh" command and uses the coder gitssh key for authentication`, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() + Handler: func(inv *clibase.Invokation) error { + ctx := inv.Context() env := os.Environ() // Catch interrupt signals to ensure the temporary private @@ -81,21 +81,21 @@ func gitssh() *cobra.Command { args = append(identityArgs, args...) c := exec.CommandContext(ctx, "ssh", args...) c.Env = append(c.Env, env...) - c.Stderr = cmd.ErrOrStderr() + c.Stderr = inv.Stderr c.Stdout = cmd.OutOrStdout() c.Stdin = cmd.InOrStdin() err = c.Run() if err != nil { exitErr := &exec.ExitError{} if xerrors.As(err, &exitErr) && exitErr.ExitCode() == 255 { - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), + _, _ = fmt.Fprintln(inv.Stderr, "\n"+cliui.Styles.Wrap.Render("Coder authenticates with "+cliui.Styles.Field.Render("git")+ " using the public key below. All clones with SSH are authenticated automatically 🪄.")+"\n") - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n") - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Add to GitHub and GitLab:") - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Prompt.String()+"https://github.com/settings/ssh/new") - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Prompt.String()+"https://gitlab.com/-/profile/keys") - _, _ = fmt.Fprintln(cmd.ErrOrStderr()) + _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n") + _, _ = fmt.Fprintln(inv.Stderr, "Add to GitHub and GitLab:") + _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"https://github.com/settings/ssh/new") + _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"https://gitlab.com/-/profile/keys") + _, _ = fmt.Fprintln(inv.Stderr) return err } return xerrors.Errorf("run ssh command: %w", err) diff --git a/cli/list.go b/cli/list.go index a69945084f4db..2f6d4c57f6d85 100644 --- a/cli/list.go +++ b/cli/list.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/schedule" "github.com/coder/coder/coderd/util/ptr" @@ -64,7 +65,7 @@ func workspaceListRowFromWorkspace(now time.Time, usersByID map[uuid.UUID]coders } } -func list() *cobra.Command { +func list() *clibase.Command { var ( all bool defaultQuery = "owner:me" @@ -75,13 +76,13 @@ func list() *cobra.Command { cliui.JSONFormat(), ) ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "list", Short: "List workspaces", Aliases: []string{"ls"}, Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -94,19 +95,19 @@ func list() *cobra.Command { filter.FilterQuery = "" } - res, err := client.Workspaces(cmd.Context(), filter) + res, err := client.Workspaces(inv.Context(), filter) if err != nil { return err } if len(res.Workspaces) == 0 { - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Prompt.String()+"No workspaces found! Create one:") - _, _ = fmt.Fprintln(cmd.ErrOrStderr()) - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), " "+cliui.Styles.Code.Render("coder create ")) - _, _ = fmt.Fprintln(cmd.ErrOrStderr()) + _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"No workspaces found! Create one:") + _, _ = fmt.Fprintln(inv.Stderr) + _, _ = fmt.Fprintln(inv.Stderr, " "+cliui.Styles.Code.Render("coder create ")) + _, _ = fmt.Fprintln(inv.Stderr) return nil } - userRes, err := client.Users(cmd.Context(), codersdk.UsersRequest{}) + userRes, err := client.Users(inv.Context(), codersdk.UsersRequest{}) if err != nil { return err } @@ -122,7 +123,7 @@ func list() *cobra.Command { displayWorkspaces[i] = workspaceListRowFromWorkspace(now, usersByID, workspace) } - out, err := formatter.Format(cmd.Context(), displayWorkspaces) + out, err := formatter.Format(inv.Context(), displayWorkspaces) if err != nil { return err } diff --git a/cli/login.go b/cli/login.go index bda389c3fe771..d8ca385b39f6e 100644 --- a/cli/login.go +++ b/cli/login.go @@ -17,6 +17,7 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/userpassword" @@ -38,7 +39,7 @@ func init() { browser.Stdout = io.Discard } -func login() *cobra.Command { +func login() *clibase.Command { const firstUserTrialEnv = "CODER_FIRST_USER_TRIAL" var ( @@ -47,11 +48,11 @@ func login() *cobra.Command { password string trial bool ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "login ", Short: "Authenticate with Coder deployment", Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { rawURL := "" if len(args) == 0 { var err error @@ -91,10 +92,10 @@ func login() *cobra.Command { if err != nil { // Checking versions isn't a fatal error so we print a warning // and proceed. - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Warn.Render(err.Error())) + _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Warn.Render(err.Error())) } - hasInitialUser, err := client.HasFirstUser(cmd.Context()) + hasInitialUser, err := client.HasFirstUser(inv.Context()) if err != nil { return xerrors.Errorf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser? Error - has initial user: %w", serverURL.String(), err) } @@ -187,7 +188,7 @@ func login() *cobra.Command { trial = v == "yes" || v == "y" } - _, err = client.CreateFirstUser(cmd.Context(), codersdk.CreateFirstUserRequest{ + _, err = client.CreateFirstUser(inv.Context(), codersdk.CreateFirstUserRequest{ Email: email, Username: username, Password: password, @@ -196,7 +197,7 @@ func login() *cobra.Command { if err != nil { return xerrors.Errorf("create initial user: %w", err) } - resp, err := client.LoginWithPassword(cmd.Context(), codersdk.LoginWithPasswordRequest{ + resp, err := client.LoginWithPassword(inv.Context(), codersdk.LoginWithPasswordRequest{ Email: email, Password: password, }) @@ -240,7 +241,7 @@ func login() *cobra.Command { Secret: true, Validate: func(token string) error { client.SetSessionToken(token) - _, err := client.User(cmd.Context(), codersdk.Me) + _, err := client.User(inv.Context(), codersdk.Me) if err != nil { return xerrors.New("That's not a valid token!") } @@ -254,7 +255,7 @@ func login() *cobra.Command { // Login to get user data - verify it is OK before persisting client.SetSessionToken(sessionToken) - resp, err := client.User(cmd.Context(), codersdk.Me) + resp, err := client.User(inv.Context(), codersdk.Me) if err != nil { return xerrors.Errorf("get user: %w", err) } @@ -293,7 +294,7 @@ func isWSL() (bool, error) { } // openURL opens the provided URL via user's default browser -func openURL(cmd *cobra.Command, urlToOpen string) error { +func openURL(cmd *clibase.Command, urlToOpen string) error { noOpen, err := cmd.Flags().GetBool(varNoOpen) if err != nil { panic(err) @@ -314,7 +315,7 @@ func openURL(cmd *cobra.Command, urlToOpen string) error { browserEnv := os.Getenv("BROWSER") if browserEnv != "" { browserSh := fmt.Sprintf("%s '%s'", browserEnv, urlToOpen) - cmd := exec.CommandContext(cmd.Context(), "sh", "-c", browserSh) + cmd := exec.CommandContext(inv.Context(), "sh", "-c", browserSh) out, err := cmd.CombinedOutput() if err != nil { return xerrors.Errorf("failed to run %v (out: %q): %w", cmd.Args, out, err) diff --git a/cli/logout.go b/cli/logout.go index 689bd4f949857..59b81a147055b 100644 --- a/cli/logout.go +++ b/cli/logout.go @@ -5,17 +5,17 @@ import ( "os" "strings" - "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" ) -func logout() *cobra.Command { - cmd := &cobra.Command{ +func logout() *clibase.Command { + cmd := &clibase.Command{ Use: "logout", Short: "Unauthenticate your local session", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -34,7 +34,7 @@ func logout() *cobra.Command { return err } - err = client.Logout(cmd.Context()) + err = client.Logout(inv.Context()) if err != nil { errors = append(errors, xerrors.Errorf("logout api: %w", err)) } diff --git a/cli/parameter.go b/cli/parameter.go index d826b1ec69dbf..e3a3f8d1dbe0c 100644 --- a/cli/parameter.go +++ b/cli/parameter.go @@ -3,10 +3,10 @@ package cli import ( "os" - "github.com/spf13/cobra" "golang.org/x/xerrors" "gopkg.in/yaml.v3" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) @@ -36,7 +36,7 @@ func createParameterMapFromFile(parameterFile string) (map[string]string, error) // Returns a parameter value from a given map, if the map does not exist or does not contain the item, it takes input from the user. // Throws an error if there are any errors with the users input. -func getParameterValueFromMapOrInput(cmd *cobra.Command, parameterMap map[string]string, parameterSchema codersdk.ParameterSchema) (string, error) { +func getParameterValueFromMapOrInput(cmd *clibase.Command, parameterMap map[string]string, parameterSchema codersdk.ParameterSchema) (string, error) { var parameterValue string var err error if parameterMap != nil { @@ -57,7 +57,7 @@ func getParameterValueFromMapOrInput(cmd *cobra.Command, parameterMap map[string return parameterValue, nil } -func getWorkspaceBuildParameterValueFromMapOrInput(cmd *cobra.Command, parameterMap map[string]string, templateVersionParameter codersdk.TemplateVersionParameter) (*codersdk.WorkspaceBuildParameter, error) { +func getWorkspaceBuildParameterValueFromMapOrInput(cmd *clibase.Command, parameterMap map[string]string, templateVersionParameter codersdk.TemplateVersionParameter) (*codersdk.WorkspaceBuildParameter, error) { var parameterValue string var err error if parameterMap != nil { diff --git a/cli/parameters.go b/cli/parameters.go index 3fb54973ab98b..43df342573acb 100644 --- a/cli/parameters.go +++ b/cli/parameters.go @@ -1,11 +1,12 @@ package cli import ( - "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" + "gvisor.dev/gvisor/runsc/cmd" ) -func parameters() *cobra.Command { - cmd := &cobra.Command{ +func parameters() *clibase.Command { + cmd := &clibase.Command{ Short: "List parameters for a given scope", Example: formatExamples( example{ @@ -20,7 +21,7 @@ func parameters() *cobra.Command { // constructing curl requests. Hidden: true, Aliases: []string{"params"}, - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { return cmd.Help() }, } diff --git a/cli/parameterslist.go b/cli/parameterslist.go index 3539e19696bd2..89bf4e5946efd 100644 --- a/cli/parameterslist.go +++ b/cli/parameterslist.go @@ -7,21 +7,22 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func parameterList() *cobra.Command { +func parameterList() *clibase.Command { formatter := cliui.NewOutputFormatter( cliui.TableFormat([]codersdk.Parameter{}, []string{"name", "scope", "destination scheme"}), cliui.JSONFormat(), ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "list", Aliases: []string{"ls"}, Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { scope, name := args[0], args[1] client, err := useClient(cmd) @@ -43,7 +44,7 @@ func parameterList() *cobra.Command { } scopeID = workspace.ID case codersdk.ParameterTemplate: - template, err := client.TemplateByName(cmd.Context(), organization.ID, name) + template, err := client.TemplateByName(inv.Context(), organization.ID, name) if err != nil { return xerrors.Errorf("get workspace template: %w", err) } @@ -57,7 +58,7 @@ func parameterList() *cobra.Command { // Could be a template_version id or a job id. Check for the // version id. - tv, err := client.TemplateVersion(cmd.Context(), scopeID) + tv, err := client.TemplateVersion(inv.Context(), scopeID) if err == nil { scopeID = tv.Job.ID } @@ -68,12 +69,12 @@ func parameterList() *cobra.Command { }) } - params, err := client.Parameters(cmd.Context(), codersdk.ParameterScope(scope), scopeID) + params, err := client.Parameters(inv.Context(), codersdk.ParameterScope(scope), scopeID) if err != nil { return xerrors.Errorf("fetch params: %w", err) } - out, err := formatter.Format(cmd.Context(), params) + out, err := formatter.Format(inv.Context(), params) if err != nil { return xerrors.Errorf("render output: %w", err) } diff --git a/cli/ping.go b/cli/ping.go index 7c596064fcea8..6c88f4d551e21 100644 --- a/cli/ping.go +++ b/cli/ping.go @@ -11,24 +11,25 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func ping() *cobra.Command { +func ping() *clibase.Command { var ( pingNum int pingTimeout time.Duration pingWait time.Duration verbose bool ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "ping ", Short: "Ping a workspace", Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithCancel(cmd.Context()) + Handler: func(inv *clibase.Invokation) error { + ctx, cancel := context.WithCancel(inv.Context()) defer cancel() client, err := useClient(cmd) diff --git a/cli/portforward.go b/cli/portforward.go index 1b34dd9062216..768374365928e 100644 --- a/cli/portforward.go +++ b/cli/portforward.go @@ -16,17 +16,18 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/agent" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func portForward() *cobra.Command { +func portForward() *clibase.Command { var ( tcpForwards []string // : udpForwards []string // : ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "port-forward ", Short: "Forward ports from machine to a workspace", Aliases: []string{"tunnel"}, @@ -49,8 +50,8 @@ func portForward() *cobra.Command { Command: "coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012", }, ), - RunE: func(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithCancel(cmd.Context()) + Handler: func(inv *clibase.Invokation) error { + ctx, cancel := context.WithCancel(inv.Context()) defer cancel() specs, err := parsePortForwards(tcpForwards, udpForwards) @@ -78,13 +79,13 @@ func portForward() *cobra.Command { return xerrors.New("workspace must be in start transition to port-forward") } if workspace.LatestBuild.Job.CompletedAt == nil { - err = cliui.WorkspaceBuild(ctx, cmd.ErrOrStderr(), client, workspace.LatestBuild.ID) + err = cliui.WorkspaceBuild(ctx, inv.Stderr, client, workspace.LatestBuild.ID) if err != nil { return err } } - err = cliui.Agent(ctx, cmd.ErrOrStderr(), cliui.AgentOptions{ + err = cliui.Agent(ctx, inv.Stderr, cliui.AgentOptions{ WorkspaceName: workspace.Name, Fetch: func(ctx context.Context) (codersdk.WorkspaceAgent, error) { return client.WorkspaceAgent(ctx, workspaceAgent.ID) @@ -156,7 +157,7 @@ func portForward() *cobra.Command { return cmd } -func listenAndPortForward(ctx context.Context, cmd *cobra.Command, conn *codersdk.WorkspaceAgentConn, wg *sync.WaitGroup, spec portForwardSpec) (net.Listener, error) { +func listenAndPortForward(ctx context.Context, cmd *clibase.Command, conn *codersdk.WorkspaceAgentConn, wg *sync.WaitGroup, spec portForwardSpec) (net.Listener, error) { _, _ = fmt.Fprintf(cmd.OutOrStderr(), "Forwarding '%v://%v' locally to '%v://%v' in the workspace\n", spec.listenNetwork, spec.listenAddress, spec.dialNetwork, spec.dialAddress) var ( diff --git a/cli/publickey.go b/cli/publickey.go index 0064bef401cc7..8d693615e9e30 100644 --- a/cli/publickey.go +++ b/cli/publickey.go @@ -3,21 +3,21 @@ package cli import ( "strings" - "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func publickey() *cobra.Command { +func publickey() *clibase.Command { var reset bool - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "publickey", Aliases: []string{"pubkey"}, Short: "Output your Coder public key used for Git operations", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) @@ -36,13 +36,13 @@ func publickey() *cobra.Command { } // Reset the public key, let the retrieve re-read it. - _, err = client.RegenerateGitSSHKey(cmd.Context(), codersdk.Me) + _, err = client.RegenerateGitSSHKey(inv.Context(), codersdk.Me) if err != nil { return err } } - key, err := client.GitSSHKey(cmd.Context(), codersdk.Me) + key, err := client.GitSSHKey(inv.Context(), codersdk.Me) if err != nil { return xerrors.Errorf("create codersdk client: %w", err) } diff --git a/cli/rename.go b/cli/rename.go index fb6383d1c5cd8..ab2519558f9d5 100644 --- a/cli/rename.go +++ b/cli/rename.go @@ -6,17 +6,18 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func rename() *cobra.Command { - cmd := &cobra.Command{ +func rename() *clibase.Command { + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "rename ", Short: "Rename a workspace", Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -43,7 +44,7 @@ func rename() *cobra.Command { return err } - err = client.UpdateWorkspace(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceRequest{ + err = client.UpdateWorkspace(inv.Context(), workspace.ID, codersdk.UpdateWorkspaceRequest{ Name: args[1], }) if err != nil { diff --git a/cli/resetpassword.go b/cli/resetpassword.go index 8aea553730f1c..fee4c7e38e30a 100644 --- a/cli/resetpassword.go +++ b/cli/resetpassword.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/database" @@ -14,14 +15,14 @@ import ( "github.com/coder/coder/coderd/userpassword" ) -func resetPassword() *cobra.Command { +func resetPassword() *clibase.Command { var postgresURL string - root := &cobra.Command{ + root := &clibase.Command{ Use: "reset-password ", Short: "Directly connect to the database to reset a user's password", Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { username := args[0] sqlDB, err := sql.Open("postgres", postgresURL) @@ -40,7 +41,7 @@ func resetPassword() *cobra.Command { } db := database.New(sqlDB) - user, err := db.GetUserByEmailOrUsername(cmd.Context(), database.GetUserByEmailOrUsernameParams{ + user, err := db.GetUserByEmailOrUsername(inv.Context(), database.GetUserByEmailOrUsernameParams{ Username: username, }) if err != nil { @@ -74,7 +75,7 @@ func resetPassword() *cobra.Command { return xerrors.Errorf("hash password: %w", err) } - err = db.UpdateUserHashedPassword(cmd.Context(), database.UpdateUserHashedPasswordParams{ + err = db.UpdateUserHashedPassword(inv.Context(), database.UpdateUserHashedPasswordParams{ ID: user.ID, HashedPassword: []byte(hashedPassword), }) diff --git a/cli/restart.go b/cli/restart.go index 693e9bfd5cfd2..f96b415fb7ab9 100644 --- a/cli/restart.go +++ b/cli/restart.go @@ -6,18 +6,19 @@ import ( "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func restart() *cobra.Command { - cmd := &cobra.Command{ +func restart() *clibase.Command { + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "restart ", Short: "Restart a workspace", Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() + Handler: func(inv *clibase.Invokation) error { + ctx := inv.Context() out := cmd.OutOrStdout() _, err := cliui.Prompt(cmd, cliui.PromptOptions{ diff --git a/cli/root.go b/cli/root.go index 0e5aebebb4034..3af00f6f647bc 100644 --- a/cli/root.go +++ b/cli/root.go @@ -233,11 +233,11 @@ func LoggerFromContext(ctx context.Context) (slog.Logger, bool) { } // versionCmd prints the coder version -func versionCmd() *cobra.Command { - return &cobra.Command{ +func versionCmd() *clibase.Command { + return &clibase.Command{ Use: "version", Short: "Show coder version", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { var str strings.Builder _, _ = str.WriteString("Coder ") if buildinfo.IsAGPL() { @@ -383,7 +383,7 @@ func (r *RootCmd) createUnauthenticatedClient(serverURL *url.URL) (*codersdk.Cli // createAgentClient returns a new client from the command context. // It works just like CreateClient, but uses the agent token and URL instead. -func createAgentClient(cmd *cobra.Command) (*agentsdk.Client, error) { +func createAgentClient(cmd *clibase.Command) (*agentsdk.Client, error) { rawURL, err := cmd.Flags().GetString(varAgentURL) if err != nil { return nil, err @@ -402,8 +402,8 @@ func createAgentClient(cmd *cobra.Command) (*agentsdk.Client, error) { } // CurrentOrganization returns the currently active organization for the authenticated user. -func CurrentOrganization(cmd *cobra.Command, client *codersdk.Client) (codersdk.Organization, error) { - orgs, err := client.OrganizationsByUser(cmd.Context(), codersdk.Me) +func CurrentOrganization(cmd *clibase.Command, client *codersdk.Client) (codersdk.Organization, error) { + orgs, err := client.OrganizationsByUser(inv.Context(), codersdk.Me) if err != nil { return codersdk.Organization{}, nil } @@ -441,7 +441,7 @@ func (r *RootCmd) createConfig() config.Root { // isTTY returns whether the passed reader is a TTY or not. // This accepts a reader to work with Cobra's "InOrStdin" // function for simple testing. -func isTTY(cmd *cobra.Command) bool { +func isTTY(cmd *clibase.Command) bool { // If the `--force-tty` command is available, and set, // assume we're in a tty. This is primarily for cases on Windows // where we may not be able to reliably detect this automatically (ie, tests) @@ -459,18 +459,18 @@ func isTTY(cmd *cobra.Command) bool { // isTTYOut returns whether the passed reader is a TTY or not. // This accepts a reader to work with Cobra's "OutOrStdout" // function for simple testing. -func isTTYOut(cmd *cobra.Command) bool { +func isTTYOut(cmd *clibase.Command) bool { return isTTYWriter(cmd, cmd.OutOrStdout) } // isTTYErr returns whether the passed reader is a TTY or not. // This accepts a reader to work with Cobra's "ErrOrStderr" // function for simple testing. -func isTTYErr(cmd *cobra.Command) bool { +func isTTYErr(cmd *clibase.Command) bool { return isTTYWriter(cmd, cmd.ErrOrStderr) } -func isTTYWriter(cmd *cobra.Command, writer func() io.Writer) bool { +func isTTYWriter(cmd *clibase.Command, writer func() io.Writer) bool { // If the `--force-tty` command is available, and set, // assume we're in a tty. This is primarily for cases on Windows // where we may not be able to reliably detect this automatically (ie, tests) @@ -496,12 +496,12 @@ func usageHeader(s string) string { return cliui.Styles.Placeholder.Render(s) } -func isWorkspaceCommand(cmd *cobra.Command) bool { +func isWorkspaceCommand(cmd *clibase.Command) bool { if _, ok := cmd.Annotations["workspaces"]; ok { return true } var ws bool - cmd.VisitParents(func(cmd *cobra.Command) { + cmd.VisitParents(func(cmd *clibase.Command) { if _, ok := cmd.Annotations["workspaces"]; ok { ws = true } @@ -604,8 +604,8 @@ func formatExamples(examples ...example) string { return sb.String() } -// FormatCobraError colorizes and adds "--help" docs to cobra commands. -func FormatCobraError(err error, cmd *cobra.Command) string { +// FormatCobraError colorizes and adds "--help" docs to clibase.Commands. +func FormatCobraError(err error, cmd *clibase.Command) string { helpErrMsg := fmt.Sprintf("Run '%s --help' for usage.", cmd.CommandPath()) var ( diff --git a/cli/root_test.go b/cli/root_test.go index f2acbaa0299b0..edb06c9ad9043 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -14,13 +14,13 @@ import ( "strings" "testing" - "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/xerrors" "github.com/coder/coder/buildinfo" "github.com/coder/coder/cli" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/clitest" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/coderd/database/dbtestutil" @@ -172,7 +172,7 @@ ExtractCommandPathsLoop: } } -func extractVisibleCommandPaths(cmdPath []string, cmds []*cobra.Command) [][]string { +func extractVisibleCommandPaths(cmdPath []string, cmds []*clibase.Command) [][]string { var cmdPaths [][]string for _, c := range cmds { if c.Hidden { @@ -263,7 +263,7 @@ func TestRoot(t *testing.T) { cmd, _ := clitest.New(t) - cmd.RunE = func(cmd *cobra.Command, args []string) error { + cmd.RunE = func(inv *clibase.Invokation) error { var err error = &codersdk.Error{ Response: codersdk.Response{ Message: "This is a message.", @@ -289,7 +289,7 @@ func TestRoot(t *testing.T) { cmd, _ := clitest.New(t) - cmd.RunE = func(cmd *cobra.Command, args []string) error { + cmd.RunE = func(inv *clibase.Invokation) error { return xerrors.Errorf("this is a non-codersdk error: %w", xerrors.Errorf("a wrapped error")) } @@ -305,7 +305,7 @@ func TestRoot(t *testing.T) { cmd, _ := clitest.New(t, "--verbose") - cmd.RunE = func(cmd *cobra.Command, args []string) error { + cmd.RunE = func(inv *clibase.Invokation) error { var err error = &codersdk.Error{ Response: codersdk.Response{ Message: "This is a message.", @@ -330,7 +330,7 @@ func TestRoot(t *testing.T) { cmd, _ := clitest.New(t, "--verbose") - cmd.RunE = func(cmd *cobra.Command, args []string) error { + cmd.RunE = func(inv *clibase.Invokation) error { return xerrors.Errorf("this is a non-codersdk error: %w", xerrors.Errorf("a wrapped error")) } diff --git a/cli/scaletest.go b/cli/scaletest.go index 4e05813ce4698..fba571b1d85d2 100644 --- a/cli/scaletest.go +++ b/cli/scaletest.go @@ -14,10 +14,10 @@ import ( "time" "github.com/google/uuid" - "github.com/spf13/cobra" "go.opentelemetry.io/otel/trace" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/httpapi" @@ -33,12 +33,12 @@ import ( const scaletestTracerName = "coder_scaletest" -func scaletest() *cobra.Command { - cmd := &cobra.Command{ +func scaletest() *clibase.Command { + cmd := &clibase.Command{ Use: "scaletest", Short: "Run a scale test against the Coder API", Long: "Perform scale tests against the Coder server.", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { return cmd.Help() }, } @@ -58,7 +58,7 @@ type scaletestTracingFlags struct { tracePropagate bool } -func (s *scaletestTracingFlags) attach(cmd *cobra.Command) { +func (s *scaletestTracingFlags) attach(cmd *clibase.Command) { cliflag.BoolVarP(cmd.Flags(), &s.traceEnable, "trace", "", "CODER_LOADTEST_TRACE", false, "Whether application tracing data is collected. It exports to a backend configured by environment variables. See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md") cliflag.BoolVarP(cmd.Flags(), &s.traceCoder, "trace-coder", "", "CODER_LOADTEST_TRACE_CODER", false, "Whether opentelemetry traces are sent to Coder. We recommend keeping this disabled unless we advise you to enable it.") cliflag.StringVarP(cmd.Flags(), &s.traceHoneycombAPIKey, "trace-honeycomb-api-key", "", "CODER_LOADTEST_TRACE_HONEYCOMB_API_KEY", "", "Enables trace exporting to Honeycomb.io using the provided API key.") @@ -101,7 +101,7 @@ type scaletestStrategyFlags struct { timeoutPerJob time.Duration } -func (s *scaletestStrategyFlags) attach(cmd *cobra.Command) { +func (s *scaletestStrategyFlags) attach(cmd *clibase.Command) { concurrencyLong, concurrencyEnv, concurrencyDescription := "concurrency", "CODER_LOADTEST_CONCURRENCY", "Number of concurrent jobs to run. 0 means unlimited." timeoutLong, timeoutEnv, timeoutDescription := "timeout", "CODER_LOADTEST_TIMEOUT", "Timeout for the entire test run. 0 means unlimited." jobTimeoutLong, jobTimeoutEnv, jobTimeoutDescription := "job-timeout", "CODER_LOADTEST_JOB_TIMEOUT", "Timeout per job. Jobs may take longer to complete under higher concurrency limits." @@ -208,7 +208,7 @@ type scaletestOutputFlags struct { outputSpecs []string } -func (s *scaletestOutputFlags) attach(cmd *cobra.Command) { +func (s *scaletestOutputFlags) attach(cmd *clibase.Command) { cliflag.StringArrayVarP(cmd.Flags(), &s.outputSpecs, "output", "", "CODER_SCALETEST_OUTPUTS", []string{"text"}, `Output format specs in the format "[:]". Not specifying a path will default to stdout. Available formats: text, json.`) } @@ -308,15 +308,15 @@ func (r *userCleanupRunner) Run(ctx context.Context, _ string, _ io.Writer) erro return nil } -func scaletestCleanup() *cobra.Command { +func scaletestCleanup() *clibase.Command { cleanupStrategy := &scaletestStrategyFlags{cleanup: true} - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "cleanup", Short: "Cleanup any orphaned scaletest resources", Long: "Cleanup scaletest workspaces, then cleanup scaletest users. The strategy flags will apply to each stage of the cleanup process.", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() + Handler: func(inv *clibase.Invokation) error { + ctx := inv.Context() client, err := useClient(cmd) if err != nil { return err @@ -386,7 +386,7 @@ func scaletestCleanup() *cobra.Command { cmd.Println("Done deleting scaletest workspaces:") res := harness.Results() - res.PrintText(cmd.ErrOrStderr()) + res.PrintText(inv.Stderr) if res.TotalFail > 0 { return xerrors.Errorf("failed to delete scaletest workspaces") @@ -446,7 +446,7 @@ func scaletestCleanup() *cobra.Command { cmd.Println("Done deleting scaletest users:") res := harness.Results() - res.PrintText(cmd.ErrOrStderr()) + res.PrintText(inv.Stderr) if res.TotalFail > 0 { return xerrors.Errorf("failed to delete scaletest users") @@ -461,7 +461,7 @@ func scaletestCleanup() *cobra.Command { return cmd } -func scaletestCreateWorkspaces() *cobra.Command { +func scaletestCreateWorkspaces() *clibase.Command { var ( count int template string @@ -494,14 +494,14 @@ func scaletestCreateWorkspaces() *cobra.Command { output = &scaletestOutputFlags{} ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "create-workspaces", Short: "Creates many workspaces and waits for them to be ready", Long: `Creates many users, then creates a workspace for each user and waits for them finish building and fully come online. Optionally runs a command inside each workspace, and connects to the workspace over WireGuard. It is recommended that all rate limits are disabled on the server before running this scaletest. This test generates many login events which will be rate limited against the (most likely single) IP.`, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() + Handler: func(inv *clibase.Invokation) error { + ctx := inv.Context() client, err := useClient(cmd) if err != nil { return err @@ -613,15 +613,15 @@ It is recommended that all rate limits are disabled on the server before running return xerrors.Errorf("start dry run workspace creation: %w", err) } _, _ = fmt.Fprintln(cmd.OutOrStdout(), "Planning workspace...") - err = cliui.ProvisionerJob(cmd.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ + err = cliui.ProvisionerJob(inv.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ Fetch: func() (codersdk.ProvisionerJob, error) { - return client.TemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID) + return client.TemplateVersionDryRun(inv.Context(), templateVersion.ID, dryRun.ID) }, Cancel: func() error { - return client.CancelTemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID) + return client.CancelTemplateVersionDryRun(inv.Context(), templateVersion.ID, dryRun.ID) }, Logs: func() (<-chan codersdk.ProvisionerJobLog, io.Closer, error) { - return client.TemplateVersionDryRunLogsAfter(cmd.Context(), templateVersion.ID, dryRun.ID, 0) + return client.TemplateVersionDryRunLogsAfter(inv.Context(), templateVersion.ID, dryRun.ID, 0) }, // Don't show log output for the dry-run unless there's an error. Silent: true, @@ -728,7 +728,7 @@ It is recommended that all rate limits are disabled on the server before running } // TODO: live progress output - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Running load test...") + _, _ = fmt.Fprintln(inv.Stderr, "Running load test...") testCtx, testCancel := strategy.toContext(ctx) defer testCancel() err = th.Run(testCtx) @@ -744,7 +744,7 @@ It is recommended that all rate limits are disabled on the server before running } } - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "\nCleaning up...") + _, _ = fmt.Fprintln(inv.Stderr, "\nCleaning up...") cleanupCtx, cleanupCancel := cleanupStrategy.toContext(ctx) defer cleanupCancel() err = th.Cleanup(cleanupCtx) @@ -754,12 +754,12 @@ It is recommended that all rate limits are disabled on the server before running // Upload traces. if tracingEnabled { - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "\nUploading traces...") + _, _ = fmt.Fprintln(inv.Stderr, "\nUploading traces...") ctx, cancel := context.WithTimeout(ctx, 1*time.Minute) defer cancel() err := closeTracing(ctx) if err != nil { - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "\nError uploading traces: %+v\n", err) + _, _ = fmt.Fprintf(inv.Stderr, "\nError uploading traces: %+v\n", err) } } diff --git a/cli/schedule.go b/cli/schedule.go index 9a663d134c6a3..2dc4847aef084 100644 --- a/cli/schedule.go +++ b/cli/schedule.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/schedule" "github.com/coder/coder/coderd/util/ptr" @@ -53,12 +54,12 @@ When enabling scheduled stop, enter a duration in one of the following formats: ` ) -func schedules() *cobra.Command { - scheduleCmd := &cobra.Command{ +func schedules() *clibase.Command { + scheduleCmd := &clibase.Command{ Annotations: workspaceCommand, Use: "schedule { show | start | stop | override } ", Short: "Schedule automated start and stop times for workspaces", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { return cmd.Help() }, } @@ -73,13 +74,13 @@ func schedules() *cobra.Command { return scheduleCmd } -func scheduleShow() *cobra.Command { - showCmd := &cobra.Command{ +func scheduleShow() *clibase.Command { + showCmd := &clibase.Command{ Use: "show ", Short: "Show workspace schedule", Long: scheduleShowDescriptionLong, Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -96,8 +97,8 @@ func scheduleShow() *cobra.Command { return showCmd } -func scheduleStart() *cobra.Command { - cmd := &cobra.Command{ +func scheduleStart() *clibase.Command { + cmd := &clibase.Command{ Use: "start { [day-of-week] [location] | manual }", Example: formatExamples( example{ @@ -108,7 +109,7 @@ func scheduleStart() *cobra.Command { Short: "Edit workspace start schedule", Long: scheduleStartDescriptionLong, Args: cobra.RangeArgs(2, 4), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -129,7 +130,7 @@ func scheduleStart() *cobra.Command { schedStr = ptr.Ref(sched.String()) } - err = client.UpdateWorkspaceAutostart(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ + err = client.UpdateWorkspaceAutostart(inv.Context(), workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{ Schedule: schedStr, }) if err != nil { @@ -147,8 +148,8 @@ func scheduleStart() *cobra.Command { return cmd } -func scheduleStop() *cobra.Command { - return &cobra.Command{ +func scheduleStop() *clibase.Command { + return &clibase.Command{ Args: cobra.ExactArgs(2), Use: "stop { | manual }", Example: formatExamples( @@ -158,7 +159,7 @@ func scheduleStop() *cobra.Command { ), Short: "Edit workspace stop schedule", Long: scheduleStopDescriptionLong, - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -178,7 +179,7 @@ func scheduleStop() *cobra.Command { durMillis = ptr.Ref(dur.Milliseconds()) } - if err := client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ + if err := client.UpdateWorkspaceTTL(inv.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{ TTLMillis: durMillis, }); err != nil { return err @@ -193,8 +194,8 @@ func scheduleStop() *cobra.Command { } } -func scheduleOverride() *cobra.Command { - overrideCmd := &cobra.Command{ +func scheduleOverride() *clibase.Command { + overrideCmd := &clibase.Command{ Args: cobra.ExactArgs(2), Use: "override-stop ", Example: formatExamples( @@ -204,7 +205,7 @@ func scheduleOverride() *cobra.Command { ), Short: "Edit stop time of active workspace", Long: scheduleOverrideDescriptionLong, - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { overrideDuration, err := parseDuration(args[1]) if err != nil { return err @@ -234,7 +235,7 @@ func scheduleOverride() *cobra.Command { } newDeadline := time.Now().In(loc).Add(overrideDuration) - if err := client.PutExtendWorkspace(cmd.Context(), workspace.ID, codersdk.PutExtendWorkspaceRequest{ + if err := client.PutExtendWorkspace(inv.Context(), workspace.ID, codersdk.PutExtendWorkspaceRequest{ Deadline: newDeadline, }); err != nil { return err diff --git a/cli/server.go b/cli/server.go index d42e6c97a30cb..6068e750fddb3 100644 --- a/cli/server.go +++ b/cli/server.go @@ -41,7 +41,6 @@ import ( "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/afero" - "github.com/spf13/cobra" "go.opentelemetry.io/otel/trace" "golang.org/x/mod/semver" "golang.org/x/oauth2" @@ -155,14 +154,14 @@ func ReadGitAuthProvidersFromEnv(environ []string) ([]codersdk.GitAuthConfig, er // nolint:gocyclo func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *clibase.Command { - root := &cobra.Command{ + root := &clibase.Command{ Use: "server", Short: "Start a Coder server", DisableFlagParsing: true, - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { // Main command context for managing cancellation of running // services. - ctx, cancel := context.WithCancel(cmd.Context()) + ctx, cancel := context.WithCancel(inv.Context()) defer cancel() cfg := &codersdk.DeploymentValues{} @@ -192,8 +191,8 @@ func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Close flagSet := cliOpts.FlagSet() // These parents and children will be moved once we convert the // rest of the `cli` package to clibase. - flagSet.Usage = usageFn(cmd.ErrOrStderr(), &clibase.Cmd{ - Parent: &clibase.Cmd{ + flagSet.Usage = usageFn(inv.Stderr, &clibase.Command{ + Parent: &clibase.Command{ Use: "coder", }, Children: []*clibase.Cmd{ @@ -239,7 +238,7 @@ flags, and YAML configuration. The precedence is as follows: if err != nil { return xerrors.Errorf("generate yaml: %w", err) } - enc := yaml.NewEncoder(cmd.ErrOrStderr()) + enc := yaml.NewEncoder(inv.Stderr) err = enc.Encode(n) if err != nil { return xerrors.Errorf("encode yaml: %w", err) @@ -1166,10 +1165,10 @@ flags, and YAML configuration. The precedence is as follows: } var pgRawURL bool - postgresBuiltinURLCmd := &cobra.Command{ + postgresBuiltinURLCmd := &clibase.Command{ Use: "postgres-builtin-url", Short: "Output the connection URL for the built-in PostgreSQL deployment.", - RunE: func(cmd *cobra.Command, _ []string) error { + Handler: func(inv *clibase.Invokation) error { cfg := createConfig(cmd) url, err := embeddedPostgresURL(cfg) if err != nil { @@ -1183,14 +1182,14 @@ flags, and YAML configuration. The precedence is as follows: return nil }, } - postgresBuiltinServeCmd := &cobra.Command{ + postgresBuiltinServeCmd := &clibase.Command{ Use: "postgres-builtin-serve", Short: "Run the built-in PostgreSQL deployment.", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() + Handler: func(inv *clibase.Invokation) error { + ctx := inv.Context() cfg := createConfig(cmd) - logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr())) + logger := slog.Make(sloghuman.Sink(inv.Stderr)) if ok, _ := cmd.Flags().GetBool(varVerbose); ok { logger = logger.Leveled(slog.LevelDebug) } @@ -1218,7 +1217,7 @@ flags, and YAML configuration. The precedence is as follows: postgresBuiltinServeCmd.Flags().BoolVar(&pgRawURL, "raw-url", false, "Output the raw connection URL instead of a psql command.") createAdminUserCommand := newCreateAdminUserCommand() - root.SetHelpFunc(func(cmd *cobra.Command, args []string) { + root.SetHelpFunc(func(inv *clibase.Invokation) { // Help is handled by clibase in command body. }) root.AddCommand(postgresBuiltinURLCmd, postgresBuiltinServeCmd, createAdminUserCommand) @@ -1361,7 +1360,7 @@ func newProvisionerDaemon( } // nolint: revive -func printLogo(cmd *cobra.Command) { +func printLogo(cmd *clibase.Command) { // Only print the logo in TTYs. if !isTTYOut(cmd) { return @@ -1766,7 +1765,7 @@ func isLocalhost(host string) bool { return host == "localhost" || host == "127.0.0.1" || host == "::1" } -func buildLogger(cmd *cobra.Command, cfg *codersdk.DeploymentValues) (slog.Logger, func(), error) { +func buildLogger(cmd *clibase.Command, cfg *codersdk.DeploymentValues) (slog.Logger, func(), error) { var ( sinks = []slog.Sink{} closers = []func() error{} @@ -1780,7 +1779,7 @@ func buildLogger(cmd *cobra.Command, cfg *codersdk.DeploymentValues) (slog.Logge sinks = append(sinks, sinkFn(cmd.OutOrStdout())) case "/dev/stderr": - sinks = append(sinks, sinkFn(cmd.ErrOrStderr())) + sinks = append(sinks, sinkFn(inv.Stderr)) default: fi, err := os.OpenFile(loc, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644) diff --git a/cli/server_createadminuser.go b/cli/server_createadminuser.go index d21a7f07cce1e..9441d29d9e9a6 100644 --- a/cli/server_createadminuser.go +++ b/cli/server_createadminuser.go @@ -9,11 +9,11 @@ import ( "sort" "github.com/google/uuid" - "github.com/spf13/cobra" "golang.org/x/xerrors" "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/gitsshkey" @@ -23,7 +23,7 @@ import ( "github.com/coder/coder/codersdk" ) -func newCreateAdminUserCommand() *cobra.Command { +func newCreateAdminUserCommand() *clibase.Command { var ( newUserDBURL string newUserSSHKeygenAlgorithm string @@ -31,11 +31,11 @@ func newCreateAdminUserCommand() *cobra.Command { newUserEmail string newUserPassword string ) - createAdminUserCommand := &cobra.Command{ + createAdminUserCommand := &clibase.Command{ Use: "create-admin-user", Short: "Create a new admin user with the given username, email and password and adds it to every organization.", - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() + Handler: func(inv *clibase.Invokation) error { + ctx := inv.Context() sshKeygenAlgorithm, err := gitsshkey.ParseAlgorithm(newUserSSHKeygenAlgorithm) if err != nil { @@ -59,7 +59,7 @@ func newCreateAdminUserCommand() *cobra.Command { } cfg := createConfig(cmd) - logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr())) + logger := slog.Make(sloghuman.Sink(inv.Stderr)) if ok, _ := cmd.Flags().GetBool(varVerbose); ok { logger = logger.Leveled(slog.LevelDebug) } @@ -191,7 +191,7 @@ func newCreateAdminUserCommand() *cobra.Command { return orgs[i].Name < orgs[j].Name }) - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Creating user...") + _, _ = fmt.Fprintln(inv.Stderr, "Creating user...") newUser, err = tx.InsertUser(ctx, database.InsertUserParams{ ID: uuid.New(), Email: newUserEmail, @@ -206,7 +206,7 @@ func newCreateAdminUserCommand() *cobra.Command { return xerrors.Errorf("insert user: %w", err) } - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Generating user SSH key...") + _, _ = fmt.Fprintln(inv.Stderr, "Generating user SSH key...") privateKey, publicKey, err := gitsshkey.Generate(sshKeygenAlgorithm) if err != nil { return xerrors.Errorf("generate user gitsshkey: %w", err) @@ -223,7 +223,7 @@ func newCreateAdminUserCommand() *cobra.Command { } for _, org := range orgs { - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Adding user to organization %q (%s) as admin...\n", org.Name, org.ID.String()) + _, _ = fmt.Fprintf(inv.Stderr, "Adding user to organization %q (%s) as admin...\n", org.Name, org.ID.String()) _, err := tx.InsertOrganizationMember(ctx, database.InsertOrganizationMemberParams{ OrganizationID: org.ID, UserID: newUser.ID, @@ -242,12 +242,12 @@ func newCreateAdminUserCommand() *cobra.Command { return err } - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "") - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "User created successfully.") - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "ID: "+newUser.ID.String()) - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Username: "+newUser.Username) - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Email: "+newUser.Email) - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Password: ********") + _, _ = fmt.Fprintln(inv.Stderr, "") + _, _ = fmt.Fprintln(inv.Stderr, "User created successfully.") + _, _ = fmt.Fprintln(inv.Stderr, "ID: "+newUser.ID.String()) + _, _ = fmt.Fprintln(inv.Stderr, "Username: "+newUser.Username) + _, _ = fmt.Fprintln(inv.Stderr, "Email: "+newUser.Email) + _, _ = fmt.Fprintln(inv.Stderr, "Password: ********") return nil }, diff --git a/cli/server_slim.go b/cli/server_slim.go index b54cf8c88d52b..320a6d072e3b3 100644 --- a/cli/server_slim.go +++ b/cli/server_slim.go @@ -8,39 +8,38 @@ import ( "io" "os" - "github.com/spf13/cobra" - + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd" ) -func Server(_ func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *cobra.Command { - root := &cobra.Command{ +func Server(_ func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *clibase.Command { + root := &clibase.Command{ Use: "server", Short: "Start a Coder server", Hidden: true, - RunE: func(cmd *cobra.Command, args []string) error { - serverUnsupported(cmd.ErrOrStderr()) + Handler: func(inv *clibase.Invokation) error { + serverUnsupported(inv.Stderr) return nil }, } var pgRawURL bool - postgresBuiltinURLCmd := &cobra.Command{ + postgresBuiltinURLCmd := &clibase.Command{ Use: "postgres-builtin-url", Short: "Output the connection URL for the built-in PostgreSQL deployment.", Hidden: true, - RunE: func(cmd *cobra.Command, _ []string) error { - serverUnsupported(cmd.ErrOrStderr()) + Handler: func(inv *clibase.Invokation) error { + serverUnsupported(inv.Stderr) return nil }, } - postgresBuiltinServeCmd := &cobra.Command{ + postgresBuiltinServeCmd := &clibase.Command{ Use: "postgres-builtin-serve", Short: "Run the built-in PostgreSQL deployment.", Hidden: true, - RunE: func(cmd *cobra.Command, args []string) error { - serverUnsupported(cmd.ErrOrStderr()) + Handler: func(inv *clibase.Invokation) error { + serverUnsupported(inv.Stderr) return nil }, } @@ -52,12 +51,12 @@ func Server(_ func(context.Context, *coderd.Options) (*coderd.API, io.Closer, er newUserEmail string newUserPassword string ) - createAdminUserCommand := &cobra.Command{ + createAdminUserCommand := &clibase.Command{ Use: "create-admin-user", Short: "Create a new admin user with the given username, email and password and adds it to every organization.", Hidden: true, - RunE: func(cmd *cobra.Command, args []string) error { - serverUnsupported(cmd.ErrOrStderr()) + Handler: func(inv *clibase.Invokation) error { + serverUnsupported(inv.Stderr) return nil }, } diff --git a/cli/speedtest.go b/cli/speedtest.go index a9d9757fe9f6d..f5aa493c4e311 100644 --- a/cli/speedtest.go +++ b/cli/speedtest.go @@ -12,24 +12,25 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func speedtest() *cobra.Command { +func speedtest() *clibase.Command { var ( direct bool duration time.Duration direction string ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "speedtest ", Args: cobra.ExactArgs(1), Short: "Run upload and download tests from your machine to a workspace", - RunE: func(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithCancel(cmd.Context()) + Handler: func(inv *clibase.Invokation) error { + ctx, cancel := context.WithCancel(inv.Context()) defer cancel() client, err := useClient(cmd) @@ -42,7 +43,7 @@ func speedtest() *cobra.Command { return err } - err = cliui.Agent(ctx, cmd.ErrOrStderr(), cliui.AgentOptions{ + err = cliui.Agent(ctx, inv.Stderr, cliui.AgentOptions{ WorkspaceName: workspace.Name, Fetch: func(ctx context.Context) (codersdk.WorkspaceAgent, error) { return client.WorkspaceAgent(ctx, workspaceAgent.ID) @@ -53,7 +54,7 @@ func speedtest() *cobra.Command { } logger, ok := LoggerFromContext(ctx) if !ok { - logger = slog.Make(sloghuman.Sink(cmd.ErrOrStderr())) + logger = slog.Make(sloghuman.Sink(inv.Stderr)) } if cliflag.IsSetBool(cmd, varVerbose) { logger = logger.Leveled(slog.LevelDebug) diff --git a/cli/ssh.go b/cli/ssh.go index 0d7868ed1b707..38edb6b1d0746 100644 --- a/cli/ssh.go +++ b/cli/ssh.go @@ -25,6 +25,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/agent" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/autobuild/notify" @@ -38,7 +39,7 @@ var ( autostopNotifyCountdown = []time.Duration{30 * time.Minute} ) -func ssh() *cobra.Command { +func ssh() *clibase.Command { var ( stdio bool shuffle bool @@ -48,13 +49,13 @@ func ssh() *cobra.Command { wsPollInterval time.Duration noWait bool ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "ssh ", Short: "Start a shell into a workspace", Args: cobra.ArbitraryArgs, - RunE: func(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithCancel(cmd.Context()) + Handler: func(inv *clibase.Invokation) error { + ctx, cancel := context.WithCancel(inv.Context()) defer cancel() client, err := useClient(cmd) @@ -81,12 +82,12 @@ func ssh() *cobra.Command { updateWorkspaceBanner, outdated := verifyWorkspaceOutdated(client, workspace) if outdated && isTTYErr(cmd) { - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), updateWorkspaceBanner) + _, _ = fmt.Fprintln(inv.Stderr, updateWorkspaceBanner) } // OpenSSH passes stderr directly to the calling TTY. // This is required in "stdio" mode so a connecting indicator can be displayed. - err = cliui.Agent(ctx, cmd.ErrOrStderr(), cliui.AgentOptions{ + err = cliui.Agent(ctx, inv.Stderr, cliui.AgentOptions{ WorkspaceName: workspace.Name, Fetch: func(ctx context.Context) (codersdk.WorkspaceAgent, error) { return client.WorkspaceAgent(ctx, workspaceAgent.ID) @@ -168,7 +169,7 @@ func ssh() *cobra.Command { if err != nil { return xerrors.Errorf("upload GPG public keys and ownertrust to workspace: %w", err) } - closer, err := forwardGPGAgent(ctx, cmd.ErrOrStderr(), sshClient) + closer, err := forwardGPGAgent(ctx, inv.Stderr, sshClient) if err != nil { return xerrors.Errorf("forward GPG socket: %w", err) } @@ -210,7 +211,7 @@ func ssh() *cobra.Command { sshSession.Stdin = cmd.InOrStdin() sshSession.Stdout = cmd.OutOrStdout() - sshSession.Stderr = cmd.ErrOrStderr() + sshSession.Stderr = inv.Stderr err = sshSession.Shell() if err != nil { @@ -257,7 +258,7 @@ func ssh() *cobra.Command { // getWorkspaceAgent returns the workspace and agent selected using either the // `[.]` syntax via `in` or picks a random workspace and agent // if `shuffle` is true. -func getWorkspaceAndAgent(ctx context.Context, cmd *cobra.Command, client *codersdk.Client, userID string, in string, shuffle bool) (codersdk.Workspace, codersdk.WorkspaceAgent, error) { //nolint:revive +func getWorkspaceAndAgent(ctx context.Context, cmd *clibase.Command, client *codersdk.Client, userID string, in string, shuffle bool) (codersdk.Workspace, codersdk.WorkspaceAgent, error) { //nolint:revive var ( workspace codersdk.Workspace workspaceParts = strings.Split(in, ".") @@ -289,7 +290,7 @@ func getWorkspaceAndAgent(ctx context.Context, cmd *cobra.Command, client *coder return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.New("workspace must be in start transition to ssh") } if workspace.LatestBuild.Job.CompletedAt == nil { - err := cliui.WorkspaceBuild(ctx, cmd.ErrOrStderr(), client, workspace.LatestBuild.ID) + err := cliui.WorkspaceBuild(ctx, inv.Stderr, client, workspace.LatestBuild.ID) if err != nil { return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err } diff --git a/cli/start.go b/cli/start.go index da44c359914c7..3f9f6e607b601 100644 --- a/cli/start.go +++ b/cli/start.go @@ -6,17 +6,18 @@ import ( "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func start() *cobra.Command { - cmd := &cobra.Command{ +func start() *clibase.Command { + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "start ", Short: "Start a workspace", Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -25,14 +26,14 @@ func start() *cobra.Command { if err != nil { return err } - build, err := client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + build, err := client.CreateWorkspaceBuild(inv.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ Transition: codersdk.WorkspaceTransitionStart, }) if err != nil { return err } - err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, build.ID) + err = cliui.WorkspaceBuild(inv.Context(), cmd.OutOrStdout(), client, build.ID) if err != nil { return err } diff --git a/cli/state.go b/cli/state.go index bf4cbd7a064c5..fb93fe29020b4 100644 --- a/cli/state.go +++ b/cli/state.go @@ -8,15 +8,16 @@ import ( "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func state() *cobra.Command { - cmd := &cobra.Command{ +func state() *clibase.Command { + cmd := &clibase.Command{ Use: "state", Short: "Manually manage Terraform state to fix broken workspaces", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { return cmd.Help() }, } @@ -24,13 +25,13 @@ func state() *cobra.Command { return cmd } -func statePull() *cobra.Command { +func statePull() *clibase.Command { var buildNumber int - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "pull [file]", Short: "Pull a Terraform state file from a workspace.", Args: cobra.MinimumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -43,13 +44,13 @@ func statePull() *cobra.Command { } build = workspace.LatestBuild } else { - build, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber(cmd.Context(), codersdk.Me, args[0], strconv.Itoa(buildNumber)) + build, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber(inv.Context(), codersdk.Me, args[0], strconv.Itoa(buildNumber)) if err != nil { return err } } - state, err := client.WorkspaceBuildState(cmd.Context(), build.ID) + state, err := client.WorkspaceBuildState(inv.Context(), build.ID) if err != nil { return err } @@ -66,13 +67,13 @@ func statePull() *cobra.Command { return cmd } -func statePush() *cobra.Command { +func statePush() *clibase.Command { var buildNumber int - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "push ", Args: cobra.ExactArgs(2), Short: "Push a Terraform state file to a workspace.", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -85,7 +86,7 @@ func statePush() *cobra.Command { if buildNumber == 0 { build = workspace.LatestBuild } else { - build, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber(cmd.Context(), codersdk.Me, args[0], strconv.Itoa(buildNumber)) + build, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber(inv.Context(), codersdk.Me, args[0], strconv.Itoa(buildNumber)) if err != nil { return err } @@ -101,7 +102,7 @@ func statePush() *cobra.Command { return err } - build, err = client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + build, err = client.CreateWorkspaceBuild(inv.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ TemplateVersionID: build.TemplateVersionID, Transition: build.Transition, ProvisionerState: state, @@ -109,7 +110,7 @@ func statePush() *cobra.Command { if err != nil { return err } - return cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStderr(), client, build.ID) + return cliui.WorkspaceBuild(inv.Context(), cmd.OutOrStderr(), client, build.ID) }, } cmd.Flags().IntVarP(&buildNumber, "build", "b", 0, "Specify a workspace build to target by name.") diff --git a/cli/stop.go b/cli/stop.go index 91afd21bf6dde..2179794532330 100644 --- a/cli/stop.go +++ b/cli/stop.go @@ -6,17 +6,18 @@ import ( "github.com/spf13/cobra" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func stop() *cobra.Command { - cmd := &cobra.Command{ +func stop() *clibase.Command { + cmd := &clibase.Command{ Annotations: workspaceCommand, Use: "stop ", Short: "Stop a workspace", Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { _, err := cliui.Prompt(cmd, cliui.PromptOptions{ Text: "Confirm stop workspace?", IsConfirm: true, @@ -33,14 +34,14 @@ func stop() *cobra.Command { if err != nil { return err } - build, err := client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + build, err := client.CreateWorkspaceBuild(inv.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ Transition: codersdk.WorkspaceTransitionStop, }) if err != nil { return err } - err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, build.ID) + err = cliui.WorkspaceBuild(inv.Context(), cmd.OutOrStdout(), client, build.ID) if err != nil { return err } diff --git a/cli/templatecreate.go b/cli/templatecreate.go index b38f0190f8ceb..52b5b8132788a 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -13,6 +13,7 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/util/ptr" @@ -20,7 +21,7 @@ import ( "github.com/coder/coder/provisionerd" ) -func templateCreate() *cobra.Command { +func templateCreate() *clibase.Command { var ( provisioner string provisionerTags []string @@ -31,11 +32,11 @@ func templateCreate() *cobra.Command { uploadFlags templateUploadFlags ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "create [name]", Short: "Create a template from the current directory or as specified by flag", Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { client, err := useClient(cmd) if err != nil { return err @@ -55,7 +56,7 @@ func templateCreate() *cobra.Command { return xerrors.Errorf("Template name must be less than 32 characters") } - _, err = client.TemplateByName(cmd.Context(), organization.ID, templateName) + _, err = client.TemplateByName(inv.Context(), organization.ID, templateName) if err == nil { return xerrors.Errorf("A template already exists named %q!", templateName) } @@ -101,7 +102,7 @@ func templateCreate() *cobra.Command { DefaultTTLMillis: ptr.Ref(defaultTTL.Milliseconds()), } - _, err = client.CreateTemplate(cmd.Context(), organization.ID, createReq) + _, err = client.CreateTemplate(inv.Context(), organization.ID, createReq) if err != nil { return err } @@ -152,7 +153,7 @@ type createValidTemplateVersionArgs struct { ProvisionerTags map[string]string } -func createValidTemplateVersion(cmd *cobra.Command, args createValidTemplateVersionArgs, parameters ...codersdk.CreateParameterRequest) (*codersdk.TemplateVersion, []codersdk.CreateParameterRequest, error) { +func createValidTemplateVersion(cmd *clibase.Command, args createValidTemplateVersionArgs, parameters ...codersdk.CreateParameterRequest) (*codersdk.TemplateVersion, []codersdk.CreateParameterRequest, error) { client := args.Client variableValues, err := loadVariableValuesFromFile(args.VariablesFile) @@ -178,21 +179,21 @@ func createValidTemplateVersion(cmd *cobra.Command, args createValidTemplateVers if args.Template != nil { req.TemplateID = args.Template.ID } - version, err := client.CreateTemplateVersion(cmd.Context(), args.Organization.ID, req) + version, err := client.CreateTemplateVersion(inv.Context(), args.Organization.ID, req) if err != nil { return nil, nil, err } - err = cliui.ProvisionerJob(cmd.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ + err = cliui.ProvisionerJob(inv.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{ Fetch: func() (codersdk.ProvisionerJob, error) { - version, err := client.TemplateVersion(cmd.Context(), version.ID) + version, err := client.TemplateVersion(inv.Context(), version.ID) return version.Job, err }, Cancel: func() error { - return client.CancelTemplateVersion(cmd.Context(), version.ID) + return client.CancelTemplateVersion(inv.Context(), version.ID) }, Logs: func() (<-chan codersdk.ProvisionerJobLog, io.Closer, error) { - return client.TemplateVersionLogsAfter(cmd.Context(), version.ID, 0) + return client.TemplateVersionLogsAfter(inv.Context(), version.ID, 0) }, }) if err != nil { @@ -200,15 +201,15 @@ func createValidTemplateVersion(cmd *cobra.Command, args createValidTemplateVers return nil, nil, err } } - version, err = client.TemplateVersion(cmd.Context(), version.ID) + version, err = client.TemplateVersion(inv.Context(), version.ID) if err != nil { return nil, nil, err } - parameterSchemas, err := client.TemplateVersionSchema(cmd.Context(), version.ID) + parameterSchemas, err := client.TemplateVersionSchema(inv.Context(), version.ID) if err != nil { return nil, nil, err } - parameterValues, err := client.TemplateVersionParameters(cmd.Context(), version.ID) + parameterValues, err := client.TemplateVersionParameters(inv.Context(), version.ID) if err != nil { return nil, nil, err } @@ -218,13 +219,13 @@ func createValidTemplateVersion(cmd *cobra.Command, args createValidTemplateVers // version instead of prompting if we are updating template versions. lastParameterValues := make(map[string]codersdk.Parameter) if args.ReuseParameters && args.Template != nil { - activeVersion, err := client.TemplateVersion(cmd.Context(), args.Template.ActiveVersionID) + activeVersion, err := client.TemplateVersion(inv.Context(), args.Template.ActiveVersionID) if err != nil { return nil, nil, xerrors.Errorf("Fetch current active template version: %w", err) } // We don't want to compute the params, we only want to copy from this scope - values, err := client.Parameters(cmd.Context(), codersdk.ParameterImportJob, activeVersion.Job.ID) + values, err := client.Parameters(inv.Context(), codersdk.ParameterImportJob, activeVersion.Job.ID) if err != nil { return nil, nil, xerrors.Errorf("Fetch previous version parameters: %w", err) } @@ -303,7 +304,7 @@ func createValidTemplateVersion(cmd *cobra.Command, args createValidTemplateVers return nil, nil, xerrors.New(version.Job.Error) } - resources, err := client.TemplateVersionResources(cmd.Context(), version.ID) + resources, err := client.TemplateVersionResources(inv.Context(), version.ID) if err != nil { return nil, nil, err } diff --git a/cli/templatedelete.go b/cli/templatedelete.go index 4cffe60ac9711..b94589a05caa7 100644 --- a/cli/templatedelete.go +++ b/cli/templatedelete.go @@ -5,20 +5,20 @@ import ( "strings" "time" - "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func templateDelete() *cobra.Command { - cmd := &cobra.Command{ +func templateDelete() *clibase.Command { + cmd := &clibase.Command{ Use: "delete [name...]", Short: "Delete templates", - RunE: func(cmd *cobra.Command, args []string) error { + Handler: func(inv *clibase.Invokation) error { var ( - ctx = cmd.Context() + ctx = inv.Context() templateNames = []string{} templates = []codersdk.Template{} ) diff --git a/cli/templateedit.go b/cli/templateedit.go index bddf5780a8dab..b5a76098177a1 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -8,11 +8,12 @@ import ( "github.com/spf13/cobra" "golang.org/x/xerrors" + "github.com/coder/coder/cli/clibase" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) -func templateEdit() *cobra.Command { +func templateEdit() *clibase.Command { var ( name string displayName string @@ -23,18 +24,18 @@ func templateEdit() *cobra.Command { allowUserCancelWorkspaceJobs bool ) - cmd := &cobra.Command{ + cmd := &clibase.Command{ Use: "edit