Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc5c13bc

Browse files
Emyrkkylecarbs
authored andcommitted
feat: Add confirm prompts to some cli actions (#1591)
* feat: Add confirm prompts to some cli actions- Add optional -y skip. Standardize -y flag across commands
1 parentc459928 commitc5c13bc

File tree

10 files changed

+121
-39
lines changed

10 files changed

+121
-39
lines changed

‎cli/cliui/prompt.go‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,21 @@ type PromptOptions struct {
2424
Validatefunc(string)error
2525
}
2626

27+
funcAllowSkipPrompt(cmd*cobra.Command) {
28+
cmd.Flags().BoolP("yes","y",false,"Bypass prompts")
29+
}
30+
2731
// Prompt asks the user for input.
2832
funcPrompt(cmd*cobra.Command,optsPromptOptions) (string,error) {
33+
// If the cmd has a "yes" flag for skipping confirm prompts, honor it.
34+
// If it's not a "Confirm" prompt, then don't skip. As the default value of
35+
// "yes" makes no sense.
36+
ifopts.IsConfirm&&cmd.Flags().Lookup("yes")!=nil {
37+
ifskip,_:=cmd.Flags().GetBool("yes");skip {
38+
return"yes",nil
39+
}
40+
}
41+
2942
_,_=fmt.Fprint(cmd.OutOrStdout(),Styles.FocusedPrompt.String()+opts.Text+" ")
3043
ifopts.IsConfirm {
3144
opts.Default="yes"

‎cli/cliui/prompt_test.go‎

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package cliui_test
22

33
import (
4+
"bytes"
45
"context"
6+
"io"
57
"os"
68
"os/exec"
79
"testing"
@@ -24,7 +26,7 @@ func TestPrompt(t *testing.T) {
2426
gofunc() {
2527
resp,err:=newPrompt(ptty, cliui.PromptOptions{
2628
Text:"Example",
27-
})
29+
},nil)
2830
require.NoError(t,err)
2931
msgChan<-resp
3032
}()
@@ -41,7 +43,7 @@ func TestPrompt(t *testing.T) {
4143
resp,err:=newPrompt(ptty, cliui.PromptOptions{
4244
Text:"Example",
4345
IsConfirm:true,
44-
})
46+
},nil)
4547
require.NoError(t,err)
4648
doneChan<-resp
4749
}()
@@ -50,14 +52,55 @@ func TestPrompt(t *testing.T) {
5052
require.Equal(t,"yes",<-doneChan)
5153
})
5254

55+
t.Run("Skip",func(t*testing.T) {
56+
t.Parallel()
57+
ptty:=ptytest.New(t)
58+
varbuf bytes.Buffer
59+
60+
// Copy all data written out to a buffer. When we close the ptty, we can
61+
// no longer read from the ptty.Output(), but we can read what was
62+
// written to the buffer.
63+
dataRead,doneReading:=context.WithTimeout(context.Background(),time.Second*2)
64+
gofunc() {
65+
// This will throw an error sometimes. The underlying ptty
66+
// has its own cleanup routines in t.Cleanup. Instead of
67+
// trying to control the close perfectly, just let the ptty
68+
// double close. This error isn't important, we just
69+
// want to know the ptty is done sending output.
70+
_,_=io.Copy(&buf,ptty.Output())
71+
doneReading()
72+
}()
73+
74+
doneChan:=make(chanstring)
75+
gofunc() {
76+
resp,err:=newPrompt(ptty, cliui.PromptOptions{
77+
Text:"ShouldNotSeeThis",
78+
IsConfirm:true,
79+
},func(cmd*cobra.Command) {
80+
cliui.AllowSkipPrompt(cmd)
81+
cmd.SetArgs([]string{"-y"})
82+
})
83+
require.NoError(t,err)
84+
doneChan<-resp
85+
}()
86+
87+
require.Equal(t,"yes",<-doneChan)
88+
// Close the reader to end the io.Copy
89+
require.NoError(t,ptty.Close(),"close eof reader")
90+
// Wait for the IO copy to finish
91+
<-dataRead.Done()
92+
// Timeout error means the output was hanging
93+
require.ErrorIs(t,dataRead.Err(),context.Canceled,"should be canceled")
94+
require.Len(t,buf.Bytes(),0,"expect no output")
95+
})
5396
t.Run("JSON",func(t*testing.T) {
5497
t.Parallel()
5598
ptty:=ptytest.New(t)
5699
doneChan:=make(chanstring)
57100
gofunc() {
58101
resp,err:=newPrompt(ptty, cliui.PromptOptions{
59102
Text:"Example",
60-
})
103+
},nil)
61104
require.NoError(t,err)
62105
doneChan<-resp
63106
}()
@@ -73,7 +116,7 @@ func TestPrompt(t *testing.T) {
73116
gofunc() {
74117
resp,err:=newPrompt(ptty, cliui.PromptOptions{
75118
Text:"Example",
76-
})
119+
},nil)
77120
require.NoError(t,err)
78121
doneChan<-resp
79122
}()
@@ -89,7 +132,7 @@ func TestPrompt(t *testing.T) {
89132
gofunc() {
90133
resp,err:=newPrompt(ptty, cliui.PromptOptions{
91134
Text:"Example",
92-
})
135+
},nil)
93136
require.NoError(t,err)
94137
doneChan<-resp
95138
}()
@@ -101,7 +144,7 @@ func TestPrompt(t *testing.T) {
101144
})
102145
}
103146

104-
funcnewPrompt(ptty*ptytest.PTY,opts cliui.PromptOptions) (string,error) {
147+
funcnewPrompt(ptty*ptytest.PTY,opts cliui.PromptOptions,cmdOptfunc(cmd*cobra.Command)) (string,error) {
105148
value:=""
106149
cmd:=&cobra.Command{
107150
RunE:func(cmd*cobra.Command,args []string)error {
@@ -110,7 +153,12 @@ func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions) (string, error) {
110153
returnerr
111154
},
112155
}
113-
cmd.SetOutput(ptty.Output())
156+
// Optionally modify the cmd
157+
ifcmdOpt!=nil {
158+
cmdOpt(cmd)
159+
}
160+
cmd.SetOut(ptty.Output())
161+
cmd.SetErr(ptty.Output())
114162
cmd.SetIn(ptty.Input())
115163
returnvalue,cmd.ExecuteContext(context.Background())
116164
}

‎cli/create.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ func create() *cobra.Command {
204204
},
205205
}
206206

207+
cliui.AllowSkipPrompt(cmd)
207208
cliflag.StringVarP(cmd.Flags(),&templateName,"template","t","CODER_TEMPLATE_NAME","","Specify a template name.")
208209
cliflag.StringVarP(cmd.Flags(),&parameterFile,"parameter-file","","CODER_PARAMETER_FILE","","Specify a file path with parameter values.")
209210
returncmd

‎cli/create_test.go‎

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package cli_test
22

33
import (
4+
"context"
45
"fmt"
56
"os"
67
"testing"
8+
"time"
79

810
"github.com/stretchr/testify/require"
911

@@ -46,34 +48,24 @@ func TestCreate(t *testing.T) {
4648
<-doneChan
4749
})
4850

49-
t.Run("CreateFromList",func(t*testing.T) {
51+
t.Run("CreateFromListWithSkip",func(t*testing.T) {
5052
t.Parallel()
5153
client:=coderdtest.New(t,&coderdtest.Options{IncludeProvisionerD:true})
5254
user:=coderdtest.CreateFirstUser(t,client)
5355
version:=coderdtest.CreateTemplateVersion(t,client,user.OrganizationID,nil)
5456
coderdtest.AwaitTemplateVersionJob(t,client,version.ID)
5557
_=coderdtest.CreateTemplate(t,client,user.OrganizationID,version.ID)
56-
cmd,root:=clitest.New(t,"create","my-workspace")
58+
cmd,root:=clitest.New(t,"create","my-workspace","-y")
5759
clitest.SetupConfig(t,client,root)
58-
doneChan:=make(chanstruct{})
59-
pty:=ptytest.New(t)
60-
cmd.SetIn(pty.Input())
61-
cmd.SetOut(pty.Output())
60+
cmdCtx,done:=context.WithTimeout(context.Background(),time.Second*3)
6261
gofunc() {
63-
deferclose(doneChan)
64-
err:=cmd.Execute()
62+
deferdone()
63+
err:=cmd.ExecuteContext(cmdCtx)
6564
require.NoError(t,err)
6665
}()
67-
matches:= []string{
68-
"Confirm create","yes",
69-
}
70-
fori:=0;i<len(matches);i+=2 {
71-
match:=matches[i]
72-
value:=matches[i+1]
73-
pty.ExpectMatch(match)
74-
pty.WriteLine(value)
75-
}
76-
<-doneChan
66+
// No pty interaction needed since we use the -y skip prompt flag
67+
<-cmdCtx.Done()
68+
require.ErrorIs(t,cmdCtx.Err(),context.Canceled)
7769
})
7870

7971
t.Run("FromNothing",func(t*testing.T) {

‎cli/delete.go‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ import (
1111

1212
// nolint
1313
funcdelete()*cobra.Command {
14-
return&cobra.Command{
14+
cmd:=&cobra.Command{
1515
Annotations:workspaceCommand,
1616
Use:"delete <workspace>",
1717
Short:"Delete a workspace",
1818
Aliases: []string{"rm"},
1919
Args:cobra.ExactArgs(1),
2020
RunE:func(cmd*cobra.Command,args []string)error {
21+
_,err:=cliui.Prompt(cmd, cliui.PromptOptions{
22+
Text:"Confirm delete workspace?",
23+
IsConfirm:true,
24+
})
25+
iferr!=nil {
26+
returnerr
27+
}
28+
2129
client,err:=createClient(cmd)
2230
iferr!=nil {
2331
returnerr
@@ -40,4 +48,6 @@ func delete() *cobra.Command {
4048
returncliui.WorkspaceBuild(cmd.Context(),cmd.OutOrStdout(),client,build.ID,before)
4149
},
4250
}
51+
cliui.AllowSkipPrompt(cmd)
52+
returncmd
4353
}

‎cli/delete_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func TestDelete(t *testing.T) {
2020
template:=coderdtest.CreateTemplate(t,client,user.OrganizationID,version.ID)
2121
workspace:=coderdtest.CreateWorkspace(t,client,user.OrganizationID,template.ID)
2222
coderdtest.AwaitWorkspaceBuildJob(t,client,workspace.LatestBuild.ID)
23-
cmd,root:=clitest.New(t,"delete",workspace.Name)
23+
cmd,root:=clitest.New(t,"delete",workspace.Name,"-y")
2424
clitest.SetupConfig(t,client,root)
2525
doneChan:=make(chanstruct{})
2626
pty:=ptytest.New(t)

‎cli/start.go‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ import (
1010
)
1111

1212
funcstart()*cobra.Command {
13-
return&cobra.Command{
13+
cmd:=&cobra.Command{
1414
Annotations:workspaceCommand,
1515
Use:"start <workspace>",
1616
Short:"Build a workspace with the start state",
1717
Args:cobra.ExactArgs(1),
1818
RunE:func(cmd*cobra.Command,args []string)error {
19+
_,err:=cliui.Prompt(cmd, cliui.PromptOptions{
20+
Text:"Confirm start workspace?",
21+
IsConfirm:true,
22+
})
23+
iferr!=nil {
24+
returnerr
25+
}
26+
1927
client,err:=createClient(cmd)
2028
iferr!=nil {
2129
returnerr
@@ -38,4 +46,6 @@ func start() *cobra.Command {
3846
returncliui.WorkspaceBuild(cmd.Context(),cmd.OutOrStdout(),client,build.ID,before)
3947
},
4048
}
49+
cliui.AllowSkipPrompt(cmd)
50+
returncmd
4151
}

‎cli/stop.go‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ import (
1010
)
1111

1212
funcstop()*cobra.Command {
13-
return&cobra.Command{
13+
cmd:=&cobra.Command{
1414
Annotations:workspaceCommand,
1515
Use:"stop <workspace>",
1616
Short:"Build a workspace with the stop state",
1717
Args:cobra.ExactArgs(1),
1818
RunE:func(cmd*cobra.Command,args []string)error {
19+
_,err:=cliui.Prompt(cmd, cliui.PromptOptions{
20+
Text:"Confirm stop workspace?",
21+
IsConfirm:true,
22+
})
23+
iferr!=nil {
24+
returnerr
25+
}
26+
1927
client,err:=createClient(cmd)
2028
iferr!=nil {
2129
returnerr
@@ -38,4 +46,6 @@ func stop() *cobra.Command {
3846
returncliui.WorkspaceBuild(cmd.Context(),cmd.OutOrStdout(),client,build.ID,before)
3947
},
4048
}
49+
cliui.AllowSkipPrompt(cmd)
50+
returncmd
4151
}

‎cli/templatecreate.go‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121

2222
functemplateCreate()*cobra.Command {
2323
var (
24-
yesbool
2524
directorystring
2625
provisionerstring
2726
parameterFilestring
@@ -85,14 +84,12 @@ func templateCreate() *cobra.Command {
8584
returnerr
8685
}
8786

88-
if!yes {
89-
_,err=cliui.Prompt(cmd, cliui.PromptOptions{
90-
Text:"Confirm create?",
91-
IsConfirm:true,
92-
})
93-
iferr!=nil {
94-
returnerr
95-
}
87+
_,err=cliui.Prompt(cmd, cliui.PromptOptions{
88+
Text:"Confirm create?",
89+
IsConfirm:true,
90+
})
91+
iferr!=nil {
92+
returnerr
9693
}
9794

9895
_,err=client.CreateTemplate(cmd.Context(),organization.ID, codersdk.CreateTemplateRequest{
@@ -123,7 +120,7 @@ func templateCreate() *cobra.Command {
123120
iferr!=nil {
124121
panic(err)
125122
}
126-
cmd.Flags().BoolVarP(&yes,"yes","y",false,"Bypass prompts")
123+
cliui.AllowSkipPrompt(cmd)
127124
returncmd
128125
}
129126

‎cli/templateupdate.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ func templateUpdate() *cobra.Command {
108108
currentDirectory,_:=os.Getwd()
109109
cmd.Flags().StringVarP(&directory,"directory","d",currentDirectory,"Specify the directory to create from")
110110
cmd.Flags().StringVarP(&provisioner,"test.provisioner","","terraform","Customize the provisioner backend")
111+
cliui.AllowSkipPrompt(cmd)
111112
// This is for testing!
112113
err:=cmd.Flags().MarkHidden("test.provisioner")
113114
iferr!=nil {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp