Skip to content

Commit a678576

Browse files
committed
102 problems left...
1 parent d028e1e commit a678576

File tree

7 files changed

+162
-155
lines changed

7 files changed

+162
-155
lines changed

cli/portforward.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616

1717
"github.com/coder/coder/agent"
1818
"github.com/coder/coder/cli/clibase"
19-
"github.com/coder/coder/cli/cliflag"
2019
"github.com/coder/coder/cli/cliui"
2120
"github.com/coder/coder/codersdk"
2221
)
@@ -69,7 +68,7 @@ func (r *RootCmd) portForward() *clibase.Cmd {
6968
return xerrors.New("no port-forwards requested")
7069
}
7170

72-
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, cmd, client, codersdk.Me, inv.Args[0], false)
71+
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, codersdk.Me, inv.Args[0], false)
7372
if err != nil {
7473
return err
7574
}
@@ -115,7 +114,7 @@ func (r *RootCmd) portForward() *clibase.Cmd {
115114
defer closeAllListeners()
116115

117116
for i, spec := range specs {
118-
l, err := listenAndPortForward(ctx, cmd, conn, wg, spec)
117+
l, err := listenAndPortForward(ctx, inv, conn, wg, spec)
119118
if err != nil {
120119
return err
121120
}
@@ -150,12 +149,26 @@ func (r *RootCmd) portForward() *clibase.Cmd {
150149
},
151150
}
152151

153-
cliflag.StringArrayVarP(cmd.Flags(), &tcpForwards, "tcp", "p", "CODER_PORT_FORWARD_TCP", nil, "Forward TCP port(s) from the workspace to the local machine")
154-
cliflag.StringArrayVarP(cmd.Flags(), &udpForwards, "udp", "", "CODER_PORT_FORWARD_UDP", nil, "Forward UDP port(s) from the workspace to the local machine. The UDP connection has TCP-like semantics to support stateful UDP protocols")
152+
cmd.Options = []clibase.Option{
153+
{
154+
Flag: "tcp",
155+
FlagShorthand: "p",
156+
Env: "CODER_PORT_FORWARD_TCP",
157+
Description: "Forward TCP port(s) from the workspace to the local machine",
158+
Value: clibase.StringsOf(&tcpForwards),
159+
},
160+
{
161+
Flag: "udp",
162+
Env: "CODER_PORT_FORWARD_UDP",
163+
Description: "Forward UDP port(s) from the workspace to the local machine. The UDP connection has TCP-like semantics to support stateful UDP protocols",
164+
Value: clibase.StringsOf(&udpForwards),
165+
},
166+
}
167+
155168
return cmd
156169
}
157170

158-
func listenAndPortForward(ctx context.Context, cmd *clibase.Cmd, conn *codersdk.WorkspaceAgentConn, wg *sync.WaitGroup, spec portForwardSpec) (net.Listener, error) {
171+
func listenAndPortForward(ctx context.Context, inv *clibase.Invokation, conn *codersdk.WorkspaceAgentConn, wg *sync.WaitGroup, spec portForwardSpec) (net.Listener, error) {
159172
_, _ = fmt.Fprintf(inv.Stderr, "Forwarding '%v://%v' locally to '%v://%v' in the workspace\n", spec.listenNetwork, spec.listenAddress, spec.dialNetwork, spec.dialAddress)
160173

161174
var (

cli/resetpassword.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"golang.org/x/xerrors"
88

99
"github.com/coder/coder/cli/clibase"
10-
"github.com/coder/coder/cli/cliflag"
1110
"github.com/coder/coder/cli/cliui"
1211
"github.com/coder/coder/coderd/database"
1312
"github.com/coder/coder/coderd/database/migrations"
@@ -87,7 +86,14 @@ func (r *RootCmd) resetPassword() *clibase.Cmd {
8786
},
8887
}
8988

90-
cliflag.StringVarP(root.Flags(), &postgresURL, "postgres-url", "", "CODER_PG_CONNECTION_URL", "", "URL of a PostgreSQL database to connect to")
89+
root.Options = clibase.OptionSet{
90+
{
91+
Name: "postgres-url",
92+
Description: "URL of a PostgreSQL database to connect to",
93+
Env: "CODER_PG_CONNECTION_URL",
94+
Value: clibase.StringOf(&postgresURL),
95+
},
96+
}
9197

9298
return root
9399
}

cli/root.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ func Core() []*clibase.Cmd {
7474
}
7575
}
7676

77-
func AGPL() []*clibase.Cmd {
78-
all := append(Core(), Server(func(_ context.Context, o *coderd.Options) (*coderd.API, io.Closer, error) {
77+
func AGPL(r *RootCmd) []*clibase.Cmd {
78+
all := append(Core(), r.Server(func(_ context.Context, o *coderd.Options) (*coderd.API, io.Closer, error) {
7979
api := coderd.New(o)
8080
return api, api, nil
8181
}))

cli/root_test.go

Lines changed: 4 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616

1717
"github.com/stretchr/testify/assert"
1818
"github.com/stretchr/testify/require"
19-
"golang.org/x/xerrors"
2019

2120
"github.com/coder/coder/buildinfo"
2221
"github.com/coder/coder/cli"
@@ -78,9 +77,10 @@ func TestCommandHelp(t *testing.T) {
7877
},
7978
}
8079

81-
root := cli.Root(cli.AGPL())
80+
rootCmd := new(cli.RootCmd)
81+
root := rootCmd.Command(cli.AGPL(rootCmd))
8282
ExtractCommandPathsLoop:
83-
for _, cp := range extractVisibleCommandPaths(nil, root.Commands()) {
83+
for _, cp := range extractVisibleCommandPaths(nil, root.Children) {
8484
name := fmt.Sprintf("coder %s --help", strings.Join(cp, " "))
8585
cmd := append(cp, "--help")
8686
for _, tt := range tests {
@@ -184,7 +184,7 @@ func extractVisibleCommandPaths(cmdPath []string, cmds []*clibase.Cmd) [][]strin
184184
}
185185
cmdPath := append(cmdPath, c.Name())
186186
cmdPaths = append(cmdPaths, cmdPath)
187-
cmdPaths = append(cmdPaths, extractVisibleCommandPaths(cmdPath, c.Commands())...)
187+
cmdPaths = append(cmdPaths, extractVisibleCommandPaths(cmdPath, c.Children)...)
188188
}
189189
return cmdPaths
190190
}
@@ -241,106 +241,6 @@ func prepareTestData(t *testing.T) (*codersdk.Client, map[string]string) {
241241

242242
func TestRoot(t *testing.T) {
243243
t.Parallel()
244-
t.Run("FormatCobraError", func(t *testing.T) {
245-
t.Parallel()
246-
247-
t.Run("OK", func(t *testing.T) {
248-
t.Parallel()
249-
250-
inv, _ := clitest.New(t, "delete")
251-
252-
cmd, err := cmd.RunC()
253-
errStr := cli.FormatCobraError(err, cmd)
254-
require.Contains(t, errStr, "Run 'coder delete --help' for usage.")
255-
})
256-
257-
t.Run("Verbose", func(t *testing.T) {
258-
t.Parallel()
259-
260-
// Test that the verbose error is masked without verbose flag.
261-
t.Run("NoVerboseAPIError", func(t *testing.T) {
262-
t.Parallel()
263-
264-
inv, _ := clitest.New(t)
265-
266-
cmd.RunE = func(inv *clibase.Invokation) error {
267-
var err error = &codersdk.Error{
268-
Response: codersdk.Response{
269-
Message: "This is a message.",
270-
},
271-
Helper: "Try this instead.",
272-
}
273-
274-
err = xerrors.Errorf("wrap me: %w", err)
275-
276-
return err
277-
}
278-
279-
cmd, err := cmd.RunC()
280-
errStr := cli.FormatCobraError(err, cmd)
281-
require.Contains(t, errStr, "This is a message. Try this instead.")
282-
require.NotContains(t, errStr, err.Error())
283-
})
284-
285-
// Assert that a regular error is not masked when verbose is not
286-
// specified.
287-
t.Run("NoVerboseRegularError", func(t *testing.T) {
288-
t.Parallel()
289-
290-
inv, _ := clitest.New(t)
291-
292-
cmd.RunE = func(inv *clibase.Invokation) error {
293-
return xerrors.Errorf("this is a non-codersdk error: %w", xerrors.Errorf("a wrapped error"))
294-
}
295-
296-
cmd, err := cmd.RunC()
297-
errStr := cli.FormatCobraError(err, cmd)
298-
require.Contains(t, errStr, err.Error())
299-
})
300-
301-
// Test that both the friendly error and the verbose error are
302-
// displayed when verbose is passed.
303-
t.Run("APIError", func(t *testing.T) {
304-
t.Parallel()
305-
306-
inv, _ := clitest.New(t, "--verbose")
307-
308-
cmd.RunE = func(inv *clibase.Invokation) error {
309-
var err error = &codersdk.Error{
310-
Response: codersdk.Response{
311-
Message: "This is a message.",
312-
},
313-
Helper: "Try this instead.",
314-
}
315-
316-
err = xerrors.Errorf("wrap me: %w", err)
317-
318-
return err
319-
}
320-
321-
cmd, err := cmd.RunC()
322-
errStr := cli.FormatCobraError(err, cmd)
323-
require.Contains(t, errStr, "This is a message. Try this instead.")
324-
require.Contains(t, errStr, err.Error())
325-
})
326-
327-
// Assert that a regular error is not masked when verbose specified.
328-
t.Run("RegularError", func(t *testing.T) {
329-
t.Parallel()
330-
331-
inv, _ := clitest.New(t, "--verbose")
332-
333-
cmd.RunE = func(inv *clibase.Invokation) error {
334-
return xerrors.Errorf("this is a non-codersdk error: %w", xerrors.Errorf("a wrapped error"))
335-
}
336-
337-
cmd, err := cmd.RunC()
338-
errStr := cli.FormatCobraError(err, cmd)
339-
require.Contains(t, errStr, err.Error())
340-
})
341-
})
342-
})
343-
344244
t.Run("Version", func(t *testing.T) {
345245
t.Parallel()
346246

cli/ssh.go

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,13 @@ import (
1818
"github.com/gofrs/flock"
1919
"github.com/google/uuid"
2020
"github.com/mattn/go-isatty"
21-
"github.com/spf13/cobra"
2221
gossh "golang.org/x/crypto/ssh"
2322
gosshagent "golang.org/x/crypto/ssh/agent"
2423
"golang.org/x/term"
2524
"golang.org/x/xerrors"
2625

2726
"github.com/coder/coder/agent"
2827
"github.com/coder/coder/cli/clibase"
29-
"github.com/coder/coder/cli/cliflag"
3028
"github.com/coder/coder/cli/cliui"
3129
"github.com/coder/coder/coderd/autobuild/notify"
3230
"github.com/coder/coder/coderd/util/ptr"
@@ -61,19 +59,15 @@ func (r *RootCmd) ssh() *clibase.Cmd {
6159
ctx, cancel := context.WithCancel(inv.Context())
6260
defer cancel()
6361

64-
if shuffle {
65-
err := cobra.ExactArgs(0)(cmd, args)
66-
if err != nil {
67-
return err
68-
}
69-
} else {
70-
err := cobra.MinimumNArgs(1)(cmd, args)
71-
if err != nil {
72-
return err
73-
}
62+
if shuffle && len(inv.Args) > 0 {
63+
return xerrors.New("cannot specify workspace name when using --shuffle")
64+
}
65+
66+
if len(inv.Args) < 1 {
67+
return xerrors.New("missing workspace name")
7468
}
7569

76-
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, cmd, client, codersdk.Me, args[0], shuffle)
70+
workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, codersdk.Me, inv.Args[0], shuffle)
7771
if err != nil {
7872
return err
7973
}
@@ -242,14 +236,53 @@ func (r *RootCmd) ssh() *clibase.Cmd {
242236
return nil
243237
},
244238
}
245-
cliflag.BoolVarP(cmd.Flags(), &stdio, "stdio", "", "CODER_SSH_STDIO", false, "Specifies whether to emit SSH output over stdin/stdout.")
246-
cliflag.BoolVarP(cmd.Flags(), &shuffle, "shuffle", "", "CODER_SSH_SHUFFLE", false, "Specifies whether to choose a random workspace")
247-
_ = inv.ParsedFlags().MarkHidden("shuffle")
248-
cliflag.BoolVarP(cmd.Flags(), &forwardAgent, "forward-agent", "A", "CODER_SSH_FORWARD_AGENT", false, "Specifies whether to forward the SSH agent specified in $SSH_AUTH_SOCK")
249-
cliflag.BoolVarP(cmd.Flags(), &forwardGPG, "forward-gpg", "G", "CODER_SSH_FORWARD_GPG", false, "Specifies whether to forward the GPG agent. Unsupported on Windows workspaces, but supports all clients. Requires gnupg (gpg, gpgconf) on both the client and workspace. The GPG agent must already be running locally and will not be started for you. If a GPG agent is already running in the workspace, it will be attempted to be killed.")
250-
cliflag.StringVarP(cmd.Flags(), &identityAgent, "identity-agent", "", "CODER_SSH_IDENTITY_AGENT", "", "Specifies which identity agent to use (overrides $SSH_AUTH_SOCK), forward agent must also be enabled")
251-
cliflag.DurationVarP(cmd.Flags(), &wsPollInterval, "workspace-poll-interval", "", "CODER_WORKSPACE_POLL_INTERVAL", workspacePollInterval, "Specifies how often to poll for workspace automated shutdown.")
252-
cliflag.BoolVarP(cmd.Flags(), &noWait, "no-wait", "", "CODER_SSH_NO_WAIT", false, "Specifies whether to wait for a workspace to become ready before logging in (only applicable when the login before ready option has not been enabled). Note that the workspace agent may still be in the process of executing the startup script and the workspace may be in an incomplete state.")
239+
cmd.Options = clibase.OptionSet{
240+
{
241+
Flag: "stdio",
242+
Env: "CODER_SSH_STDIO",
243+
Description: "Specifies whether to emit SSH output over stdin/stdout.",
244+
Value: clibase.BoolOf(&stdio),
245+
},
246+
{
247+
Flag: "shuffle",
248+
Env: "CODER_SSH_SHUFFLE",
249+
Description: "Specifies whether to choose a random workspace",
250+
Value: clibase.BoolOf(&shuffle),
251+
Hidden: true,
252+
},
253+
{
254+
Flag: "forward-agent",
255+
FlagShorthand: "A",
256+
Env: "CODER_SSH_FORWARD_AGENT",
257+
Description: "Specifies whether to forward the SSH agent specified in $SSH_AUTH_SOCK",
258+
Value: clibase.BoolOf(&forwardAgent),
259+
},
260+
{
261+
Flag: "forward-gpg",
262+
FlagShorthand: "G",
263+
Env: "CODER_SSH_FORWARD_GPG",
264+
Description: "Specifies whether to forward the GPG agent. Unsupported on Windows workspaces, but supports all clients. Requires gnupg (gpg, gpg2, gpgsm) and gpg-agent to be installed on the host.",
265+
Value: clibase.BoolOf(&forwardGPG),
266+
},
267+
{
268+
Flag: "identity-agent",
269+
Env: "CODER_SSH_IDENTITY_AGENT",
270+
Description: "Specifies the path to the SSH agent socket to use for identity forwarding. Defaults to $SSH_AUTH_SOCK.",
271+
Value: clibase.StringOf(&identityAgent),
272+
},
273+
{
274+
Flag: "workspace-poll-interval",
275+
Env: "CODER_WORKSPACE_POLL_INTERVAL",
276+
Description: "Specifies the interval at which to poll for a workspace to be ready. Defaults to 1s.",
277+
Value: clibase.DurationOf(&wsPollInterval),
278+
},
279+
{
280+
Flag: "no-wait",
281+
Env: "CODER_SSH_NO_WAIT",
282+
Description: "Specifies whether to wait for the workspace to be ready before connecting. Defaults to false.",
283+
Value: clibase.BoolOf(&noWait),
284+
},
285+
}
253286
return cmd
254287
}
255288

cli/templatecreate.go

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,43 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
116116
return nil
117117
},
118118
}
119-
cmd.Flags().StringVarP(&parameterFile, "parameter-file", "", "", "Specify a file path with parameter values.")
120-
cmd.Flags().StringVarP(&variablesFile, "variables-file", "", "", "Specify a file path with values for Terraform-managed variables.")
121-
cmd.Flags().StringArrayVarP(&variables, "variable", "", []string{}, "Specify a set of values for Terraform-managed variables.")
122-
cmd.Flags().StringArrayVarP(&provisionerTags, "provisioner-tag", "", []string{}, "Specify a set of tags to target provisioner daemons.")
123-
cmd.Flags().DurationVarP(&defaultTTL, "default-ttl", "", 24*time.Hour, "Specify a default TTL for workspaces created from this template.")
124-
uploadFlags.register(cmd.Flags())
125-
cmd.Flags().StringVarP(&provisioner, "test.provisioner", "", "terraform", "Customize the provisioner backend")
126-
// This is for testing!
127-
err := inv.ParsedFlags().MarkHidden("test.provisioner")
128-
if err != nil {
129-
panic(err)
119+
cmd.Options = []clibase.Option{
120+
{
121+
Flag: "parameter-file",
122+
Description: "Specify a file path with parameter values.",
123+
Value: clibase.StringOf(&parameterFile),
124+
},
125+
{
126+
Flag: "variables-file",
127+
Description: "Specify a file path with values for Terraform-managed variables.",
128+
Value: clibase.StringOf(&variablesFile),
129+
},
130+
{
131+
Flag: "variable",
132+
Description: "Specify a set of values for Terraform-managed variables.",
133+
Value: clibase.StringsOf(&variables),
134+
},
135+
{
136+
Flag: "provisioner-tag",
137+
Description: "Specify a set of tags to target provisioner daemons.",
138+
Value: clibase.StringsOf(&provisionerTags),
139+
},
140+
{
141+
Flag: "default-ttl",
142+
Description: "Specify a default TTL for workspaces created from this template.",
143+
Default: "24h",
144+
Value: clibase.DurationOf(&defaultTTL),
145+
},
146+
uploadFlags.option(),
147+
{
148+
Flag: "test.provisioner",
149+
Description: "Customize the provisioner backend",
150+
Default: "terraform",
151+
Value: clibase.StringOf(&provisioner),
152+
Hidden: true,
153+
},
154+
cliui.SkipPromptOption(),
130155
}
131-
cliui.SkipPromptOption(inv)
132156
return cmd
133157
}
134158

0 commit comments

Comments
 (0)