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

Commita2a758d

Browse files
chore(cli): re-order CLI create command (#19658)
Relates tocoder/internal#893Instead of `coder task create <template> --input <input>`, it is now`coder task create <input> --template <template>`.If there is only one AI task template on the deployment, the`--template` parameter can be omitted.
1 parent5198127 commita2a758d

File tree

2 files changed

+147
-28
lines changed

2 files changed

+147
-28
lines changed

‎cli/exp_taskcreate.go‎renamed to ‎cli/exp_task_create.go‎

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cli
22

33
import (
44
"fmt"
5+
"io"
56
"strings"
67

78
"github.com/google/uuid"
@@ -20,43 +21,49 @@ func (r *RootCmd) taskCreate() *serpent.Command {
2021
templateNamestring
2122
templateVersionNamestring
2223
presetNamestring
23-
taskInputstring
24+
stdinbool
2425
)
2526

2627
cmd:=&serpent.Command{
27-
Use:"create [template]",
28+
Use:"create [input]",
2829
Short:"Create an experimental task",
2930
Middleware:serpent.Chain(
3031
serpent.RequireRangeArgs(0,1),
3132
r.InitClient(client),
3233
),
3334
Options: serpent.OptionSet{
3435
{
35-
Flag:"input",
36-
Env:"CODER_TASK_INPUT",
37-
Value:serpent.StringOf(&taskInput),
38-
Required:true,
39-
},
40-
{
36+
Name:"template",
37+
Flag:"template",
4138
Env:"CODER_TASK_TEMPLATE_NAME",
4239
Value:serpent.StringOf(&templateName),
4340
},
4441
{
42+
Name:"template-version",
43+
Flag:"template-version",
4544
Env:"CODER_TASK_TEMPLATE_VERSION",
4645
Value:serpent.StringOf(&templateVersionName),
4746
},
4847
{
48+
Name:"preset",
4949
Flag:"preset",
5050
Env:"CODER_TASK_PRESET_NAME",
5151
Value:serpent.StringOf(&presetName),
5252
Default:PresetNone,
5353
},
54+
{
55+
Name:"stdin",
56+
Flag:"stdin",
57+
Description:"Reads from stdin for the task input.",
58+
Value:serpent.BoolOf(&stdin),
59+
},
5460
},
5561
Handler:func(inv*serpent.Invocation)error {
5662
var (
5763
ctx=inv.Context()
5864
expClient=codersdk.NewExperimentalClient(client)
5965

66+
taskInputstring
6067
templateVersionID uuid.UUID
6168
templateVersionPresetID uuid.UUID
6269
)
@@ -66,22 +73,68 @@ func (r *RootCmd) taskCreate() *serpent.Command {
6673
returnxerrors.Errorf("get current organization: %w",err)
6774
}
6875

69-
iflen(inv.Args)>0 {
70-
templateName,templateVersionName,_=strings.Cut(inv.Args[0],"@")
76+
ifstdin {
77+
bytes,err:=io.ReadAll(inv.Stdin)
78+
iferr!=nil {
79+
returnxerrors.Errorf("reading stdin: %w",err)
80+
}
81+
82+
taskInput=string(bytes)
83+
}else {
84+
iflen(inv.Args)!=1 {
85+
returnxerrors.Errorf("expected an input for task")
86+
}
87+
88+
taskInput=inv.Args[0]
7189
}
7290

73-
iftemplateName=="" {
74-
returnxerrors.Errorf("template name not provided")
91+
iftaskInput=="" {
92+
returnxerrors.Errorf("a task cannot be started with an empty input")
7593
}
7694

77-
iftemplateVersionName!="" {
95+
switch {
96+
casetemplateName=="":
97+
templates,err:=client.Templates(ctx, codersdk.TemplateFilter{SearchQuery:"has-ai-task:true",OrganizationID:organization.ID})
98+
iferr!=nil {
99+
returnxerrors.Errorf("list templates: %w",err)
100+
}
101+
102+
iflen(templates)==0 {
103+
returnxerrors.Errorf("no task templates configured")
104+
}
105+
106+
// When a deployment has only 1 AI task template, we will
107+
// allow omitting the template. Otherwise we will require
108+
// the user to be explicit with their choice of template.
109+
iflen(templates)>1 {
110+
templateNames:=make([]string,0,len(templates))
111+
for_,template:=rangetemplates {
112+
templateNames=append(templateNames,template.Name)
113+
}
114+
115+
returnxerrors.Errorf("template name not provided, available templates: %s",strings.Join(templateNames,", "))
116+
}
117+
118+
iftemplateVersionName!="" {
119+
templateVersion,err:=client.TemplateVersionByOrganizationAndName(ctx,organization.ID,templates[0].Name,templateVersionName)
120+
iferr!=nil {
121+
returnxerrors.Errorf("get template version: %w",err)
122+
}
123+
124+
templateVersionID=templateVersion.ID
125+
}else {
126+
templateVersionID=templates[0].ActiveVersionID
127+
}
128+
129+
casetemplateVersionName!="":
78130
templateVersion,err:=client.TemplateVersionByOrganizationAndName(ctx,organization.ID,templateName,templateVersionName)
79131
iferr!=nil {
80132
returnxerrors.Errorf("get template version: %w",err)
81133
}
82134

83135
templateVersionID=templateVersion.ID
84-
}else {
136+
137+
default:
85138
template,err:=client.TemplateByName(ctx,organization.ID,templateName)
86139
iferr!=nil {
87140
returnxerrors.Errorf("get template: %w",err)

‎cli/exp_taskcreate_test.go‎renamed to ‎cli/exp_task_create_test.go‎

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ func TestTaskCreate(t *testing.T) {
6060
Name:presetName,
6161
},
6262
})
63+
case"/api/v2/templates":
64+
httpapi.Write(ctx,w,http.StatusOK, []codersdk.Template{
65+
{
66+
ID:templateID,
67+
Name:templateName,
68+
ActiveVersionID:templateVersionID,
69+
},
70+
})
6371
case"/api/experimental/tasks/me":
6472
varreq codersdk.CreateTaskRequest
6573
if!httpapi.Read(ctx,w,r,&req) {
@@ -88,71 +96,80 @@ func TestTaskCreate(t *testing.T) {
8896
tests:= []struct {
8997
args []string
9098
env []string
99+
stdinstring
91100
expectErrorstring
92101
expectOutputstring
93102
handlerfunc(t*testing.T,ctx context.Context) http.HandlerFunc
94103
}{
95104
{
96-
args: []string{"my-template@my-template-version","--input","my custom prompt","--org",organizationID.String()},
105+
args: []string{"--stdin"},
106+
stdin:"reads prompt from stdin",
107+
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
108+
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
109+
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","my-template-version","","reads prompt from stdin")
110+
},
111+
},
112+
{
113+
args: []string{"my custom prompt"},
97114
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
98115
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
99116
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","my-template-version","","my custom prompt")
100117
},
101118
},
102119
{
103-
args: []string{"my-template","--input","my custom prompt","--org",organizationID.String()},
104-
env: []string{"CODER_TASK_TEMPLATE_VERSION=my-template-version"},
120+
args: []string{"my custom prompt","--template","my-template","--template-version","my-template-version","--org",organizationID.String()},
105121
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
106122
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
107123
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","my-template-version","","my custom prompt")
108124
},
109125
},
110126
{
111-
args: []string{"--input","my custom prompt","--org",organizationID.String()},
112-
env: []string{"CODER_TASK_TEMPLATE_NAME=my-template","CODER_TASK_TEMPLATE_VERSION=my-template-version"},
127+
args: []string{"my custom prompt","--template","my-template","--org",organizationID.String()},
128+
env: []string{"CODER_TASK_TEMPLATE_VERSION=my-template-version"},
113129
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
114130
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
115131
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","my-template-version","","my custom prompt")
116132
},
117133
},
118134
{
119-
env: []string{"CODER_TASK_TEMPLATE_NAME=my-template","CODER_TASK_TEMPLATE_VERSION=my-template-version","CODER_TASK_INPUT=my custom prompt","CODER_ORGANIZATION="+organizationID.String()},
135+
args: []string{"my custom prompt","--org",organizationID.String()},
136+
env: []string{"CODER_TASK_TEMPLATE_NAME=my-template","CODER_TASK_TEMPLATE_VERSION=my-template-version"},
120137
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
121138
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
122139
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","my-template-version","","my custom prompt")
123140
},
124141
},
125142
{
126-
args: []string{"my-template","--input","my custom prompt","--org",organizationID.String()},
143+
args: []string{"my custom prompt","--template","my-template","--org",organizationID.String()},
127144
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
128145
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
129146
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","","","my custom prompt")
130147
},
131148
},
132149
{
133-
args: []string{"my-template","--input","my custom prompt","--preset","my-preset","--org",organizationID.String()},
150+
args: []string{"my custom prompt","--template","my-template","--preset","my-preset","--org",organizationID.String()},
134151
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
135152
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
136153
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","","my-preset","my custom prompt")
137154
},
138155
},
139156
{
140-
args: []string{"my-template","--input","my custom prompt"},
157+
args: []string{"my custom prompt","--template","my-template"},
141158
env: []string{"CODER_TASK_PRESET_NAME=my-preset"},
142159
expectOutput:fmt.Sprintf("The task %s has been created at %s!",cliui.Keyword("task-wild-goldfish-27"),cliui.Timestamp(taskCreatedAt)),
143160
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
144161
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","","my-preset","my custom prompt")
145162
},
146163
},
147164
{
148-
args: []string{"my-template","--input","my custom prompt","--preset","not-real-preset"},
165+
args: []string{"my custom prompt","--template","my-template","--preset","not-real-preset"},
149166
expectError:`preset "not-real-preset" not found`,
150167
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
151168
returntemplateAndVersionFoundHandler(t,ctx,organizationID,"my-template","","my-preset","my custom prompt")
152169
},
153170
},
154171
{
155-
args: []string{"my-template@not-real-template-version","--input","my custom prompt"},
172+
args: []string{"my custom prompt","--template","my-template","--template-version","not-real-template-version"},
156173
expectError:httpapi.ResourceNotFoundResponse.Message,
157174
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
158175
returnfunc(w http.ResponseWriter,r*http.Request) {
@@ -163,6 +180,11 @@ func TestTaskCreate(t *testing.T) {
163180
ID:organizationID,
164181
}},
165182
})
183+
casefmt.Sprintf("/api/v2/organizations/%s/templates/my-template",organizationID):
184+
httpapi.Write(ctx,w,http.StatusOK, codersdk.Template{
185+
ID:templateID,
186+
ActiveVersionID:templateVersionID,
187+
})
166188
casefmt.Sprintf("/api/v2/organizations/%s/templates/my-template/versions/not-real-template-version",organizationID):
167189
httpapi.ResourceNotFound(w)
168190
default:
@@ -172,7 +194,7 @@ func TestTaskCreate(t *testing.T) {
172194
},
173195
},
174196
{
175-
args: []string{"not-real-template","--input","my custom prompt","--org",organizationID.String()},
197+
args: []string{"my custom prompt","--template","not-real-template","--org",organizationID.String()},
176198
expectError:httpapi.ResourceNotFoundResponse.Message,
177199
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
178200
returnfunc(w http.ResponseWriter,r*http.Request) {
@@ -192,7 +214,7 @@ func TestTaskCreate(t *testing.T) {
192214
},
193215
},
194216
{
195-
args: []string{"template-in-different-org","--input","my-custom-prompt","--org",anotherOrganizationID.String()},
217+
args: []string{"my-custom-prompt","--template","template-in-different-org","--org",anotherOrganizationID.String()},
196218
expectError:httpapi.ResourceNotFoundResponse.Message,
197219
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
198220
returnfunc(w http.ResponseWriter,r*http.Request) {
@@ -212,7 +234,7 @@ func TestTaskCreate(t *testing.T) {
212234
},
213235
},
214236
{
215-
args: []string{"no-org","--input","my-custom-prompt"},
237+
args: []string{"no-org-prompt"},
216238
expectError:"Must select an organization with --org=<org_name>",
217239
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
218240
returnfunc(w http.ResponseWriter,r*http.Request) {
@@ -225,6 +247,49 @@ func TestTaskCreate(t *testing.T) {
225247
}
226248
},
227249
},
250+
{
251+
args: []string{"no task templates"},
252+
expectError:"no task templates configured",
253+
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
254+
returnfunc(w http.ResponseWriter,r*http.Request) {
255+
switchr.URL.Path {
256+
case"/api/v2/users/me/organizations":
257+
httpapi.Write(ctx,w,http.StatusOK, []codersdk.Organization{
258+
{MinimalOrganization: codersdk.MinimalOrganization{
259+
ID:organizationID,
260+
}},
261+
})
262+
case"/api/v2/templates":
263+
httpapi.Write(ctx,w,http.StatusOK, []codersdk.Template{})
264+
default:
265+
t.Errorf("unexpected path: %s",r.URL.Path)
266+
}
267+
}
268+
},
269+
},
270+
{
271+
args: []string{"no template name provided"},
272+
expectError:"template name not provided, available templates: wibble, wobble",
273+
handler:func(t*testing.T,ctx context.Context) http.HandlerFunc {
274+
returnfunc(w http.ResponseWriter,r*http.Request) {
275+
switchr.URL.Path {
276+
case"/api/v2/users/me/organizations":
277+
httpapi.Write(ctx,w,http.StatusOK, []codersdk.Organization{
278+
{MinimalOrganization: codersdk.MinimalOrganization{
279+
ID:organizationID,
280+
}},
281+
})
282+
case"/api/v2/templates":
283+
httpapi.Write(ctx,w,http.StatusOK, []codersdk.Template{
284+
{Name:"wibble"},
285+
{Name:"wobble"},
286+
})
287+
default:
288+
t.Errorf("unexpected path: %s",r.URL.Path)
289+
}
290+
}
291+
},
292+
},
228293
}
229294

230295
for_,tt:=rangetests {
@@ -244,6 +309,7 @@ func TestTaskCreate(t *testing.T) {
244309

245310
inv,root:=clitest.New(t,append(args,tt.args...)...)
246311
inv.Environ=serpent.ParseEnviron(tt.env,"")
312+
inv.Stdin=strings.NewReader(tt.stdin)
247313
inv.Stdout=&sb
248314
inv.Stderr=&sb
249315
clitest.SetupConfig(t,client,root)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp