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

Commit 9dcf1b9

Browse files
committed
Add coder envs rm command for removing environments
1 parent c9043b7 commit 9dcf1b9

File tree

3 files changed

+108
-9
lines changed

3 files changed

+108
-9
lines changed

docs/coder_envs.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ Perform operations on the Coder environments owned by the active user.
2323

2424
* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation
2525
* [coder envs ls](coder_envs_ls.md) - list all environments owned by the active user
26+
* [coder envs rm](coder_envs_rm.md) - remove Coder environments by name
2627
* [coder envs stop](coder_envs_stop.md) - stop Coder environments by name

docs/coder_envs_rm.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## coder envs rm
2+
3+
remove Coder environments by name
4+
5+
### Synopsis
6+
7+
remove Coder environments by name
8+
9+
```
10+
coder envs rm [...environment_names] [flags]
11+
```
12+
13+
### Options
14+
15+
```
16+
-f, --force force remove the specified environments without prompting first
17+
-h, --help help for rm
18+
```
19+
20+
### Options inherited from parent commands
21+
22+
```
23+
--user string Specify the user whose resources to target (default "me")
24+
-v, --verbose show verbose output
25+
```
26+
27+
### SEE ALSO
28+
29+
* [coder envs](coder_envs.md) - Interact with Coder environments

internal/cmd/envs.go

+78-9
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@ package cmd
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"os"
67

78
"cdr.dev/coder-cli/coder-sdk"
89
"cdr.dev/coder-cli/internal/x/xtabwriter"
10+
"github.com/manifoldco/promptui"
911
"github.com/spf13/cobra"
1012
"golang.org/x/sync/errgroup"
13+
"golang.org/x/sync/semaphore"
1114
"golang.org/x/xerrors"
1215

1316
"go.coder.com/flog"
1417
)
1518

1619
func envsCommand() *cobra.Command {
17-
var outputFmt string
1820
var user string
1921
cmd := &cobra.Command{
2022
Use: "envs",
@@ -23,7 +25,20 @@ func envsCommand() *cobra.Command {
2325
}
2426
cmd.PersistentFlags().StringVar(&user, "user", coder.Me, "Specify the user whose resources to target")
2527

26-
lsCmd := &cobra.Command{
28+
cmd.AddCommand(
29+
lsEnvsCommand(&user),
30+
stopEnvsCommand(&user),
31+
rmEnvsCommand(&user),
32+
watchBuildLogCommand(),
33+
rebuildEnvCommand(),
34+
)
35+
return cmd
36+
}
37+
38+
func lsEnvsCommand(user *string) *cobra.Command {
39+
var outputFmt string
40+
41+
cmd := &cobra.Command{
2742
Use: "ls",
2843
Short: "list all environments owned by the active user",
2944
Long: "List all Coder environments owned by the active user.",
@@ -32,7 +47,7 @@ func envsCommand() *cobra.Command {
3247
if err != nil {
3348
return err
3449
}
35-
envs, err := getEnvs(cmd.Context(), client, user)
50+
envs, err := getEnvs(cmd.Context(), client, *user)
3651
if err != nil {
3752
return err
3853
}
@@ -60,16 +75,12 @@ func envsCommand() *cobra.Command {
6075
return nil
6176
},
6277
}
63-
lsCmd.Flags().StringVarP(&outputFmt, "output", "o", "human", "human | json")
64-
cmd.AddCommand(lsCmd)
65-
cmd.AddCommand(stopEnvCommand(&user))
78+
cmd.Flags().StringVarP(&outputFmt, "output", "o", "human", "human | json")
6679

67-
cmd.AddCommand(watchBuildLogCommand())
68-
cmd.AddCommand(rebuildEnvCommand())
6980
return cmd
7081
}
7182

72-
func stopEnvCommand(user *string) *cobra.Command {
83+
func stopEnvsCommand(user *string) *cobra.Command {
7384
return &cobra.Command{
7485
Use: "stop [...environment_names]",
7586
Short: "stop Coder environments by name",
@@ -117,3 +128,61 @@ coder envs --user charlie@coder.com ls -o json \
117128
},
118129
}
119130
}
131+
132+
func rmEnvsCommand(user *string) *cobra.Command {
133+
var force bool
134+
cmd := &cobra.Command{
135+
Use: "rm [...environment_names]",
136+
Short: "remove Coder environments by name",
137+
Args: cobra.MinimumNArgs(1),
138+
RunE: func(cmd *cobra.Command, args []string) error {
139+
ctx := cmd.Context()
140+
client, err := newClient()
141+
if err != nil {
142+
return err
143+
}
144+
145+
// only show one confirmation dialogue at a time
146+
confirmLimiter := semaphore.NewWeighted(1)
147+
148+
var egroup errgroup.Group
149+
for _, envName := range args {
150+
envName := envName
151+
egroup.Go(func() error {
152+
env, err := findEnv(ctx, client, envName, *user)
153+
if err != nil {
154+
flog.Error("failed to find environment by name \"%s\": %v", envName, err)
155+
return err
156+
}
157+
if !force {
158+
confirm := promptui.Prompt{
159+
Label: fmt.Sprintf("Delete environment \"%s\"? (all data will be lost)", env.Name),
160+
IsConfirm: true,
161+
}
162+
if err := confirmLimiter.Acquire(ctx, 1); err != nil {
163+
return err
164+
}
165+
166+
if _, err = confirm.Run(); err != nil {
167+
confirmLimiter.Release(1)
168+
return xerrors.Errorf("confirm deletion of environment \"%s\"", env.Name)
169+
}
170+
confirmLimiter.Release(1)
171+
}
172+
if err = client.DeleteEnvironment(cmd.Context(), env.ID); err != nil {
173+
flog.Error("failed to delete environment \"%s\": %v", env.ID, err)
174+
return xerrors.Errorf("delete environment: %w", err)
175+
}
176+
return nil
177+
})
178+
}
179+
180+
if err = egroup.Wait(); err != nil {
181+
return xerrors.Errorf("some environment remove operations failed: %w", err)
182+
}
183+
return nil
184+
},
185+
}
186+
cmd.Flags().BoolVarP(&force, "force", "f", false, "force remove the specified environments without prompting first")
187+
return cmd
188+
}

0 commit comments

Comments
 (0)