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

Commit7e69095

Browse files
feat(agent/agentcontainers): support displayApps from devcontainer config
1 parentae3882a commit7e69095

File tree

11 files changed

+588
-26
lines changed

11 files changed

+588
-26
lines changed

‎agent/agentcontainers/acmock/acmock.go‎

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

‎agent/agentcontainers/api.go‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,13 +1096,25 @@ func (api *API) injectSubAgentIntoContainerLocked(ctx context.Context, dc coders
10961096
directory=DevcontainerDefaultContainerWorkspaceFolder
10971097
}
10981098

1099+
vardisplayApps []codersdk.DisplayApp
1100+
1101+
ifconfig,err:=api.dccli.ReadConfig(ctx,dc.WorkspaceFolder,dc.ConfigPath);err!=nil {
1102+
api.logger.Error(ctx,"unable to read devcontainer config",slog.Error(err))
1103+
}else {
1104+
coderCustomization:=config.Configuration.Customizations.Coder
1105+
ifcoderCustomization!=nil {
1106+
displayApps=coderCustomization.DisplayApps
1107+
}
1108+
}
1109+
10991110
// The preparation of the subagent is done, now we can create the
11001111
// subagent record in the database to receive the auth token.
11011112
createdAgent,err:=api.subAgentClient.Create(ctx,SubAgent{
11021113
Name:dc.Name,
11031114
Directory:directory,
11041115
OperatingSystem:"linux",// Assuming Linux for dev containers.
11051116
Architecture:arch,
1117+
DisplayApps:displayApps,
11061118
})
11071119
iferr!=nil {
11081120
returnxerrors.Errorf("create agent: %w",err)

‎agent/agentcontainers/api_test.go‎

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,14 @@ func (f *fakeContainerCLI) ExecAs(ctx context.Context, name, user string, args .
6060
// fakeDevcontainerCLI implements the agentcontainers.DevcontainerCLI
6161
// interface for testing.
6262
typefakeDevcontainerCLIstruct {
63-
upIDstring
64-
upErrerror
65-
upErrCchanerror// If set, send to return err, close to return upErr.
66-
execErrerror
67-
execErrCchanfunc(cmdstring,args...string)error// If set, send fn to return err, nil or close to return execErr.
63+
upIDstring
64+
upErrerror
65+
upErrCchanerror// If set, send to return err, close to return upErr.
66+
execErrerror
67+
execErrCchanfunc(cmdstring,args...string)error// If set, send fn to return err, nil or close to return execErr.
68+
readConfig agentcontainers.DevcontainerConfig
69+
readConfigErrerror
70+
readConfigErrCchanerror
6871
}
6972

7073
func (f*fakeDevcontainerCLI)Up(ctx context.Context,_,_string,_...agentcontainers.DevcontainerCLIUpOptions) (string,error) {
@@ -95,6 +98,20 @@ func (f *fakeDevcontainerCLI) Exec(ctx context.Context, _, _ string, cmd string,
9598
returnf.execErr
9699
}
97100

101+
func (f*fakeDevcontainerCLI)ReadConfig(ctx context.Context,_,_string,_...agentcontainers.DevcontainerCLIReadConfigOptions) (agentcontainers.DevcontainerConfig,error) {
102+
iff.readConfigErrC!=nil {
103+
select {
104+
case<-ctx.Done():
105+
return agentcontainers.DevcontainerConfig{},ctx.Err()
106+
caseerr,ok:=<-f.readConfigErrC:
107+
ifok {
108+
returnf.readConfig,err
109+
}
110+
}
111+
}
112+
returnf.readConfig,f.readConfigErr
113+
}
114+
98115
// fakeWatcher implements the watcher.Watcher interface for testing.
99116
// It allows controlling what events are sent and when.
100117
typefakeWatcherstruct {
@@ -1132,10 +1149,12 @@ func TestAPI(t *testing.T) {
11321149
Containers: []codersdk.WorkspaceAgentContainer{container},
11331150
},
11341151
}
1152+
fDCCLI:=&fakeDevcontainerCLI{}
11351153

11361154
logger:=slogtest.Make(t,nil).Leveled(slog.LevelDebug)
11371155
api:=agentcontainers.NewAPI(
11381156
logger,
1157+
agentcontainers.WithDevcontainerCLI(fDCCLI),
11391158
agentcontainers.WithContainerCLI(fLister),
11401159
agentcontainers.WithWatcher(fWatcher),
11411160
agentcontainers.WithClock(mClock),
@@ -1425,6 +1444,130 @@ func TestAPI(t *testing.T) {
14251444
assert.Contains(t,fakeSAC.deleted,existingAgentID)
14261445
assert.Empty(t,fakeSAC.agents)
14271446
})
1447+
1448+
t.Run("Create",func(t*testing.T) {
1449+
t.Parallel()
1450+
1451+
ifruntime.GOOS=="windows" {
1452+
t.Skip("Dev Container tests are not supported on Windows (this test uses mocks but fails due to Windows paths)")
1453+
}
1454+
1455+
tests:= []struct {
1456+
namestring
1457+
customization*agentcontainers.CoderCustomization
1458+
afterCreatefunc(t*testing.T,subAgent agentcontainers.SubAgent)
1459+
}{
1460+
{
1461+
name:"WithoutCustomization",
1462+
customization:nil,
1463+
},
1464+
{
1465+
name:"WithDisplayApps",
1466+
customization:&agentcontainers.CoderCustomization{
1467+
DisplayApps: []codersdk.DisplayApp{
1468+
codersdk.DisplayAppSSH,
1469+
codersdk.DisplayAppWebTerminal,
1470+
codersdk.DisplayAppVSCodeInsiders,
1471+
},
1472+
},
1473+
afterCreate:func(t*testing.T,subAgent agentcontainers.SubAgent) {
1474+
require.Len(t,subAgent.DisplayApps,3)
1475+
assert.Equal(t,codersdk.DisplayAppSSH,subAgent.DisplayApps[0])
1476+
assert.Equal(t,codersdk.DisplayAppWebTerminal,subAgent.DisplayApps[1])
1477+
assert.Equal(t,codersdk.DisplayAppVSCodeInsiders,subAgent.DisplayApps[2])
1478+
},
1479+
},
1480+
}
1481+
1482+
for_,tt:=rangetests {
1483+
t.Run(tt.name,func(t*testing.T) {
1484+
t.Parallel()
1485+
1486+
var (
1487+
ctx=testutil.Context(t,testutil.WaitMedium)
1488+
logger=testutil.Logger(t)
1489+
mClock=quartz.NewMock(t)
1490+
mCCLI=acmock.NewMockContainerCLI(gomock.NewController(t))
1491+
fSAC=&fakeSubAgentClient{createErrC:make(chanerror,1)}
1492+
fDCCLI=&fakeDevcontainerCLI{
1493+
readConfig: agentcontainers.DevcontainerConfig{
1494+
Configuration: agentcontainers.DevcontainerConfiguration{
1495+
Customizations: agentcontainers.DevcontainerCustomizations{
1496+
Coder:tt.customization,
1497+
},
1498+
},
1499+
},
1500+
execErrC:make(chanfunc(cmdstring,args...string)error,1),
1501+
}
1502+
1503+
testContainer= codersdk.WorkspaceAgentContainer{
1504+
ID:"test-container-id",
1505+
FriendlyName:"test-container",
1506+
Image:"test-image",
1507+
Running:true,
1508+
CreatedAt:time.Now(),
1509+
Labels:map[string]string{
1510+
agentcontainers.DevcontainerLocalFolderLabel:"/workspaces",
1511+
agentcontainers.DevcontainerConfigFileLabel:"/workspace/.devcontainer/devcontainer.json",
1512+
},
1513+
}
1514+
)
1515+
1516+
coderBin,err:=os.Executable()
1517+
require.NoError(t,err)
1518+
1519+
// Mock the `List` function to always return out test container.
1520+
mCCLI.EXPECT().List(gomock.Any()).Return(codersdk.WorkspaceAgentListContainersResponse{
1521+
Containers: []codersdk.WorkspaceAgentContainer{testContainer},
1522+
},nil).AnyTimes()
1523+
1524+
// Mock the steps used for injecting the coder agent.
1525+
gomock.InOrder(
1526+
mCCLI.EXPECT().DetectArchitecture(gomock.Any(),testContainer.ID).Return(runtime.GOARCH,nil),
1527+
mCCLI.EXPECT().ExecAs(gomock.Any(),testContainer.ID,"root","mkdir","-p","/.coder-agent").Return(nil,nil),
1528+
mCCLI.EXPECT().Copy(gomock.Any(),testContainer.ID,coderBin,"/.coder-agent/coder").Return(nil),
1529+
mCCLI.EXPECT().ExecAs(gomock.Any(),testContainer.ID,"root","chmod","0755","/.coder-agent","/.coder-agent/coder").Return(nil,nil),
1530+
)
1531+
1532+
mClock.Set(time.Now()).MustWait(ctx)
1533+
tickerTrap:=mClock.Trap().TickerFunc("updaterLoop")
1534+
1535+
api:=agentcontainers.NewAPI(logger,
1536+
agentcontainers.WithClock(mClock),
1537+
agentcontainers.WithContainerCLI(mCCLI),
1538+
agentcontainers.WithDevcontainerCLI(fDCCLI),
1539+
agentcontainers.WithSubAgentClient(fSAC),
1540+
agentcontainers.WithSubAgentURL("test-subagent-url"),
1541+
agentcontainers.WithWatcher(watcher.NewNoop()),
1542+
)
1543+
deferapi.Close()
1544+
1545+
// Close before api.Close() defer to avoid deadlock after test.
1546+
deferclose(fSAC.createErrC)
1547+
deferclose(fDCCLI.execErrC)
1548+
1549+
// Given: We allow agent creation and injection to succeed.
1550+
testutil.RequireSend(ctx,t,fSAC.createErrC,nil)
1551+
testutil.RequireSend(ctx,t,fDCCLI.execErrC,func(cmdstring,args...string)error {
1552+
assert.Equal(t,"pwd",cmd)
1553+
assert.Empty(t,args)
1554+
returnnil
1555+
})
1556+
1557+
// Wait until the ticker has been registered.
1558+
tickerTrap.MustWait(ctx).MustRelease(ctx)
1559+
tickerTrap.Close()
1560+
1561+
// Then: We expected it to succeed
1562+
require.Len(t,fSAC.created,1)
1563+
assert.Equal(t,testContainer.FriendlyName,fSAC.created[0].Name)
1564+
1565+
iftt.afterCreate!=nil {
1566+
tt.afterCreate(t,fSAC.created[0])
1567+
}
1568+
})
1569+
}
1570+
})
14281571
}
14291572

14301573
// mustFindDevcontainerByPath returns the devcontainer with the given workspace

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp