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

Commit8796ba3

Browse files
committed
feat(agent/agentcontainers): add Exec method to devcontainers CLI
This change adds Exec to the devcontainer CLI.Updatescoder/internal#621
1 parentea0125d commit8796ba3

File tree

4 files changed

+314
-62
lines changed

4 files changed

+314
-62
lines changed

‎agent/agentcontainers/acmock/acmock.go

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

‎agent/agentcontainers/api_test.go

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,39 @@ func (f *fakeContainerCLI) ExecAs(ctx context.Context, name, user string, args .
5858
// fakeDevcontainerCLI implements the agentcontainers.DevcontainerCLI
5959
// interface for testing.
6060
typefakeDevcontainerCLIstruct {
61-
idstring
62-
errerror
63-
continueUpchanstruct{}
61+
upIDstring
62+
upErrerror
63+
upErrCchanerror// If set, send to return err, close to return upErr.
64+
execErrerror
65+
execErrCchanerror// If set, send to return err, close to return execErr.
6466
}
6567

66-
func (f*fakeDevcontainerCLI)Up(ctx context.Context,_,_string,_...agentcontainers.DevcontainerCLIUpOptions) (string,error) {
67-
iff.continueUp!=nil {
68+
func (f*fakeDevcontainerCLI)Up(ctx context.Context,_,_string,_...agentcontainers.DevcontainerCLIOptions) (string,error) {
69+
iff.upErrC!=nil {
6870
select {
6971
case<-ctx.Done():
70-
return"",xerrors.New("test timeout")
71-
case<-f.continueUp:
72+
return"",ctx.Err()
73+
caseerr,ok:=<-f.upErrC:
74+
ifok {
75+
returnf.upID,err
76+
}
7277
}
7378
}
74-
returnf.id,f.err
79+
returnf.upID,f.upErr
80+
}
81+
82+
func (f*fakeDevcontainerCLI)Exec(ctx context.Context,_,_string,_string,_ []string,_...agentcontainers.DevcontainerCLIOptions)error {
83+
iff.execErrC!=nil {
84+
select {
85+
case<-ctx.Done():
86+
returnctx.Err()
87+
caseerr,ok:=<-f.execErrC:
88+
ifok {
89+
returnerr
90+
}
91+
}
92+
}
93+
returnf.execErr
7594
}
7695

7796
// fakeWatcher implements the watcher.Watcher interface for testing.
@@ -398,7 +417,7 @@ func TestAPI(t *testing.T) {
398417
},
399418
},
400419
devcontainerCLI:&fakeDevcontainerCLI{
401-
err:xerrors.New("devcontainer CLI error"),
420+
upErr:xerrors.New("devcontainer CLI error"),
402421
},
403422
wantStatus: []int{http.StatusAccepted,http.StatusConflict},
404423
wantBody: []string{"Devcontainer recreation initiated","Devcontainer recreation already in progress"},
@@ -432,7 +451,7 @@ func TestAPI(t *testing.T) {
432451
nowRecreateErrorTrap:=mClock.Trap().Now("recreate","errorTimes")
433452
nowRecreateSuccessTrap:=mClock.Trap().Now("recreate","successTimes")
434453

435-
tt.devcontainerCLI.continueUp=make(chanstruct{})
454+
tt.devcontainerCLI.upErrC=make(chanerror)
436455

437456
// Setup router with the handler under test.
438457
r:=chi.NewRouter()
@@ -470,7 +489,7 @@ func TestAPI(t *testing.T) {
470489
// because we must check what state the devcontainer ends up in
471490
// after the recreation process is initiated and finished.
472491
iftt.wantStatus[0]!=http.StatusAccepted {
473-
close(tt.devcontainerCLI.continueUp)
492+
close(tt.devcontainerCLI.upErrC)
474493
nowRecreateSuccessTrap.Close()
475494
nowRecreateErrorTrap.Close()
476495
return
@@ -497,10 +516,10 @@ func TestAPI(t *testing.T) {
497516
assert.Equal(t,codersdk.WorkspaceAgentDevcontainerStatusStarting,resp.Devcontainers[0].Container.DevcontainerStatus,"container dc status is not starting")
498517

499518
// Allow the devcontainer CLI to continue the up process.
500-
close(tt.devcontainerCLI.continueUp)
519+
close(tt.devcontainerCLI.upErrC)
501520

502521
// Ensure the devcontainer ends up in error state if the up call fails.
503-
iftt.devcontainerCLI.err!=nil {
522+
iftt.devcontainerCLI.upErr!=nil {
504523
nowRecreateSuccessTrap.Close()
505524
// The timestamp for the error will be stored, which gives
506525
// us a good anchor point to know when to do our request.

‎agent/agentcontainers/devcontainercli.go

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,67 @@ import (
1616

1717
// DevcontainerCLI is an interface for the devcontainer CLI.
1818
typeDevcontainerCLIinterface {
19-
Up(ctx context.Context,workspaceFolder,configPathstring,opts...DevcontainerCLIUpOptions) (idstring,errerror)
19+
Up(ctx context.Context,workspaceFolder,configPathstring,opts...DevcontainerCLIOptions) (idstring,errerror)
20+
Exec(ctx context.Context,workspaceFolder,configPathstring,cmdstring,cmdArgs []string,opts...DevcontainerCLIOptions)error
2021
}
2122

22-
// DevcontainerCLIUpOptions are options for the devcontainer CLI up
23-
// command.
24-
typeDevcontainerCLIUpOptionsfunc(*devcontainerCLIUpConfig)
23+
// DevcontainerCLIOptions are options for the devcontainer CLI commands.
24+
typeDevcontainerCLIOptionsfunc(*devcontainerCLIUpConfig)
2525

2626
// WithRemoveExistingContainer is an option to remove the existing
27-
// container.
28-
funcWithRemoveExistingContainer()DevcontainerCLIUpOptions {
27+
// container. Can only be used with the Up command.
28+
funcWithRemoveExistingContainer()DevcontainerCLIOptions {
2929
returnfunc(o*devcontainerCLIUpConfig) {
30-
o.removeExistingContainer=true
30+
ifo.command!="up" {
31+
panic("developer error: WithRemoveExistingContainer can only be used with the Up command")
32+
}
33+
o.args=append(o.args,"--remove-existing-container")
3134
}
3235
}
3336

34-
// WithOutput sets stdout and stderr writers for Up command logs.
35-
funcWithOutput(stdout,stderr io.Writer)DevcontainerCLIUpOptions {
37+
// WithOutput setsadditionalstdout and stderr writers for logs.
38+
funcWithOutput(stdout,stderr io.Writer)DevcontainerCLIOptions {
3639
returnfunc(o*devcontainerCLIUpConfig) {
3740
o.stdout=stdout
3841
o.stderr=stderr
3942
}
4043
}
4144

45+
// WithContainerID sets the container ID to target a specific container.
46+
// Can only be used with the Exec command.
47+
funcWithContainerID(idstring)DevcontainerCLIOptions {
48+
returnfunc(o*devcontainerCLIUpConfig) {
49+
ifo.command!="exec" {
50+
panic("developer error: WithContainerID can only be used with the Exec command")
51+
}
52+
o.args=append(o.args,"--container-id",id)
53+
}
54+
}
55+
56+
// WithRemoteEnv sets environment variables for the Exec command.
57+
// Can only be used with the Exec command.
58+
funcWithRemoteEnv(env...string)DevcontainerCLIOptions {
59+
returnfunc(o*devcontainerCLIUpConfig) {
60+
ifo.command!="exec" {
61+
panic("developer error: WithRemoteEnv can only be used with the Exec command")
62+
}
63+
for_,e:=rangeenv {
64+
o.args=append(o.args,"--remote-env",e)
65+
}
66+
}
67+
}
68+
4269
typedevcontainerCLIUpConfigstruct {
70+
commandstring// The devcontainer CLI command to run, e.g. "up", "exec".
4371
removeExistingContainerbool
72+
args []string// Additional arguments for the command.
4473
stdout io.Writer
4574
stderr io.Writer
4675
}
4776

48-
funcapplyDevcontainerCLIUpOptions(opts []DevcontainerCLIUpOptions)devcontainerCLIUpConfig {
77+
funcapplyDevcontainerCLIOptions(commandstring,opts []DevcontainerCLIOptions)devcontainerCLIUpConfig {
4978
conf:=devcontainerCLIUpConfig{
79+
command:command,
5080
removeExistingContainer:false,
5181
}
5282
for_,opt:=rangeopts {
@@ -71,8 +101,8 @@ func NewDevcontainerCLI(logger slog.Logger, execer agentexec.Execer) Devcontaine
71101
}
72102
}
73103

74-
func (d*devcontainerCLI)Up(ctx context.Context,workspaceFolder,configPathstring,opts...DevcontainerCLIUpOptions) (string,error) {
75-
conf:=applyDevcontainerCLIUpOptions(opts)
104+
func (d*devcontainerCLI)Up(ctx context.Context,workspaceFolder,configPathstring,opts...DevcontainerCLIOptions) (string,error) {
105+
conf:=applyDevcontainerCLIOptions("up",opts)
76106
logger:=d.logger.With(slog.F("workspace_folder",workspaceFolder),slog.F("config_path",configPath),slog.F("recreate",conf.removeExistingContainer))
77107

78108
args:= []string{
@@ -83,9 +113,7 @@ func (d *devcontainerCLI) Up(ctx context.Context, workspaceFolder, configPath st
83113
ifconfigPath!="" {
84114
args=append(args,"--config",configPath)
85115
}
86-
ifconf.removeExistingContainer {
87-
args=append(args,"--remove-existing-container")
88-
}
116+
args=append(args,conf.args...)
89117
cmd:=d.execer.CommandContext(ctx,"devcontainer",args...)
90118

91119
// Capture stdout for parsing and stream logs for both default and provided writers.
@@ -117,6 +145,40 @@ func (d *devcontainerCLI) Up(ctx context.Context, workspaceFolder, configPath st
117145
returnresult.ContainerID,nil
118146
}
119147

148+
func (d*devcontainerCLI)Exec(ctx context.Context,workspaceFolder,configPathstring,cmdstring,cmdArgs []string,opts...DevcontainerCLIOptions)error {
149+
conf:=applyDevcontainerCLIOptions("exec",opts)
150+
logger:=d.logger.With(slog.F("workspace_folder",workspaceFolder),slog.F("config_path",configPath))
151+
152+
args:= []string{"exec"}
153+
ifworkspaceFolder!="" {
154+
args=append(args,"--workspace-folder",workspaceFolder)
155+
}
156+
ifconfigPath!="" {
157+
args=append(args,"--config",configPath)
158+
}
159+
args=append(args,conf.args...)
160+
args=append(args,cmd)
161+
args=append(args,cmdArgs...)
162+
c:=d.execer.CommandContext(ctx,"devcontainer",args...)
163+
164+
stdoutWriters:= []io.Writer{&devcontainerCLILogWriter{ctx:ctx,logger:logger.With(slog.F("stdout",true))}}
165+
ifconf.stdout!=nil {
166+
stdoutWriters=append(stdoutWriters,conf.stdout)
167+
}
168+
c.Stdout=io.MultiWriter(stdoutWriters...)
169+
stderrWriters:= []io.Writer{&devcontainerCLILogWriter{ctx:ctx,logger:logger.With(slog.F("stderr",true))}}
170+
ifconf.stderr!=nil {
171+
stderrWriters=append(stderrWriters,conf.stderr)
172+
}
173+
c.Stderr=io.MultiWriter(stderrWriters...)
174+
175+
iferr:=c.Run();err!=nil {
176+
returnxerrors.Errorf("devcontainer exec failed: %w",err)
177+
}
178+
179+
returnnil
180+
}
181+
120182
// parseDevcontainerCLILastLine parses the last line of the devcontainer CLI output
121183
// which is a JSON object.
122184
funcparseDevcontainerCLILastLine(ctx context.Context,logger slog.Logger,p []byte) (resultdevcontainerCLIResult,errerror) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp