Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit b957f37

Browse files
committed
Mirgation to urfave/cli
1 parent bae77f0 commit b957f37

File tree

19 files changed

+628
-781
lines changed

19 files changed

+628
-781
lines changed

Diff for: ci/integration/integration_test.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,16 @@ func TestCoderCLI(t *testing.T) {
3434
tcli.StderrEmpty(),
3535
)
3636

37-
c.Run(ctx, "coder version").Assert(t,
37+
c.Run(ctx, "coder --version").Assert(t,
3838
tcli.StderrEmpty(),
3939
tcli.Success(),
4040
tcli.StdoutMatches("linux"),
4141
)
4242

43-
c.Run(ctx, "coder help").Assert(t,
43+
c.Run(ctx, "coder --help").Assert(t,
4444
tcli.Success(),
45-
tcli.StderrMatches("Commands:"),
46-
tcli.StderrMatches("Usage: coder"),
47-
tcli.StdoutEmpty(),
45+
tcli.StdoutMatches("COMMANDS:"),
46+
tcli.StdoutMatches("USAGE:"),
4847
)
4948

5049
headlessLogin(ctx, t, c)
@@ -53,6 +52,10 @@ func TestCoderCLI(t *testing.T) {
5352
tcli.Success(),
5453
)
5554

55+
c.Run(ctx, "coder envs ls").Assert(t,
56+
tcli.Success(),
57+
)
58+
5659
c.Run(ctx, "coder urls").Assert(t,
5760
tcli.Error(),
5861
)
@@ -66,14 +69,14 @@ func TestCoderCLI(t *testing.T) {
6669
)
6770

6871
var user entclient.User
69-
c.Run(ctx, `coder users ls -o json | jq -c '.[] | select( .username == "charlie")'`).Assert(t,
72+
c.Run(ctx, `coder users ls --output json | jq -c '.[] | select( .username == "charlie")'`).Assert(t,
7073
tcli.Success(),
7174
stdoutUnmarshalsJSON(&user),
7275
)
7376
assert.Equal(t, "user email is as expected", "[email protected]", user.Email)
7477
assert.Equal(t, "username is as expected", "Charlie", user.Name)
7578

76-
c.Run(ctx, "coder users ls -o human | grep charlie").Assert(t,
79+
c.Run(ctx, "coder users ls --output human | grep charlie").Assert(t,
7780
tcli.Success(),
7881
tcli.StdoutMatches("charlie"),
7982
)
@@ -82,7 +85,7 @@ func TestCoderCLI(t *testing.T) {
8285
tcli.Success(),
8386
)
8487

85-
c.Run(ctx, "coder envs").Assert(t,
88+
c.Run(ctx, "coder envs ls").Assert(t,
8689
tcli.Error(),
8790
)
8891
}

Diff for: ci/integration/secrets_test.go

-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ func TestSecrets(t *testing.T) {
3636

3737
c.Run(ctx, "coder secrets create").Assert(t,
3838
tcli.Error(),
39-
tcli.StdoutEmpty(),
4039
)
4140

4241
// this tests the "Value:" prompt fallback

Diff for: cmd/coder/configssh.go

+106-103
Original file line numberDiff line numberDiff line change
@@ -11,162 +11,165 @@ import (
1111
"strings"
1212
"time"
1313

14-
"github.com/spf13/pflag"
15-
"go.coder.com/cli"
16-
"go.coder.com/flog"
17-
1814
"cdr.dev/coder-cli/internal/config"
1915
"cdr.dev/coder-cli/internal/entclient"
20-
)
16+
"github.com/urfave/cli"
2117

22-
var (
23-
privateKeyFilepath = filepath.Join(os.Getenv("HOME"), ".ssh", "coder_enterprise")
18+
"go.coder.com/flog"
2419
)
2520

26-
type configSSHCmd struct {
27-
filepath string
28-
remove bool
29-
30-
startToken, startMessage, endToken string
31-
}
32-
33-
func (cmd *configSSHCmd) Spec() cli.CommandSpec {
34-
return cli.CommandSpec{
35-
Name: "config-ssh",
36-
Usage: "",
37-
Desc: "add your Coder Enterprise environments to ~/.ssh/config",
21+
func makeConfigSSHCmd() cli.Command {
22+
var (
23+
configpath string
24+
remove = false
25+
)
26+
27+
return cli.Command{
28+
Name: "config-ssh",
29+
Usage: "Configure SSH to access Coder environments",
30+
Description: "Inject the proper OpenSSH configuration into your local SSH config file.",
31+
Action: configSSH(&configpath, &remove),
32+
Flags: []cli.Flag{
33+
cli.StringFlag{
34+
Name: "filepath",
35+
Usage: "overide the default path of your ssh config file",
36+
Value: filepath.Join(os.Getenv("HOME"), ".ssh", "config"),
37+
TakesFile: true,
38+
Destination: &configpath,
39+
},
40+
cli.BoolFlag{
41+
Name: "remove",
42+
Usage: "remove the auto-generated Coder Enterprise ssh config",
43+
Destination: &remove,
44+
},
45+
},
3846
}
3947
}
4048

41-
func (cmd *configSSHCmd) RegisterFlags(fl *pflag.FlagSet) {
42-
fl.BoolVar(&cmd.remove, "remove", false, "remove the auto-generated Coder Enterprise ssh config")
43-
home := os.Getenv("HOME")
44-
defaultPath := filepath.Join(home, ".ssh", "config")
45-
fl.StringVar(&cmd.filepath, "config-path", defaultPath, "overide the default path of your ssh config file")
46-
47-
cmd.startToken = "# ------------START-CODER-ENTERPRISE-----------"
48-
cmd.startMessage = `# The following has been auto-generated by "coder config-ssh"
49+
func configSSH(filepath *string, remove *bool) func(c *cli.Context) {
50+
startToken := "# ------------START-CODER-ENTERPRISE-----------"
51+
startMessage := `# The following has been auto-generated by "coder config-ssh"
4952
# to make accessing your Coder Enterprise environments easier.
5053
#
5154
# To remove this blob, run:
5255
#
5356
# coder config-ssh --remove
5457
#
5558
# You should not hand-edit this section, unless you are deleting it.`
56-
cmd.endToken = "# ------------END-CODER-ENTERPRISE------------"
57-
}
58-
59-
func (cmd *configSSHCmd) Run(fl *pflag.FlagSet) {
60-
ctx, cancel := context.WithCancel(context.Background())
61-
defer cancel()
59+
endToken := "# ------------END-CODER-ENTERPRISE------------"
60+
61+
return func(c *cli.Context) {
62+
ctx, cancel := context.WithCancel(context.Background())
63+
defer cancel()
64+
65+
currentConfig, err := readStr(*filepath)
66+
if os.IsNotExist(err) {
67+
// SSH configs are not always already there.
68+
currentConfig = ""
69+
} else if err != nil {
70+
flog.Fatal("failed to read ssh config file %q: %v", filepath, err)
71+
}
6272

63-
currentConfig, err := readStr(cmd.filepath)
64-
if os.IsNotExist(err) {
65-
// SSH configs are not always already there.
66-
currentConfig = ""
67-
} else if err != nil {
68-
flog.Fatal("failed to read ssh config file %q: %v", cmd.filepath, err)
69-
}
73+
startIndex := strings.Index(currentConfig, startToken)
74+
endIndex := strings.Index(currentConfig, endToken)
7075

71-
startIndex := strings.Index(currentConfig, cmd.startToken)
72-
endIndex := strings.Index(currentConfig, cmd.endToken)
76+
if *remove {
77+
if startIndex == -1 || endIndex == -1 {
78+
flog.Fatal("the Coder Enterprise ssh configuration section could not be safely deleted or does not exist")
79+
}
80+
currentConfig = currentConfig[:startIndex-1] + currentConfig[endIndex+len(endToken)+1:]
7381

74-
if cmd.remove {
75-
if startIndex == -1 || endIndex == -1 {
76-
flog.Fatal("the Coder Enterprise ssh configuration section could not be safely deleted or does not exist")
77-
}
78-
currentConfig = currentConfig[:startIndex-1] + currentConfig[endIndex+len(cmd.endToken)+1:]
82+
err = writeStr(*filepath, currentConfig)
83+
if err != nil {
84+
flog.Fatal("failed to write to ssh config file %q: %v", *filepath, err)
85+
}
7986

80-
err = writeStr(cmd.filepath, currentConfig)
81-
if err != nil {
82-
flog.Fatal("failed to write to ssh config file %q: %v", cmd.filepath, err)
87+
return
8388
}
8489

85-
return
86-
}
90+
entClient := requireAuth()
8791

88-
entClient := requireAuth()
92+
sshAvailable := isSSHAvailable(ctx)
93+
if !sshAvailable {
94+
flog.Fatal("SSH is disabled or not available for your Coder Enterprise deployment.")
95+
}
8996

90-
sshAvailable := cmd.ensureSSHAvailable(ctx)
91-
if !sshAvailable {
92-
flog.Fatal("SSH is disabled or not available for your Coder Enterprise deployment.")
93-
}
97+
me, err := entClient.Me()
98+
if err != nil {
99+
flog.Fatal("failed to fetch username: %v", err)
100+
}
94101

95-
me, err := entClient.Me()
96-
if err != nil {
97-
flog.Fatal("failed to fetch username: %v", err)
98-
}
102+
envs := getEnvs(entClient)
103+
if len(envs) < 1 {
104+
flog.Fatal("no environments found")
105+
}
106+
newConfig, err := makeNewConfigs(me.Username, envs, startToken, startMessage, endToken)
107+
if err != nil {
108+
flog.Fatal("failed to make new ssh configurations: %v", err)
109+
}
99110

100-
envs := getEnvs(entClient)
101-
if len(envs) < 1 {
102-
flog.Fatal("no environments found")
103-
}
104-
newConfig, err := cmd.makeNewConfigs(me.Username, envs)
105-
if err != nil {
106-
flog.Fatal("failed to make new ssh configurations: %v", err)
107-
}
111+
// if we find the old config, remove those chars from the string
112+
if startIndex != -1 && endIndex != -1 {
113+
currentConfig = currentConfig[:startIndex-1] + currentConfig[endIndex+len(endToken)+1:]
114+
}
108115

109-
// if we find the old config, remove those chars from the string
110-
if startIndex != -1 && endIndex != -1 {
111-
currentConfig = currentConfig[:startIndex-1] + currentConfig[endIndex+len(cmd.endToken)+1:]
112-
}
116+
err = writeStr(*filepath, currentConfig+newConfig)
117+
if err != nil {
118+
flog.Fatal("failed to write new configurations to ssh config file %q: %v", filepath, err)
119+
}
120+
err = writeSSHKey(ctx, entClient)
121+
if err != nil {
122+
flog.Fatal("failed to fetch and write ssh key: %v", err)
123+
}
113124

114-
err = writeStr(cmd.filepath, currentConfig+newConfig)
115-
if err != nil {
116-
flog.Fatal("failed to write new configurations to ssh config file %q: %v", cmd.filepath, err)
117-
}
118-
err = writeSSHKey(ctx, entClient)
119-
if err != nil {
120-
flog.Fatal("failed to fetch and write ssh key: %v", err)
125+
fmt.Printf("An auto-generated ssh config was written to %q\n", *filepath)
126+
fmt.Printf("Your private ssh key was written to %q\n", privateKeyFilepath)
127+
fmt.Println("You should now be able to ssh into your environment")
128+
fmt.Printf("For example, try running\n\n\t$ ssh coder.%s\n\n", envs[0].Name)
121129
}
122-
123-
fmt.Printf("An auto-generated ssh config was written to %q\n", cmd.filepath)
124-
fmt.Printf("Your private ssh key was written to %q\n", privateKeyFilepath)
125-
fmt.Println("You should now be able to ssh into your environment")
126-
fmt.Printf("For example, try running\n\n\t$ ssh coder.%s\n\n", envs[0].Name)
127130
}
128131

132+
var (
133+
privateKeyFilepath = filepath.Join(os.Getenv("HOME"), ".ssh", "coder_enterprise")
134+
)
135+
129136
func writeSSHKey(ctx context.Context, client *entclient.Client) error {
130137
key, err := client.SSHKey()
131138
if err != nil {
132139
return err
133140
}
134-
err = ioutil.WriteFile(privateKeyFilepath, []byte(key.PrivateKey), 0400)
135-
if err != nil {
136-
return err
137-
}
138-
return nil
141+
return ioutil.WriteFile(privateKeyFilepath, []byte(key.PrivateKey), 0400)
139142
}
140143

141-
func (cmd *configSSHCmd) makeNewConfigs(userName string, envs []entclient.Environment) (string, error) {
144+
func makeNewConfigs(userName string, envs []entclient.Environment, startToken, startMsg, endToken string) (string, error) {
142145
hostname, err := configuredHostname()
143146
if err != nil {
144147
return "", nil
145148
}
146149

147-
newConfig := fmt.Sprintf("\n%s\n%s\n\n", cmd.startToken, cmd.startMessage)
150+
newConfig := fmt.Sprintf("\n%s\n%s\n\n", startToken, startMsg)
148151
for _, env := range envs {
149-
newConfig += cmd.makeConfig(hostname, userName, env.Name)
152+
newConfig += makeSSHConfig(hostname, userName, env.Name)
150153
}
151-
newConfig += fmt.Sprintf("\n%s\n", cmd.endToken)
154+
newConfig += fmt.Sprintf("\n%s\n", endToken)
152155

153156
return newConfig, nil
154157
}
155158

156-
func (cmd *configSSHCmd) makeConfig(host, userName, envName string) string {
159+
func makeSSHConfig(host, userName, envName string) string {
157160
return fmt.Sprintf(
158161
`Host coder.%s
159-
HostName %s
160-
User %s-%s
161-
StrictHostKeyChecking no
162-
ConnectTimeout=0
163-
IdentityFile=%s
164-
ServerAliveInterval 60
165-
ServerAliveCountMax 3
162+
HostName %s
163+
User %s-%s
164+
StrictHostKeyChecking no
165+
ConnectTimeout=0
166+
IdentityFile=%s
167+
ServerAliveInterval 60
168+
ServerAliveCountMax 3
166169
`, envName, host, userName, envName, privateKeyFilepath)
167170
}
168171

169-
func (cmd *configSSHCmd) ensureSSHAvailable(ctx context.Context) bool {
172+
func isSSHAvailable(ctx context.Context) bool {
170173
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
171174
defer cancel()
172175

Diff for: cmd/coder/envs.go

+23-20
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,30 @@ package main
33
import (
44
"fmt"
55

6-
"github.com/spf13/pflag"
7-
8-
"go.coder.com/cli"
6+
"github.com/urfave/cli"
97
)
108

11-
type envsCmd struct {
12-
}
13-
14-
func (cmd envsCmd) Spec() cli.CommandSpec {
15-
return cli.CommandSpec{
16-
Name: "envs",
17-
Desc: "get a list of environments owned by the authenticated user",
18-
}
19-
}
20-
21-
func (cmd envsCmd) Run(fl *pflag.FlagSet) {
22-
entClient := requireAuth()
23-
24-
envs := getEnvs(entClient)
25-
26-
for _, env := range envs {
27-
fmt.Println(env.Name)
9+
func makeEnvsCommand() cli.Command {
10+
return cli.Command{
11+
Name: "envs",
12+
Usage: "Interact with Coder environments",
13+
Description: "Perform operations on the Coder environments owned by the active user.",
14+
Subcommands: []cli.Command{
15+
{
16+
Name: "ls",
17+
Usage: "list all environments owned by the active user",
18+
Description: "List all Coder environments owned by the active user.",
19+
ArgsUsage: "[...flags]>",
20+
Action: func(c *cli.Context) {
21+
entClient := requireAuth()
22+
envs := getEnvs(entClient)
23+
24+
for _, env := range envs {
25+
fmt.Println(env.Name)
26+
}
27+
},
28+
Flags: nil,
29+
},
30+
},
2831
}
2932
}

0 commit comments

Comments
 (0)