diff --git a/cmd/internal/agentworkspace/up.go b/cmd/internal/agentworkspace/up.go index 204cbb0f6..de041dee0 100644 --- a/cmd/internal/agentworkspace/up.go +++ b/cmd/internal/agentworkspace/up.go @@ -506,12 +506,14 @@ func (w *workspaceInitializer) prepareWorkspaceContent(ctx context.Context) erro }) } -// waitForDocker waits for the Docker installation to complete. -// Note: This function modifies workspaceInfo.Agent.Docker.Path if Docker was installed. +// waitForDocker waits for Docker discovery or installation to complete. +// It replaces an unset path or the provider default with the resolved path while +// preserving an explicitly configured custom Docker path. func (w *workspaceInitializer) waitForDocker(resultChan <-chan dockerInstallResult) error { result := <-resultChan - if result.path != "" && w.workspaceInfo.Agent.Docker.Path == "" { + dockerPath := w.workspaceInfo.Agent.Docker.Path + if result.path != "" && (dockerPath == "" || dockerPath == "docker") { w.workspaceInfo.Agent.Docker.Path = result.path log.Debugf("set docker path to %s", result.path) } diff --git a/cmd/internal/agentworkspace/up_test.go b/cmd/internal/agentworkspace/up_test.go new file mode 100644 index 000000000..0b1f7de9e --- /dev/null +++ b/cmd/internal/agentworkspace/up_test.go @@ -0,0 +1,56 @@ +package agentworkspace + +import ( + "errors" + "testing" + + "github.com/devsy-org/devsy/pkg/provider" +) + +func TestWaitForDockerPropagatesResolvedPath(t *testing.T) { + const resolvedPath = "/Users/dev/.rd/bin/docker" + + for _, configuredPath := range []string{"", "docker"} { + t.Run(configuredPath, func(t *testing.T) { + workspaceInfo := &provider.AgentWorkspaceInfo{} + workspaceInfo.Agent.Docker.Path = configuredPath + initializer := &workspaceInitializer{workspaceInfo: workspaceInfo} + resultChan := make(chan dockerInstallResult, 1) + resultChan <- dockerInstallResult{path: resolvedPath} + + if err := initializer.waitForDocker(resultChan); err != nil { + t.Fatalf("waitForDocker() error = %v", err) + } + if got := workspaceInfo.Agent.Docker.Path; got != resolvedPath { + t.Fatalf("Docker.Path = %q, want %q", got, resolvedPath) + } + }) + } +} + +func TestWaitForDockerPreservesExplicitPath(t *testing.T) { + const customPath = "/opt/custom/bin/docker" + workspaceInfo := &provider.AgentWorkspaceInfo{} + workspaceInfo.Agent.Docker.Path = customPath + initializer := &workspaceInitializer{workspaceInfo: workspaceInfo} + resultChan := make(chan dockerInstallResult, 1) + resultChan <- dockerInstallResult{path: "/Users/dev/.rd/bin/docker"} + + if err := initializer.waitForDocker(resultChan); err != nil { + t.Fatalf("waitForDocker() error = %v", err) + } + if got := workspaceInfo.Agent.Docker.Path; got != customPath { + t.Fatalf("Docker.Path = %q, want explicit path %q", got, customPath) + } +} + +func TestWaitForDockerReturnsDiscoveryError(t *testing.T) { + discoveryErr := errors.New("docker not found") + initializer := &workspaceInitializer{workspaceInfo: &provider.AgentWorkspaceInfo{}} + resultChan := make(chan dockerInstallResult, 1) + resultChan <- dockerInstallResult{err: discoveryErr} + + if err := initializer.waitForDocker(resultChan); !errors.Is(err, discoveryErr) { + t.Fatalf("waitForDocker() error = %v, want wrapped %v", err, discoveryErr) + } +}