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

Commit69d1a54

Browse files
refactor: modify task creation endpoint to return a task, not workspace
1 parentf721f3d commit69d1a54

File tree

11 files changed

+414
-111
lines changed

11 files changed

+414
-111
lines changed

‎cli/exp_taskcreate.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (r *RootCmd) taskCreate() *serpent.Command {
104104
templateVersionPresetID=preset.ID
105105
}
106106

107-
workspace,err:=expClient.CreateTask(ctx,codersdk.Me, codersdk.CreateTaskRequest{
107+
task,err:=expClient.CreateTask(ctx,codersdk.Me, codersdk.CreateTaskRequest{
108108
TemplateVersionID:templateVersionID,
109109
TemplateVersionPresetID:templateVersionPresetID,
110110
Prompt:taskInput,
@@ -116,8 +116,8 @@ func (r *RootCmd) taskCreate() *serpent.Command {
116116
_,_=fmt.Fprintf(
117117
inv.Stdout,
118118
"The task %s has been created at %s!\n",
119-
cliui.Keyword(workspace.Name),
120-
cliui.Timestamp(workspace.CreatedAt),
119+
cliui.Keyword(task.Name),
120+
cliui.Timestamp(task.CreatedAt),
121121
)
122122

123123
returnnil

‎coderd/aitasks.go‎

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package coderd
33
import (
44
"context"
55
"database/sql"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"net/http"
@@ -22,6 +23,7 @@ import (
2223
"github.com/coder/coder/v2/coderd/rbac/policy"
2324
"github.com/coder/coder/v2/coderd/searchquery"
2425
"github.com/coder/coder/v2/coderd/taskname"
26+
"github.com/coder/coder/v2/coderd/util/rwsink"
2527
"github.com/coder/coder/v2/codersdk"
2628
)
2729

@@ -186,9 +188,86 @@ func (api *API) tasksCreate(rw http.ResponseWriter, r *http.Request) {
186188
WorkspaceOwner:owner.Username,
187189
},
188190
})
189-
190191
defercommitAudit()
191-
createWorkspace(ctx,aReq,apiKey.UserID,api,owner,createReq,rw,r)
192+
193+
rwSink:=rwsink.New()
194+
createWorkspace(ctx,aReq,apiKey.UserID,api,owner,createReq,rwSink,r)
195+
196+
ifrwSink.StatusCode!=nil&&*rwSink.StatusCode==http.StatusCreated {
197+
bytes:=rwSink.ResetBody()
198+
199+
varws codersdk.Workspace
200+
iferr:=json.Unmarshal(bytes,&ws);err!=nil {
201+
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
202+
Message:"Internal error decoding created workspace",
203+
Detail:err.Error(),
204+
})
205+
return
206+
}
207+
208+
task:=taskFromWorkspace(ws,req.Prompt)
209+
210+
httpapi.Write(ctx,rwSink,http.StatusCreated,task)
211+
}
212+
213+
_=rwSink.FlushTo(rw)
214+
}
215+
216+
functaskFromWorkspace(ws codersdk.Workspace,initialPromptstring) codersdk.Task {
217+
// TODO(DanielleMaywood):
218+
// This just picks up the first agent it discovers.
219+
// This approach _might_ break when a task has multiple agents,
220+
// depending on which agent was found first.
221+
//
222+
// We explicitly do not have support for running tasks
223+
// inside of a sub agent at the moment, so we can be sure
224+
// that any sub agents are not the agent we're looking for.
225+
vartaskAgentID uuid.NullUUID
226+
vartaskAgentLifecycle*codersdk.WorkspaceAgentLifecycle
227+
vartaskAgentHealth*codersdk.WorkspaceAgentHealth
228+
for_,resource:=rangews.LatestBuild.Resources {
229+
for_,agent:=rangeresource.Agents {
230+
ifagent.ParentID.Valid {
231+
continue
232+
}
233+
234+
taskAgentID= uuid.NullUUID{Valid:true,UUID:agent.ID}
235+
taskAgentLifecycle=&agent.LifecycleState
236+
taskAgentHealth=&agent.Health
237+
break
238+
}
239+
}
240+
241+
varcurrentState*codersdk.TaskStateEntry
242+
ifws.LatestAppStatus!=nil {
243+
currentState=&codersdk.TaskStateEntry{
244+
Timestamp:ws.LatestAppStatus.CreatedAt,
245+
State:codersdk.TaskState(ws.LatestAppStatus.State),
246+
Message:ws.LatestAppStatus.Message,
247+
URI:ws.LatestAppStatus.URI,
248+
}
249+
}
250+
251+
return codersdk.Task{
252+
ID:ws.ID,
253+
OrganizationID:ws.OrganizationID,
254+
OwnerID:ws.OwnerID,
255+
OwnerName:ws.OwnerName,
256+
Name:ws.Name,
257+
TemplateID:ws.TemplateID,
258+
TemplateName:ws.TemplateName,
259+
TemplateDisplayName:ws.TemplateDisplayName,
260+
TemplateIcon:ws.TemplateIcon,
261+
WorkspaceID: uuid.NullUUID{Valid:true,UUID:ws.ID},
262+
WorkspaceAgentID:taskAgentID,
263+
WorkspaceAgentLifecycle:taskAgentLifecycle,
264+
WorkspaceAgentHealth:taskAgentHealth,
265+
CreatedAt:ws.CreatedAt,
266+
UpdatedAt:ws.UpdatedAt,
267+
InitialPrompt:initialPrompt,
268+
Status:ws.LatestBuild.Status,
269+
CurrentState:currentState,
270+
}
192271
}
193272

194273
// tasksFromWorkspaces converts a slice of API workspaces into tasks, fetching
@@ -213,60 +292,7 @@ func (api *API) tasksFromWorkspaces(ctx context.Context, apiWorkspaces []codersd
213292

214293
tasks:=make([]codersdk.Task,0,len(apiWorkspaces))
215294
for_,ws:=rangeapiWorkspaces {
216-
// TODO(DanielleMaywood):
217-
// This just picks up the first agent it discovers.
218-
// This approach _might_ break when a task has multiple agents,
219-
// depending on which agent was found first.
220-
//
221-
// We explicitly do not have support for running tasks
222-
// inside of a sub agent at the moment, so we can be sure
223-
// that any sub agents are not the agent we're looking for.
224-
vartaskAgentID uuid.NullUUID
225-
vartaskAgentLifecycle*codersdk.WorkspaceAgentLifecycle
226-
vartaskAgentHealth*codersdk.WorkspaceAgentHealth
227-
for_,resource:=rangews.LatestBuild.Resources {
228-
for_,agent:=rangeresource.Agents {
229-
ifagent.ParentID.Valid {
230-
continue
231-
}
232-
233-
taskAgentID= uuid.NullUUID{Valid:true,UUID:agent.ID}
234-
taskAgentLifecycle=&agent.LifecycleState
235-
taskAgentHealth=&agent.Health
236-
break
237-
}
238-
}
239-
240-
varcurrentState*codersdk.TaskStateEntry
241-
ifws.LatestAppStatus!=nil {
242-
currentState=&codersdk.TaskStateEntry{
243-
Timestamp:ws.LatestAppStatus.CreatedAt,
244-
State:codersdk.TaskState(ws.LatestAppStatus.State),
245-
Message:ws.LatestAppStatus.Message,
246-
URI:ws.LatestAppStatus.URI,
247-
}
248-
}
249-
250-
tasks=append(tasks, codersdk.Task{
251-
ID:ws.ID,
252-
OrganizationID:ws.OrganizationID,
253-
OwnerID:ws.OwnerID,
254-
OwnerName:ws.OwnerName,
255-
Name:ws.Name,
256-
TemplateID:ws.TemplateID,
257-
TemplateName:ws.TemplateName,
258-
TemplateDisplayName:ws.TemplateDisplayName,
259-
TemplateIcon:ws.TemplateIcon,
260-
WorkspaceID: uuid.NullUUID{Valid:true,UUID:ws.ID},
261-
WorkspaceAgentID:taskAgentID,
262-
WorkspaceAgentLifecycle:taskAgentLifecycle,
263-
WorkspaceAgentHealth:taskAgentHealth,
264-
CreatedAt:ws.CreatedAt,
265-
UpdatedAt:ws.UpdatedAt,
266-
InitialPrompt:promptsByBuildID[ws.LatestBuild.ID],
267-
Status:ws.LatestBuild.Status,
268-
CurrentState:currentState,
269-
})
295+
tasks=append(tasks,taskFromWorkspace(ws,promptsByBuildID[ws.LatestBuild.ID]))
270296
}
271297

272298
returntasks,nil

‎coderd/aitasks_test.go‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,23 @@ func TestTasksCreate(t *testing.T) {
299299
expClient:=codersdk.NewExperimentalClient(client)
300300

301301
// When: We attempt to create a Task.
302-
workspace,err:=expClient.CreateTask(ctx,"me", codersdk.CreateTaskRequest{
302+
task,err:=expClient.CreateTask(ctx,"me", codersdk.CreateTaskRequest{
303303
TemplateVersionID:template.ActiveVersionID,
304304
Prompt:taskPrompt,
305305
})
306306
require.NoError(t,err)
307-
coderdtest.AwaitWorkspaceBuildJobCompleted(t,client,workspace.LatestBuild.ID)
307+
require.True(t,task.WorkspaceID.Valid)
308+
309+
ws,err:=client.Workspace(ctx,task.WorkspaceID.UUID)
310+
require.NoError(t,err)
311+
coderdtest.AwaitWorkspaceBuildJobCompleted(t,client,ws.LatestBuild.ID)
308312

309313
// Then: We expect a workspace to have been created.
310-
assert.NotEmpty(t,workspace.Name)
311-
assert.Equal(t,template.ID,workspace.TemplateID)
314+
assert.NotEmpty(t,task.Name)
315+
assert.Equal(t,template.ID,task.TemplateID)
312316

313317
// And: We expect it to have the "AI Prompt" parameter correctly set.
314-
parameters,err:=client.WorkspaceBuildParameters(ctx,workspace.LatestBuild.ID)
318+
parameters,err:=client.WorkspaceBuildParameters(ctx,ws.LatestBuild.ID)
315319
require.NoError(t,err)
316320
require.Len(t,parameters,1)
317321
assert.Equal(t,codersdk.AITaskPromptParameterName,parameters[0].Name)

‎coderd/util/rwsink/rwsink.go‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package rwsink
2+
3+
import (
4+
"bytes"
5+
"maps"
6+
"net/http"
7+
"slices"
8+
)
9+
10+
typeResponseWriterSinkstruct {
11+
StatusCode*int
12+
header http.Header
13+
body bytes.Buffer
14+
}
15+
16+
var_ http.ResponseWriter= (*ResponseWriterSink)(nil)
17+
18+
funcNew()*ResponseWriterSink {
19+
return&ResponseWriterSink{
20+
StatusCode:nil,
21+
header:make(http.Header),
22+
body: bytes.Buffer{},
23+
}
24+
}
25+
26+
func (rw*ResponseWriterSink)Header() http.Header {
27+
returnrw.header
28+
}
29+
30+
func (rw*ResponseWriterSink)Write(data []byte) (int,error) {
31+
returnrw.body.Write(data)
32+
}
33+
34+
func (rw*ResponseWriterSink)ResetBody() []byte {
35+
body:=slices.Clone(rw.body.Bytes())
36+
rw.body= bytes.Buffer{}
37+
returnbody
38+
}
39+
40+
func (rw*ResponseWriterSink)WriteHeader(statusCodeint) {
41+
ifrw.StatusCode==nil {
42+
rw.StatusCode=&statusCode
43+
}
44+
}
45+
46+
func (rw*ResponseWriterSink)Bytes() []byte {
47+
returnrw.body.Bytes()
48+
}
49+
50+
func (rw*ResponseWriterSink)FlushTo(to http.ResponseWriter)error {
51+
maps.Copy(to.Header(),rw.header)
52+
53+
ifrw.StatusCode!=nil {
54+
to.WriteHeader(*rw.StatusCode)
55+
}
56+
57+
if_,err:=to.Write(rw.body.Bytes());err!=nil {
58+
returnerr
59+
}
60+
61+
returnnil
62+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp