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

Commita67f5ed

Browse files
authored
Merge branch 'main' into cj/ui-workspace-table-update-icon
2 parentsb3402f6 +f44969b commita67f5ed

File tree

121 files changed

+6442
-1739
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+6442
-1739
lines changed

‎CLAUDE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,4 @@ Read [cursor rules](.cursorrules).
103103

104104
The frontend is contained in the site folder.
105105

106-
For building Frontend refer to[this document](docs/contributing/frontend.md)
107106
For building Frontend refer to[this document](docs/about/contributing/frontend.md)

‎agent/agentcontainers/api.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,11 @@ func (api *API) updaterLoop() {
378378
// and anyone looking to interact with the API.
379379
api.logger.Debug(api.ctx,"performing initial containers update")
380380
iferr:=api.updateContainers(api.ctx);err!=nil {
381-
api.logger.Error(api.ctx,"initial containers update failed",slog.Error(err))
381+
iferrors.Is(err,context.Canceled) {
382+
api.logger.Warn(api.ctx,"initial containers update canceled",slog.Error(err))
383+
}else {
384+
api.logger.Error(api.ctx,"initial containers update failed",slog.Error(err))
385+
}
382386
}else {
383387
api.logger.Debug(api.ctx,"initial containers update complete")
384388
}
@@ -399,7 +403,11 @@ func (api *API) updaterLoop() {
399403
caseapi.updateTrigger<-done:
400404
err:=<-done
401405
iferr!=nil {
402-
api.logger.Error(api.ctx,"updater loop ticker failed",slog.Error(err))
406+
iferrors.Is(err,context.Canceled) {
407+
api.logger.Warn(api.ctx,"updater loop ticker canceled",slog.Error(err))
408+
}else {
409+
api.logger.Error(api.ctx,"updater loop ticker failed",slog.Error(err))
410+
}
403411
}
404412
default:
405413
api.logger.Debug(api.ctx,"updater loop ticker skipped, update in progress")

‎agent/agentcontainers/containers_dockercli.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@ func (dcli *dockerCLI) List(ctx context.Context) (codersdk.WorkspaceAgentListCon
311311
// container IDs and returns the parsed output.
312312
// The stderr output is also returned for logging purposes.
313313
funcrunDockerInspect(ctx context.Context,execer agentexec.Execer,ids...string) (stdout,stderr []byte,errerror) {
314+
ifctx.Err()!=nil {
315+
// If the context is done, we don't want to run the command.
316+
return []byte{}, []byte{},ctx.Err()
317+
}
314318
varstdoutBuf,stderrBuf bytes.Buffer
315319
cmd:=execer.CommandContext(ctx,"docker",append([]string{"inspect"},ids...)...)
316320
cmd.Stdout=&stdoutBuf
@@ -319,6 +323,12 @@ func runDockerInspect(ctx context.Context, execer agentexec.Execer, ids ...strin
319323
stdout=bytes.TrimSpace(stdoutBuf.Bytes())
320324
stderr=bytes.TrimSpace(stderrBuf.Bytes())
321325
iferr!=nil {
326+
ifctx.Err()!=nil {
327+
// If the context was canceled while running the command,
328+
// return the context error instead of the command error,
329+
// which is likely to be "signal: killed".
330+
returnstdout,stderr,ctx.Err()
331+
}
322332
ifbytes.Contains(stderr, []byte("No such object:")) {
323333
// This can happen if a container is deleted between the time we check for its existence and the time we inspect it.
324334
returnstdout,stderr,nil

‎cli/testdata/coder_list_--output_json.golden

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@
6868
"available": 0,
6969
"most_recently_seen": null
7070
},
71-
"template_version_preset_id": null
71+
"template_version_preset_id": null,
72+
"has_ai_task": false
7273
},
7374
"latest_app_status": null,
7475
"outdated": false,

‎coderd/aitasks.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package coderd
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"strings"
7+
8+
"github.com/google/uuid"
9+
10+
"github.com/coder/coder/v2/coderd/httpapi"
11+
"github.com/coder/coder/v2/codersdk"
12+
)
13+
14+
// This endpoint is experimental and not guaranteed to be stable, so we're not
15+
// generating public-facing documentation for it.
16+
func (api*API)aiTasksPrompts(rw http.ResponseWriter,r*http.Request) {
17+
ctx:=r.Context()
18+
19+
buildIDsParam:=r.URL.Query().Get("build_ids")
20+
ifbuildIDsParam=="" {
21+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
22+
Message:"build_ids query parameter is required",
23+
})
24+
return
25+
}
26+
27+
// Parse build IDs
28+
buildIDStrings:=strings.Split(buildIDsParam,",")
29+
buildIDs:=make([]uuid.UUID,0,len(buildIDStrings))
30+
for_,idStr:=rangebuildIDStrings {
31+
id,err:=uuid.Parse(strings.TrimSpace(idStr))
32+
iferr!=nil {
33+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
34+
Message:fmt.Sprintf("Invalid build ID format: %s",idStr),
35+
Detail:err.Error(),
36+
})
37+
return
38+
}
39+
buildIDs=append(buildIDs,id)
40+
}
41+
42+
parameters,err:=api.Database.GetWorkspaceBuildParametersByBuildIDs(ctx,buildIDs)
43+
iferr!=nil {
44+
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
45+
Message:"Internal error fetching workspace build parameters.",
46+
Detail:err.Error(),
47+
})
48+
return
49+
}
50+
51+
promptsByBuildID:=make(map[string]string,len(parameters))
52+
for_,param:=rangeparameters {
53+
ifparam.Name!=codersdk.AITaskPromptParameterName {
54+
continue
55+
}
56+
buildID:=param.WorkspaceBuildID.String()
57+
promptsByBuildID[buildID]=param.Value
58+
}
59+
60+
httpapi.Write(ctx,rw,http.StatusOK, codersdk.AITasksPromptsResponse{
61+
Prompts:promptsByBuildID,
62+
})
63+
}

‎coderd/aitasks_test.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package coderd_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/uuid"
7+
"github.com/stretchr/testify/require"
8+
9+
"github.com/coder/coder/v2/coderd/coderdtest"
10+
"github.com/coder/coder/v2/coderd/database/dbtestutil"
11+
"github.com/coder/coder/v2/codersdk"
12+
"github.com/coder/coder/v2/provisioner/echo"
13+
"github.com/coder/coder/v2/provisionersdk/proto"
14+
"github.com/coder/coder/v2/testutil"
15+
)
16+
17+
funcTestAITasksPrompts(t*testing.T) {
18+
t.Parallel()
19+
20+
t.Run("EmptyBuildIDs",func(t*testing.T) {
21+
t.Parallel()
22+
client:=coderdtest.New(t,&coderdtest.Options{})
23+
_=coderdtest.CreateFirstUser(t,client)
24+
experimentalClient:=codersdk.NewExperimentalClient(client)
25+
26+
ctx:=testutil.Context(t,testutil.WaitShort)
27+
28+
// Test with empty build IDs
29+
prompts,err:=experimentalClient.AITaskPrompts(ctx, []uuid.UUID{})
30+
require.NoError(t,err)
31+
require.Empty(t,prompts.Prompts)
32+
})
33+
34+
t.Run("MultipleBuilds",func(t*testing.T) {
35+
t.Parallel()
36+
37+
if!dbtestutil.WillUsePostgres() {
38+
t.Skip("This test checks RBAC, which is not supported in the in-memory database")
39+
}
40+
41+
adminClient:=coderdtest.New(t,&coderdtest.Options{IncludeProvisionerDaemon:true})
42+
first:=coderdtest.CreateFirstUser(t,adminClient)
43+
memberClient,_:=coderdtest.CreateAnotherUser(t,adminClient,first.OrganizationID)
44+
45+
ctx:=testutil.Context(t,testutil.WaitLong)
46+
47+
// Create a template with parameters
48+
version:=coderdtest.CreateTemplateVersion(t,adminClient,first.OrganizationID,&echo.Responses{
49+
Parse:echo.ParseComplete,
50+
ProvisionPlan: []*proto.Response{{
51+
Type:&proto.Response_Plan{
52+
Plan:&proto.PlanComplete{
53+
Parameters: []*proto.RichParameter{
54+
{
55+
Name:"param1",
56+
Type:"string",
57+
DefaultValue:"default1",
58+
},
59+
{
60+
Name:codersdk.AITaskPromptParameterName,
61+
Type:"string",
62+
DefaultValue:"default2",
63+
},
64+
},
65+
},
66+
},
67+
}},
68+
ProvisionApply:echo.ApplyComplete,
69+
})
70+
template:=coderdtest.CreateTemplate(t,adminClient,first.OrganizationID,version.ID)
71+
coderdtest.AwaitTemplateVersionJobCompleted(t,adminClient,version.ID)
72+
73+
// Create two workspaces with different parameters
74+
workspace1:=coderdtest.CreateWorkspace(t,memberClient,template.ID,func(request*codersdk.CreateWorkspaceRequest) {
75+
request.RichParameterValues= []codersdk.WorkspaceBuildParameter{
76+
{Name:"param1",Value:"value1a"},
77+
{Name:codersdk.AITaskPromptParameterName,Value:"value2a"},
78+
}
79+
})
80+
coderdtest.AwaitWorkspaceBuildJobCompleted(t,memberClient,workspace1.LatestBuild.ID)
81+
82+
workspace2:=coderdtest.CreateWorkspace(t,memberClient,template.ID,func(request*codersdk.CreateWorkspaceRequest) {
83+
request.RichParameterValues= []codersdk.WorkspaceBuildParameter{
84+
{Name:"param1",Value:"value1b"},
85+
{Name:codersdk.AITaskPromptParameterName,Value:"value2b"},
86+
}
87+
})
88+
coderdtest.AwaitWorkspaceBuildJobCompleted(t,memberClient,workspace2.LatestBuild.ID)
89+
90+
workspace3:=coderdtest.CreateWorkspace(t,adminClient,template.ID,func(request*codersdk.CreateWorkspaceRequest) {
91+
request.RichParameterValues= []codersdk.WorkspaceBuildParameter{
92+
{Name:"param1",Value:"value1c"},
93+
{Name:codersdk.AITaskPromptParameterName,Value:"value2c"},
94+
}
95+
})
96+
coderdtest.AwaitWorkspaceBuildJobCompleted(t,adminClient,workspace3.LatestBuild.ID)
97+
allBuildIDs:= []uuid.UUID{workspace1.LatestBuild.ID,workspace2.LatestBuild.ID,workspace3.LatestBuild.ID}
98+
99+
experimentalMemberClient:=codersdk.NewExperimentalClient(memberClient)
100+
// Test parameters endpoint as member
101+
prompts,err:=experimentalMemberClient.AITaskPrompts(ctx,allBuildIDs)
102+
require.NoError(t,err)
103+
// we expect 2 prompts because the member client does not have access to workspace3
104+
// since it was created by the admin client
105+
require.Len(t,prompts.Prompts,2)
106+
107+
// Check workspace1 parameters
108+
build1Prompt:=prompts.Prompts[workspace1.LatestBuild.ID.String()]
109+
require.Equal(t,"value2a",build1Prompt)
110+
111+
// Check workspace2 parameters
112+
build2Prompt:=prompts.Prompts[workspace2.LatestBuild.ID.String()]
113+
require.Equal(t,"value2b",build2Prompt)
114+
115+
experimentalAdminClient:=codersdk.NewExperimentalClient(adminClient)
116+
// Test parameters endpoint as admin
117+
// we expect 3 prompts because the admin client has access to all workspaces
118+
prompts,err=experimentalAdminClient.AITaskPrompts(ctx,allBuildIDs)
119+
require.NoError(t,err)
120+
require.Len(t,prompts.Prompts,3)
121+
122+
// Check workspace3 parameters
123+
build3Prompt:=prompts.Prompts[workspace3.LatestBuild.ID.String()]
124+
require.Equal(t,"value2c",build3Prompt)
125+
})
126+
127+
t.Run("NonExistentBuildIDs",func(t*testing.T) {
128+
t.Parallel()
129+
client:=coderdtest.New(t,&coderdtest.Options{})
130+
_=coderdtest.CreateFirstUser(t,client)
131+
132+
ctx:=testutil.Context(t,testutil.WaitShort)
133+
134+
// Test with non-existent build IDs
135+
nonExistentID:=uuid.New()
136+
experimentalClient:=codersdk.NewExperimentalClient(client)
137+
prompts,err:=experimentalClient.AITaskPrompts(ctx, []uuid.UUID{nonExistentID})
138+
require.NoError(t,err)
139+
require.Empty(t,prompts.Prompts)
140+
})
141+
}

‎coderd/apidoc/docs.go

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/autobuild/lifecycle_executor.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"database/sql"
66
"fmt"
77
"net/http"
8+
"slices"
9+
"strings"
810
"sync"
911
"sync/atomic"
1012
"time"
@@ -155,6 +157,22 @@ func (e *Executor) runOnce(t time.Time) Stats {
155157
returnstats
156158
}
157159

160+
// Sort the workspaces by build template version ID so that we can group
161+
// identical template versions together. This is a slight (and imperfect)
162+
// optimization.
163+
//
164+
// `wsbuilder` needs to load the terraform files for a given template version
165+
// into memory. If 2 workspaces are using the same template version, they will
166+
// share the same files in the FileCache. This only happens if the builds happen
167+
// in parallel.
168+
// TODO: Actually make sure the cache has the files in the cache for the full
169+
// set of identical template versions. Then unload the files when the builds
170+
// are done. Right now, this relies on luck for the 10 goroutine workers to
171+
// overlap and keep the file reference in the cache alive.
172+
slices.SortFunc(workspaces,func(a,b database.GetWorkspacesEligibleForTransitionRow)int {
173+
returnstrings.Compare(a.BuildTemplateVersionID.UUID.String(),b.BuildTemplateVersionID.UUID.String())
174+
})
175+
158176
// We only use errgroup here for convenience of API, not for early
159177
// cancellation. This means we only return nil errors in th eg.Go.
160178
eg:= errgroup.Group{}

‎coderd/coderd.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,14 @@ func New(options *Options) *API {
939939
})
940940
})
941941

942+
// Experimental routes are not guaranteed to be stable and may change at any time.
943+
r.Route("/api/experimental",func(r chi.Router) {
944+
r.Use(apiKeyMiddleware)
945+
r.Route("/aitasks",func(r chi.Router) {
946+
r.Get("/prompts",api.aiTasksPrompts)
947+
})
948+
})
949+
942950
r.Route("/api/v2",func(r chi.Router) {
943951
api.APIHandler=r
944952

@@ -1536,7 +1544,6 @@ func New(options *Options) *API {
15361544
// Add CSP headers to all static assets and pages. CSP headers only affect
15371545
// browsers, so these don't make sense on api routes.
15381546
cspMW:=httpmw.CSPHeaders(
1539-
api.Experiments,
15401547
options.Telemetry.Enabled(),func() []*proxyhealth.ProxyHost {
15411548
ifapi.DeploymentValues.Dangerous.AllowAllCors {
15421549
// In this mode, allow all external requests.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp