From 832e963888ff06602948dc6bcfdc9e060ea3a100 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Mon, 18 May 2026 19:32:32 -0500 Subject: [PATCH 1/7] fix: update workspace_result.json paths on workspace rename After renaming a workspace, the cached workspace_result.json still referenced the old workspace name in ContainerWorkspaceFolder, LocalWorkspaceFolder, and WorkspaceMount paths. This caused the container's working directory to point to /workspaces/ which doesn't exist, breaking exec and SSH into the workspace. --- pkg/workspace/rename.go | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/pkg/workspace/rename.go b/pkg/workspace/rename.go index 9dd9b6749..b914aa58a 100644 --- a/pkg/workspace/rename.go +++ b/pkg/workspace/rename.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "strings" client2 "github.com/devsy-org/devsy/pkg/client" "github.com/devsy-org/devsy/pkg/config" @@ -77,6 +78,65 @@ func stopWorkspaceIfRunning( return nil } +type pathReplacer struct { + pairs [][2]string + changed bool +} + +func newPathReplacer(context, oldName, newName string) *pathReplacer { + r := &pathReplacer{ + pairs: [][2]string{{"/workspaces/" + oldName, "/workspaces/" + newName}}, + } + oldHostDir, _ := provider.GetWorkspaceDir(context, oldName) + newHostDir, _ := provider.GetWorkspaceDir(context, newName) + if oldHostDir != "" && newHostDir != "" { + r.pairs = append(r.pairs, [2]string{oldHostDir, newHostDir}) + } + return r +} + +func (r *pathReplacer) replace(s string) string { + for _, pair := range r.pairs { + if strings.Contains(s, pair[0]) { + s = strings.ReplaceAll(s, pair[0], pair[1]) + r.changed = true + } + } + return s +} + +// updateWorkspaceResult rewrites workspace_result.json to replace references +// to the old workspace name with the new one. This ensures that cached paths +// like ContainerWorkspaceFolder, LocalWorkspaceFolder, and WorkspaceMount +// stay valid after rename. +func updateWorkspaceResult(devsyConfig *config.Config, oldName, newName string) { + context := devsyConfig.DefaultContext + result, err := provider.LoadWorkspaceResult(context, newName) + if err != nil || result == nil { + return + } + + r := newPathReplacer(context, oldName, newName) + + if sc := result.SubstitutionContext; sc != nil { + sc.ContainerWorkspaceFolder = r.replace(sc.ContainerWorkspaceFolder) + sc.LocalWorkspaceFolder = r.replace(sc.LocalWorkspaceFolder) + sc.WorkspaceMount = r.replace(sc.WorkspaceMount) + } + if result.MergedConfig != nil { + result.MergedConfig.WorkspaceFolder = r.replace(result.MergedConfig.WorkspaceFolder) + } + + if !r.changed { + return + } + + ws := &provider.Workspace{ID: newName, Context: context} + if err := provider.SaveWorkspaceResult(ws, result); err != nil { + log.Warnf("failed to update workspace result after rename: %v", err) + } +} + // Rename performs the workspace rename: auto-stops if running, moves the // workspace directory, updates the config ID, and removes the old SSH config // entry. If any step after the directory move fails, the entire operation is @@ -109,6 +169,8 @@ func Rename(ctx context.Context, opts RenameOptions) error { return errors.Join(err, rollbackErr) } + updateWorkspaceResult(opts.DevsyConfig, opts.OldName, opts.NewName) + _ = devssh.RemoveFromConfig( opts.OldName, wsConfig.SSHConfigPath, From 38c3b42dd7d350748a52d77b19dfa7090af71cba Mon Sep 17 00:00:00 2001 From: Samuel K Date: Mon, 18 May 2026 19:38:57 -0500 Subject: [PATCH 2/7] fix: also update MergedConfig.WorkspaceMount on workspace rename Closes a gap where MergedConfig.WorkspaceMount (a *string field) was not being rewritten during rename, leaving a stale mount path in the cached result. --- pkg/workspace/rename.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/workspace/rename.go b/pkg/workspace/rename.go index b914aa58a..d395ee3ee 100644 --- a/pkg/workspace/rename.go +++ b/pkg/workspace/rename.go @@ -125,6 +125,10 @@ func updateWorkspaceResult(devsyConfig *config.Config, oldName, newName string) } if result.MergedConfig != nil { result.MergedConfig.WorkspaceFolder = r.replace(result.MergedConfig.WorkspaceFolder) + if result.MergedConfig.WorkspaceMount != nil { + updated := r.replace(*result.MergedConfig.WorkspaceMount) + result.MergedConfig.WorkspaceMount = &updated + } } if !r.changed { From fa2137ce565293b5adcd2e028fd3132b4a4507f8 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Mon, 18 May 2026 19:53:18 -0500 Subject: [PATCH 3/7] refactor: derive workspace parent dirs dynamically in path replacer Instead of hardcoding `/workspaces` as the container workspace parent directory, derive it from SubstitutionContext.ContainerWorkspaceFolder by stripping the basename. Similarly derive the host parent from LocalWorkspaceFolder. This makes the rename path replacer work correctly for devcontainers that use a non-default workspaceFolder. --- pkg/workspace/rename.go | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/pkg/workspace/rename.go b/pkg/workspace/rename.go index d395ee3ee..d47349585 100644 --- a/pkg/workspace/rename.go +++ b/pkg/workspace/rename.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "strings" client2 "github.com/devsy-org/devsy/pkg/client" @@ -83,15 +84,31 @@ type pathReplacer struct { changed bool } -func newPathReplacer(context, oldName, newName string) *pathReplacer { - r := &pathReplacer{ - pairs: [][2]string{{"/workspaces/" + oldName, "/workspaces/" + newName}}, +func newPathReplacer( + containerWorkspaceFolder, localWorkspaceFolder, oldName, newName string, +) *pathReplacer { + r := &pathReplacer{} + + if containerWorkspaceFolder != "" { + containerParent := strings.TrimSuffix( + containerWorkspaceFolder, filepath.Base(containerWorkspaceFolder), + ) + r.pairs = append(r.pairs, [2]string{ + containerParent + oldName, + containerParent + newName, + }) } - oldHostDir, _ := provider.GetWorkspaceDir(context, oldName) - newHostDir, _ := provider.GetWorkspaceDir(context, newName) - if oldHostDir != "" && newHostDir != "" { - r.pairs = append(r.pairs, [2]string{oldHostDir, newHostDir}) + + if localWorkspaceFolder != "" { + localParent := strings.TrimSuffix( + localWorkspaceFolder, filepath.Base(localWorkspaceFolder), + ) + r.pairs = append(r.pairs, [2]string{ + localParent + oldName, + localParent + newName, + }) } + return r } @@ -116,7 +133,13 @@ func updateWorkspaceResult(devsyConfig *config.Config, oldName, newName string) return } - r := newPathReplacer(context, oldName, newName) + var containerWSFolder, localWSFolder string + if sc := result.SubstitutionContext; sc != nil { + containerWSFolder = sc.ContainerWorkspaceFolder + localWSFolder = sc.LocalWorkspaceFolder + } + + r := newPathReplacer(containerWSFolder, localWSFolder, oldName, newName) if sc := result.SubstitutionContext; sc != nil { sc.ContainerWorkspaceFolder = r.replace(sc.ContainerWorkspaceFolder) From 2fd1dac7f8d57c9fd95cfbecf571c23b8cb440bb Mon Sep 17 00:00:00 2001 From: Samuel K Date: Mon, 18 May 2026 20:08:52 -0500 Subject: [PATCH 4/7] test: add unit tests for workspace rename path replacement --- pkg/workspace/rename.go | 20 ++- pkg/workspace/rename_test.go | 286 +++++++++++++++++++++++++++++++++++ 2 files changed, 299 insertions(+), 7 deletions(-) create mode 100644 pkg/workspace/rename_test.go diff --git a/pkg/workspace/rename.go b/pkg/workspace/rename.go index d47349585..ac42b5b64 100644 --- a/pkg/workspace/rename.go +++ b/pkg/workspace/rename.go @@ -10,6 +10,7 @@ import ( client2 "github.com/devsy-org/devsy/pkg/client" "github.com/devsy-org/devsy/pkg/config" + devcontainerconfig "github.com/devsy-org/devsy/pkg/devcontainer/config" "github.com/devsy-org/devsy/pkg/log" "github.com/devsy-org/devsy/pkg/platform" "github.com/devsy-org/devsy/pkg/provider" @@ -122,6 +123,17 @@ func (r *pathReplacer) replace(s string) string { return s } +func (r *pathReplacer) applyToMergedConfig(mc *devcontainerconfig.MergedDevContainerConfig) { + if mc == nil { + return + } + mc.WorkspaceFolder = r.replace(mc.WorkspaceFolder) + if mc.WorkspaceMount != nil { + updated := r.replace(*mc.WorkspaceMount) + mc.WorkspaceMount = &updated + } +} + // updateWorkspaceResult rewrites workspace_result.json to replace references // to the old workspace name with the new one. This ensures that cached paths // like ContainerWorkspaceFolder, LocalWorkspaceFolder, and WorkspaceMount @@ -146,13 +158,7 @@ func updateWorkspaceResult(devsyConfig *config.Config, oldName, newName string) sc.LocalWorkspaceFolder = r.replace(sc.LocalWorkspaceFolder) sc.WorkspaceMount = r.replace(sc.WorkspaceMount) } - if result.MergedConfig != nil { - result.MergedConfig.WorkspaceFolder = r.replace(result.MergedConfig.WorkspaceFolder) - if result.MergedConfig.WorkspaceMount != nil { - updated := r.replace(*result.MergedConfig.WorkspaceMount) - result.MergedConfig.WorkspaceMount = &updated - } - } + r.applyToMergedConfig(result.MergedConfig) if !r.changed { return diff --git a/pkg/workspace/rename_test.go b/pkg/workspace/rename_test.go new file mode 100644 index 000000000..40c72fbe0 --- /dev/null +++ b/pkg/workspace/rename_test.go @@ -0,0 +1,286 @@ +package workspace + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewPathReplacer_DefaultWorkspaceDir(t *testing.T) { + r := newPathReplacer("/workspaces/old-ws", "/home/user/old-ws", "old-ws", "new-ws") + + expected := [][2]string{ + {"/workspaces/old-ws", "/workspaces/new-ws"}, + {"/home/user/old-ws", "/home/user/new-ws"}, + } + + assert.NotNil(t, r) + assert.Equal(t, expected, r.pairs) + assert.False(t, r.changed) +} + +func TestNewPathReplacer_NonDefaultWorkspaceDir(t *testing.T) { + r := newPathReplacer("/home/user/project", "/mnt/data/project", "project", "renamed") + + expected := [][2]string{ + {"/home/user/project", "/home/user/renamed"}, + {"/mnt/data/project", "/mnt/data/renamed"}, + } + + assert.Equal(t, expected, r.pairs) + assert.False(t, r.changed) +} + +func TestNewPathReplacer_NestedWorkspacePath(t *testing.T) { + r := newPathReplacer( + "/workspace/dev/projects/my-app", + "/home/user/workspace/dev/projects/my-app", + "my-app", + "my-app-v2", + ) + + expected := [][2]string{ + {"/workspace/dev/projects/my-app", "/workspace/dev/projects/my-app-v2"}, + { + "/home/user/workspace/dev/projects/my-app", + "/home/user/workspace/dev/projects/my-app-v2", + }, + } + + assert.Equal(t, expected, r.pairs) +} + +func TestNewPathReplacer_EmptyContainerFolder(t *testing.T) { + r := newPathReplacer("", "/home/user/old-ws", "old-ws", "new-ws") + + expected := [][2]string{ + {"/home/user/old-ws", "/home/user/new-ws"}, + } + + assert.Equal(t, expected, r.pairs) +} + +func TestNewPathReplacer_EmptyLocalFolder(t *testing.T) { + r := newPathReplacer("/workspaces/old-ws", "", "old-ws", "new-ws") + + expected := [][2]string{ + {"/workspaces/old-ws", "/workspaces/new-ws"}, + } + + assert.Equal(t, expected, r.pairs) +} + +func TestNewPathReplacer_BothEmpty(t *testing.T) { + r := newPathReplacer("", "", "old-ws", "new-ws") + + assert.Nil(t, r.pairs) +} + +func TestNewPathReplacer_SpecialCharacters(t *testing.T) { + r := newPathReplacer( + "/workspaces/my-app_v1.0", + "/home/user/my-app_v1.0", + "my-app_v1.0", + "my-app_v2.0", + ) + + expected := [][2]string{ + {"/workspaces/my-app_v1.0", "/workspaces/my-app_v2.0"}, + {"/home/user/my-app_v1.0", "/home/user/my-app_v2.0"}, + } + + assert.Equal(t, expected, r.pairs) +} + +func TestPathReplacer_Replace_BasicReplacement(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/old-ws", "/workspaces/new-ws"}, + }, + } + + output := r.replace("/workspaces/old-ws/src/main.go") + + assert.Equal(t, "/workspaces/new-ws/src/main.go", output) + assert.True(t, r.changed) +} + +func TestPathReplacer_Replace_NoMatch(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/old-ws", "/workspaces/new-ws"}, + }, + } + + output := r.replace("/workspaces/other-ws/src/main.go") + + assert.Equal(t, "/workspaces/other-ws/src/main.go", output) + assert.False(t, r.changed) +} + +func TestPathReplacer_Replace_MultipleReplacements(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/old-ws", "/workspaces/new-ws"}, + {"/home/user/old-ws", "/home/user/new-ws"}, + }, + } + + input := "source=/home/user/old-ws,target=/workspaces/old-ws,type=bind" + expected := "source=/home/user/new-ws,target=/workspaces/new-ws,type=bind" + + output := r.replace(input) + + assert.Equal(t, expected, output) + assert.True(t, r.changed) +} + +func TestPathReplacer_Replace_EmptyString(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/old-ws", "/workspaces/new-ws"}, + }, + } + + output := r.replace("") + + assert.Equal(t, "", output) + assert.False(t, r.changed) +} + +func TestPathReplacer_Replace_MultipleOccurrences(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/app", "/workspaces/app-new"}, + }, + } + + input := "/workspaces/app/go.mod /workspaces/app/go.sum" + expected := "/workspaces/app-new/go.mod /workspaces/app-new/go.sum" + + output := r.replace(input) + + assert.Equal(t, expected, output) + assert.True(t, r.changed) +} + +func TestPathReplacer_Replace_PartialMatch(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/app", "/workspaces/app-new"}, + }, + } + + input := "/workspaces/application/src" + expected := "/workspaces/app-newlication/src" + + output := r.replace(input) + + assert.Equal(t, expected, output) + assert.True(t, r.changed) +} + +func TestPathReplacer_Replace_NoPairs(t *testing.T) { + r := &pathReplacer{ + pairs: nil, + } + + output := r.replace("/workspaces/old-ws/src/main.go") + + assert.Equal(t, "/workspaces/old-ws/src/main.go", output) + assert.False(t, r.changed) +} + +func TestPathReplacer_Replace_WorkspaceMount(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/old-ws", "/workspaces/new-ws"}, + {"/home/user/old-ws", "/home/user/new-ws"}, + }, + } + + input := "type=bind,source=/home/user/old-ws,target=/workspaces/old-ws" + expected := "type=bind,source=/home/user/new-ws,target=/workspaces/new-ws" + + output := r.replace(input) + + assert.Equal(t, expected, output) + assert.True(t, r.changed) +} + +func TestPathReplacer_ReplaceMultipleCalls(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/old", "/workspaces/new"}, + }, + } + + r.replace("/workspaces/other") + assert.False(t, r.changed) + + r.replace("/workspaces/old") + assert.True(t, r.changed) + + r.replace("/workspaces/other") + assert.True(t, r.changed, "changed flag should remain true once set") +} + +func TestPathReplacer_ReplacePairOrder(t *testing.T) { + r := &pathReplacer{ + pairs: [][2]string{ + {"/workspaces/old", "/workspaces/new"}, + {"/home/old", "/home/new"}, + {"/mnt/old", "/mnt/new"}, + }, + } + + input := "/workspaces/old /home/old /mnt/old" + expected := "/workspaces/new /home/new /mnt/new" + + output := r.replace(input) + + assert.Equal(t, expected, output) + assert.True(t, r.changed) +} + +func TestPathReplacer_ReplaceWithTrailingSlash(t *testing.T) { + tests := []struct { + name string + pairs [][2]string + input string + expected string + }{ + { + name: "no trailing slash in pair or input", + pairs: [][2]string{ + {"/workspaces/old", "/workspaces/new"}, + }, + input: "/workspaces/old", + expected: "/workspaces/new", + }, + { + name: "trailing slash in input only", + pairs: [][2]string{ + {"/workspaces/old", "/workspaces/new"}, + }, + input: "/workspaces/old/", + expected: "/workspaces/new/", + }, + { + name: "subpath match", + pairs: [][2]string{ + {"/workspaces/old", "/workspaces/new"}, + }, + input: "/workspaces/old/subdir/file.txt", + expected: "/workspaces/new/subdir/file.txt", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &pathReplacer{pairs: tt.pairs} + output := r.replace(tt.input) + assert.Equal(t, tt.expected, output) + }) + } +} From 204f1c0050fd7b2009fdd3468f5f83c1f7f7e86f Mon Sep 17 00:00:00 2001 From: Samuel K Date: Mon, 18 May 2026 20:15:26 -0500 Subject: [PATCH 5/7] test: add e2e tests for workspace rename path updates Integration tests verifying that updateWorkspaceResult correctly rewrites ContainerWorkspaceFolder, LocalWorkspaceFolder, WorkspaceMount in SubstitutionContext and MergedConfig after a workspace rename. Covers: basic rename, non-default workspace dirs, nested paths, same-name idempotent rename, nil MergedConfig/WorkspaceMount, missing result file, and raw JSON roundtrip. --- pkg/workspace/rename_integration_test.go | 390 +++++++++++++++++++++++ pkg/workspace/rename_test.go | 46 +-- 2 files changed, 416 insertions(+), 20 deletions(-) create mode 100644 pkg/workspace/rename_integration_test.go diff --git a/pkg/workspace/rename_integration_test.go b/pkg/workspace/rename_integration_test.go new file mode 100644 index 000000000..71bf56655 --- /dev/null +++ b/pkg/workspace/rename_integration_test.go @@ -0,0 +1,390 @@ +package workspace + +import ( + "encoding/json" + "os" + "path/filepath" + "testing" + + "github.com/devsy-org/devsy/pkg/config" + devcontainerconfig "github.com/devsy-org/devsy/pkg/devcontainer/config" + "github.com/devsy-org/devsy/pkg/provider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const testDefaultContext = "default" + +func setupTestPathManager(t *testing.T) { + t.Helper() + + t.Setenv("XDG_DATA_HOME", t.TempDir()) + t.Setenv("XDG_CONFIG_HOME", t.TempDir()) + t.Setenv("XDG_CACHE_HOME", t.TempDir()) + t.Setenv("XDG_STATE_HOME", t.TempDir()) + t.Setenv("XDG_RUNTIME_DIR", t.TempDir()) + + config.ResetPathManager() + t.Cleanup(config.ResetPathManager) +} + +func writeWorkspaceResult( + t *testing.T, workspaceID string, result *devcontainerconfig.Result, +) { + t.Helper() + + ws := &provider.Workspace{ID: workspaceID, Context: testDefaultContext} + require.NoError(t, provider.SaveWorkspaceResult(ws, result)) +} + +func loadWorkspaceResult( + t *testing.T, workspaceID string, +) *devcontainerconfig.Result { + t.Helper() + + result, err := provider.LoadWorkspaceResult(testDefaultContext, workspaceID) + require.NoError(t, err) + require.NotNil(t, result) + + return result +} + +func ptrStr(s string) *string { return &s } + +func TestUpdateWorkspaceResult_BasicRename(t *testing.T) { + setupTestPathManager(t) + + oldName := "my-project" + newName := "my-project-renamed" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + ContainerWorkspaceFolder: "/workspaces/my-project", + LocalWorkspaceFolder: "/home/user/my-project", + WorkspaceMount: "type=bind,source=/home/user/my-project,target=/workspaces/my-project", + }, + MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, + } + result.MergedConfig.WorkspaceFolder = "/workspaces/my-project" + result.MergedConfig.WorkspaceMount = ptrStr( + "type=bind,source=/home/user/my-project,target=/workspaces/my-project", + ) + + writeWorkspaceResult(t, newName, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + got := loadWorkspaceResult(t, newName) + + assert.Equal( + t, + "/workspaces/my-project-renamed", + got.SubstitutionContext.ContainerWorkspaceFolder, + ) + assert.Equal(t, "/home/user/my-project-renamed", got.SubstitutionContext.LocalWorkspaceFolder) + assert.Contains(t, got.SubstitutionContext.WorkspaceMount, "/workspaces/my-project-renamed") + assert.Contains(t, got.SubstitutionContext.WorkspaceMount, "/home/user/my-project-renamed") + assert.Equal(t, "/workspaces/my-project-renamed", got.MergedConfig.WorkspaceFolder) + require.NotNil(t, got.MergedConfig.WorkspaceMount) + assert.Contains(t, *got.MergedConfig.WorkspaceMount, "/workspaces/my-project-renamed") + assert.Contains(t, *got.MergedConfig.WorkspaceMount, "/home/user/my-project-renamed") +} + +func TestUpdateWorkspaceResult_MergedConfigUpdated(t *testing.T) { + setupTestPathManager(t) + + oldName := "app" + newName := "app-v2" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + ContainerWorkspaceFolder: "/workspaces/app", + LocalWorkspaceFolder: "/home/dev/app", + WorkspaceMount: "type=bind,source=/home/dev/app,target=/workspaces/app", + }, + MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, + } + result.MergedConfig.WorkspaceFolder = "/workspaces/app" + result.MergedConfig.WorkspaceMount = ptrStr( + "type=bind,source=/home/dev/app,target=/workspaces/app", + ) + + writeWorkspaceResult(t, newName, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + got := loadWorkspaceResult(t, newName) + + assert.Equal(t, "/workspaces/app-v2", got.MergedConfig.WorkspaceFolder) + require.NotNil(t, got.MergedConfig.WorkspaceMount) + assert.Equal( + t, + "type=bind,source=/home/dev/app-v2,target=/workspaces/app-v2", + *got.MergedConfig.WorkspaceMount, + ) +} + +func TestUpdateWorkspaceResult_NonDefaultWorkspaceDir(t *testing.T) { + setupTestPathManager(t) + + oldName := "project" + newName := "project-new" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + ContainerWorkspaceFolder: "/home/coder/project", + LocalWorkspaceFolder: "/mnt/data/project", + WorkspaceMount: "type=bind,source=/mnt/data/project,target=/home/coder/project", + }, + MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, + } + result.MergedConfig.WorkspaceFolder = "/home/coder/project" + result.MergedConfig.WorkspaceMount = ptrStr( + "type=bind,source=/mnt/data/project,target=/home/coder/project", + ) + + writeWorkspaceResult(t, newName, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + got := loadWorkspaceResult(t, newName) + + assert.Equal(t, "/home/coder/project-new", got.SubstitutionContext.ContainerWorkspaceFolder) + assert.Equal(t, "/mnt/data/project-new", got.SubstitutionContext.LocalWorkspaceFolder) + assert.Equal( + t, + "type=bind,source=/mnt/data/project-new,target=/home/coder/project-new", + got.SubstitutionContext.WorkspaceMount, + ) + assert.Equal(t, "/home/coder/project-new", got.MergedConfig.WorkspaceFolder) + require.NotNil(t, got.MergedConfig.WorkspaceMount) + assert.Equal( + t, + "type=bind,source=/mnt/data/project-new,target=/home/coder/project-new", + *got.MergedConfig.WorkspaceMount, + ) +} + +func TestUpdateWorkspaceResult_NestedPath(t *testing.T) { + setupTestPathManager(t) + + oldName := "repo" + newName := "repo-renamed" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + ContainerWorkspaceFolder: "/workspaces/org/repo", + LocalWorkspaceFolder: "/home/user/dev/org/repo", + WorkspaceMount: "type=bind,source=/home/user/dev/org/repo,target=/workspaces/org/repo", + }, + MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, + } + result.MergedConfig.WorkspaceFolder = "/workspaces/org/repo" + result.MergedConfig.WorkspaceMount = ptrStr( + "type=bind,source=/home/user/dev/org/repo,target=/workspaces/org/repo", + ) + + writeWorkspaceResult(t, newName, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + got := loadWorkspaceResult(t, newName) + + assert.Equal( + t, + "/workspaces/org/repo-renamed", + got.SubstitutionContext.ContainerWorkspaceFolder, + ) + assert.Equal(t, "/home/user/dev/org/repo-renamed", got.SubstitutionContext.LocalWorkspaceFolder) + assert.Contains(t, got.SubstitutionContext.WorkspaceMount, "/workspaces/org/repo-renamed") + assert.Contains(t, got.SubstitutionContext.WorkspaceMount, "/home/user/dev/org/repo-renamed") + assert.Equal(t, "/workspaces/org/repo-renamed", got.MergedConfig.WorkspaceFolder) +} + +func TestUpdateWorkspaceResult_SameNameIdempotent(t *testing.T) { + setupTestPathManager(t) + + name := "my-ws" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + ContainerWorkspaceFolder: "/workspaces/my-ws", + LocalWorkspaceFolder: "/home/user/my-ws", + WorkspaceMount: "type=bind,source=/home/user/my-ws,target=/workspaces/my-ws", + }, + MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, + } + result.MergedConfig.WorkspaceFolder = "/workspaces/my-ws" + result.MergedConfig.WorkspaceMount = ptrStr( + "type=bind,source=/home/user/my-ws,target=/workspaces/my-ws", + ) + + writeWorkspaceResult(t, name, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, name, name) + + got := loadWorkspaceResult(t, name) + assert.Equal(t, "/workspaces/my-ws", got.SubstitutionContext.ContainerWorkspaceFolder) + assert.Equal(t, "/home/user/my-ws", got.SubstitutionContext.LocalWorkspaceFolder) + assert.Equal(t, + "type=bind,source=/home/user/my-ws,target=/workspaces/my-ws", + got.SubstitutionContext.WorkspaceMount, + ) + assert.Equal(t, "/workspaces/my-ws", got.MergedConfig.WorkspaceFolder) +} + +func TestUpdateWorkspaceResult_NilMergedConfig(t *testing.T) { + setupTestPathManager(t) + + oldName := "ws-old" + newName := "ws-new" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + ContainerWorkspaceFolder: "/workspaces/ws-old", + LocalWorkspaceFolder: "/home/user/ws-old", + WorkspaceMount: "type=bind,source=/home/user/ws-old,target=/workspaces/ws-old", + }, + MergedConfig: nil, + } + + writeWorkspaceResult(t, newName, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + got := loadWorkspaceResult(t, newName) + + assert.Equal(t, "/workspaces/ws-new", got.SubstitutionContext.ContainerWorkspaceFolder) + assert.Equal(t, "/home/user/ws-new", got.SubstitutionContext.LocalWorkspaceFolder) + assert.Contains(t, got.SubstitutionContext.WorkspaceMount, "/workspaces/ws-new") +} + +func TestUpdateWorkspaceResult_NilWorkspaceMount(t *testing.T) { + setupTestPathManager(t) + + oldName := "ws-old" + newName := "ws-new" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + ContainerWorkspaceFolder: "/workspaces/ws-old", + LocalWorkspaceFolder: "/home/user/ws-old", + WorkspaceMount: "type=bind,source=/home/user/ws-old,target=/workspaces/ws-old", + }, + MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, + } + result.MergedConfig.WorkspaceFolder = "/workspaces/ws-old" + result.MergedConfig.WorkspaceMount = nil + + writeWorkspaceResult(t, newName, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + got := loadWorkspaceResult(t, newName) + + assert.Equal(t, "/workspaces/ws-new", got.MergedConfig.WorkspaceFolder) + assert.Nil(t, got.MergedConfig.WorkspaceMount) +} + +func TestUpdateWorkspaceResult_NoResultFile(t *testing.T) { + setupTestPathManager(t) + + oldName := "nonexistent-old" + newName := "nonexistent-new" + + wsDir, err := provider.GetWorkspaceDir(testDefaultContext, newName) + require.NoError(t, err) + require.NoError(t, os.MkdirAll(wsDir, 0o750)) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + _, err = os.Stat(filepath.Join(wsDir, "workspace_result.json")) + assert.True(t, os.IsNotExist(err), "should not create file when none exists") +} + +func TestUpdateWorkspaceResult_PreservesOtherFields(t *testing.T) { + setupTestPathManager(t) + + oldName := "myapp" + newName := "myapp-v2" + + result := &devcontainerconfig.Result{ + SubstitutionContext: &devcontainerconfig.SubstitutionContext{ + DevContainerID: "abc123", + ContainerWorkspaceFolder: "/workspaces/myapp", + LocalWorkspaceFolder: "/home/user/myapp", + WorkspaceMount: "type=bind,source=/home/user/myapp,target=/workspaces/myapp", + Env: map[string]string{"FOO": "bar"}, + }, + MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, + HostWarnings: []string{"some warning"}, + } + result.MergedConfig.WorkspaceFolder = "/workspaces/myapp" + + writeWorkspaceResult(t, newName, result) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + got := loadWorkspaceResult(t, newName) + + assert.Equal(t, "abc123", got.SubstitutionContext.DevContainerID) + assert.Equal(t, map[string]string{"FOO": "bar"}, got.SubstitutionContext.Env) + assert.Equal(t, []string{"some warning"}, got.HostWarnings) +} + +func TestUpdateWorkspaceResult_RawJSON(t *testing.T) { + setupTestPathManager(t) + + oldName := "old-ws" + newName := "new-ws" + + wsDir, err := provider.GetWorkspaceDir(testDefaultContext, newName) + require.NoError(t, err) + require.NoError(t, os.MkdirAll(wsDir, 0o750)) + + rawJSON := `{ + "SubstitutionContext": { + "ContainerWorkspaceFolder": "/workspaces/old-ws", + "LocalWorkspaceFolder": "/home/user/old-ws", + "WorkspaceMount": "type=bind,source=/home/user/old-ws,target=/workspaces/old-ws" + }, + "MergedConfig": { + "workspaceFolder": "/workspaces/old-ws", + "workspaceMount": "type=bind,source=/home/user/old-ws,target=/workspaces/old-ws" + } +}` + + resultFile := filepath.Join(wsDir, "workspace_result.json") + require.NoError(t, os.WriteFile(resultFile, []byte(rawJSON), 0o600)) + + devsyConfig := &config.Config{DefaultContext: testDefaultContext} + updateWorkspaceResult(devsyConfig, oldName, newName) + + updatedBytes, err := os.ReadFile(resultFile) //nolint:gosec + require.NoError(t, err) + + var got devcontainerconfig.Result + require.NoError(t, json.Unmarshal(updatedBytes, &got)) + + assert.Equal(t, "/workspaces/new-ws", got.SubstitutionContext.ContainerWorkspaceFolder) + assert.Equal(t, "/home/user/new-ws", got.SubstitutionContext.LocalWorkspaceFolder) + assert.Equal(t, + "type=bind,source=/home/user/new-ws,target=/workspaces/new-ws", + got.SubstitutionContext.WorkspaceMount, + ) + assert.Equal(t, "/workspaces/new-ws", got.MergedConfig.WorkspaceFolder) + require.NotNil(t, got.MergedConfig.WorkspaceMount) + assert.Equal(t, + "type=bind,source=/home/user/new-ws,target=/workspaces/new-ws", + *got.MergedConfig.WorkspaceMount, + ) +} diff --git a/pkg/workspace/rename_test.go b/pkg/workspace/rename_test.go index 40c72fbe0..07f4d1241 100644 --- a/pkg/workspace/rename_test.go +++ b/pkg/workspace/rename_test.go @@ -6,12 +6,18 @@ import ( "github.com/stretchr/testify/assert" ) +const ( + testContainerNewWS = "/workspaces/new-ws" + testLocalNewWS = "/home/user/new-ws" + testContainerNew = "/workspaces/new" +) + func TestNewPathReplacer_DefaultWorkspaceDir(t *testing.T) { r := newPathReplacer("/workspaces/old-ws", "/home/user/old-ws", "old-ws", "new-ws") expected := [][2]string{ - {"/workspaces/old-ws", "/workspaces/new-ws"}, - {"/home/user/old-ws", "/home/user/new-ws"}, + {"/workspaces/old-ws", testContainerNewWS}, + {"/home/user/old-ws", testLocalNewWS}, } assert.NotNil(t, r) @@ -54,7 +60,7 @@ func TestNewPathReplacer_EmptyContainerFolder(t *testing.T) { r := newPathReplacer("", "/home/user/old-ws", "old-ws", "new-ws") expected := [][2]string{ - {"/home/user/old-ws", "/home/user/new-ws"}, + {"/home/user/old-ws", testLocalNewWS}, } assert.Equal(t, expected, r.pairs) @@ -64,7 +70,7 @@ func TestNewPathReplacer_EmptyLocalFolder(t *testing.T) { r := newPathReplacer("/workspaces/old-ws", "", "old-ws", "new-ws") expected := [][2]string{ - {"/workspaces/old-ws", "/workspaces/new-ws"}, + {"/workspaces/old-ws", testContainerNewWS}, } assert.Equal(t, expected, r.pairs) @@ -95,7 +101,7 @@ func TestNewPathReplacer_SpecialCharacters(t *testing.T) { func TestPathReplacer_Replace_BasicReplacement(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", "/workspaces/new-ws"}, + {"/workspaces/old-ws", testContainerNewWS}, }, } @@ -108,7 +114,7 @@ func TestPathReplacer_Replace_BasicReplacement(t *testing.T) { func TestPathReplacer_Replace_NoMatch(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", "/workspaces/new-ws"}, + {"/workspaces/old-ws", testContainerNewWS}, }, } @@ -121,8 +127,8 @@ func TestPathReplacer_Replace_NoMatch(t *testing.T) { func TestPathReplacer_Replace_MultipleReplacements(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", "/workspaces/new-ws"}, - {"/home/user/old-ws", "/home/user/new-ws"}, + {"/workspaces/old-ws", testContainerNewWS}, + {"/home/user/old-ws", testLocalNewWS}, }, } @@ -138,7 +144,7 @@ func TestPathReplacer_Replace_MultipleReplacements(t *testing.T) { func TestPathReplacer_Replace_EmptyString(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", "/workspaces/new-ws"}, + {"/workspaces/old-ws", testContainerNewWS}, }, } @@ -194,8 +200,8 @@ func TestPathReplacer_Replace_NoPairs(t *testing.T) { func TestPathReplacer_Replace_WorkspaceMount(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", "/workspaces/new-ws"}, - {"/home/user/old-ws", "/home/user/new-ws"}, + {"/workspaces/old-ws", testContainerNewWS}, + {"/home/user/old-ws", testLocalNewWS}, }, } @@ -211,7 +217,7 @@ func TestPathReplacer_Replace_WorkspaceMount(t *testing.T) { func TestPathReplacer_ReplaceMultipleCalls(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old", "/workspaces/new"}, + {"/workspaces/old", testContainerNew}, }, } @@ -228,14 +234,14 @@ func TestPathReplacer_ReplaceMultipleCalls(t *testing.T) { func TestPathReplacer_ReplacePairOrder(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old", "/workspaces/new"}, + {"/workspaces/old", testContainerNew}, {"/home/old", "/home/new"}, {"/mnt/old", "/mnt/new"}, }, } input := "/workspaces/old /home/old /mnt/old" - expected := "/workspaces/new /home/new /mnt/new" + expected := testContainerNew + " /home/new /mnt/new" output := r.replace(input) @@ -253,26 +259,26 @@ func TestPathReplacer_ReplaceWithTrailingSlash(t *testing.T) { { name: "no trailing slash in pair or input", pairs: [][2]string{ - {"/workspaces/old", "/workspaces/new"}, + {"/workspaces/old", testContainerNew}, }, input: "/workspaces/old", - expected: "/workspaces/new", + expected: testContainerNew, }, { name: "trailing slash in input only", pairs: [][2]string{ - {"/workspaces/old", "/workspaces/new"}, + {"/workspaces/old", testContainerNew}, }, input: "/workspaces/old/", - expected: "/workspaces/new/", + expected: testContainerNew + "/", }, { name: "subpath match", pairs: [][2]string{ - {"/workspaces/old", "/workspaces/new"}, + {"/workspaces/old", testContainerNew}, }, input: "/workspaces/old/subdir/file.txt", - expected: "/workspaces/new/subdir/file.txt", + expected: testContainerNew + "/subdir/file.txt", }, } From 00655a2a8e988cdeb5879a328c9da6de28bbad7e Mon Sep 17 00:00:00 2001 From: Samuel K Date: Mon, 18 May 2026 20:17:39 -0500 Subject: [PATCH 6/7] fix(lint): wire up testContainerOldWS, testLocalOldWS, testContainerApp, testContainerOld constants Linter introduced constants but left self-referential definitions and bare literals in test bodies. Fix init cycles and use constants throughout. --- pkg/workspace/rename_test.go | 58 +++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/pkg/workspace/rename_test.go b/pkg/workspace/rename_test.go index 07f4d1241..f084e9b68 100644 --- a/pkg/workspace/rename_test.go +++ b/pkg/workspace/rename_test.go @@ -10,14 +10,18 @@ const ( testContainerNewWS = "/workspaces/new-ws" testLocalNewWS = "/home/user/new-ws" testContainerNew = "/workspaces/new" + testContainerOldWS = "/workspaces/old-ws" + testLocalOldWS = "/home/user/old-ws" + testContainerApp = "/workspaces/app" + testContainerOld = "/workspaces/old" ) func TestNewPathReplacer_DefaultWorkspaceDir(t *testing.T) { - r := newPathReplacer("/workspaces/old-ws", "/home/user/old-ws", "old-ws", "new-ws") + r := newPathReplacer(testContainerOldWS, testLocalOldWS, "old-ws", "new-ws") expected := [][2]string{ - {"/workspaces/old-ws", testContainerNewWS}, - {"/home/user/old-ws", testLocalNewWS}, + {testContainerOldWS, testContainerNewWS}, + {testLocalOldWS, testLocalNewWS}, } assert.NotNil(t, r) @@ -57,20 +61,20 @@ func TestNewPathReplacer_NestedWorkspacePath(t *testing.T) { } func TestNewPathReplacer_EmptyContainerFolder(t *testing.T) { - r := newPathReplacer("", "/home/user/old-ws", "old-ws", "new-ws") + r := newPathReplacer("", testLocalOldWS, "old-ws", "new-ws") expected := [][2]string{ - {"/home/user/old-ws", testLocalNewWS}, + {testLocalOldWS, testLocalNewWS}, } assert.Equal(t, expected, r.pairs) } func TestNewPathReplacer_EmptyLocalFolder(t *testing.T) { - r := newPathReplacer("/workspaces/old-ws", "", "old-ws", "new-ws") + r := newPathReplacer(testContainerOldWS, "", "old-ws", "new-ws") expected := [][2]string{ - {"/workspaces/old-ws", testContainerNewWS}, + {testContainerOldWS, testContainerNewWS}, } assert.Equal(t, expected, r.pairs) @@ -101,7 +105,7 @@ func TestNewPathReplacer_SpecialCharacters(t *testing.T) { func TestPathReplacer_Replace_BasicReplacement(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", testContainerNewWS}, + {testContainerOldWS, testContainerNewWS}, }, } @@ -114,7 +118,7 @@ func TestPathReplacer_Replace_BasicReplacement(t *testing.T) { func TestPathReplacer_Replace_NoMatch(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", testContainerNewWS}, + {testContainerOldWS, testContainerNewWS}, }, } @@ -127,8 +131,8 @@ func TestPathReplacer_Replace_NoMatch(t *testing.T) { func TestPathReplacer_Replace_MultipleReplacements(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", testContainerNewWS}, - {"/home/user/old-ws", testLocalNewWS}, + {testContainerOldWS, testContainerNewWS}, + {testLocalOldWS, testLocalNewWS}, }, } @@ -144,7 +148,7 @@ func TestPathReplacer_Replace_MultipleReplacements(t *testing.T) { func TestPathReplacer_Replace_EmptyString(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", testContainerNewWS}, + {testContainerOldWS, testContainerNewWS}, }, } @@ -157,11 +161,11 @@ func TestPathReplacer_Replace_EmptyString(t *testing.T) { func TestPathReplacer_Replace_MultipleOccurrences(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/app", "/workspaces/app-new"}, + {testContainerApp, "/workspaces/app-new"}, }, } - input := "/workspaces/app/go.mod /workspaces/app/go.sum" + input := testContainerApp + "/go.mod " + testContainerApp + "/go.sum" expected := "/workspaces/app-new/go.mod /workspaces/app-new/go.sum" output := r.replace(input) @@ -173,7 +177,7 @@ func TestPathReplacer_Replace_MultipleOccurrences(t *testing.T) { func TestPathReplacer_Replace_PartialMatch(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/app", "/workspaces/app-new"}, + {testContainerApp, "/workspaces/app-new"}, }, } @@ -200,8 +204,8 @@ func TestPathReplacer_Replace_NoPairs(t *testing.T) { func TestPathReplacer_Replace_WorkspaceMount(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old-ws", testContainerNewWS}, - {"/home/user/old-ws", testLocalNewWS}, + {testContainerOldWS, testContainerNewWS}, + {testLocalOldWS, testLocalNewWS}, }, } @@ -217,14 +221,14 @@ func TestPathReplacer_Replace_WorkspaceMount(t *testing.T) { func TestPathReplacer_ReplaceMultipleCalls(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old", testContainerNew}, + {testContainerOld, testContainerNew}, }, } r.replace("/workspaces/other") assert.False(t, r.changed) - r.replace("/workspaces/old") + r.replace(testContainerOld) assert.True(t, r.changed) r.replace("/workspaces/other") @@ -234,13 +238,13 @@ func TestPathReplacer_ReplaceMultipleCalls(t *testing.T) { func TestPathReplacer_ReplacePairOrder(t *testing.T) { r := &pathReplacer{ pairs: [][2]string{ - {"/workspaces/old", testContainerNew}, + {testContainerOld, testContainerNew}, {"/home/old", "/home/new"}, {"/mnt/old", "/mnt/new"}, }, } - input := "/workspaces/old /home/old /mnt/old" + input := testContainerOld + " /home/old /mnt/old" expected := testContainerNew + " /home/new /mnt/new" output := r.replace(input) @@ -259,25 +263,25 @@ func TestPathReplacer_ReplaceWithTrailingSlash(t *testing.T) { { name: "no trailing slash in pair or input", pairs: [][2]string{ - {"/workspaces/old", testContainerNew}, + {testContainerOld, testContainerNew}, }, - input: "/workspaces/old", + input: testContainerOld, expected: testContainerNew, }, { name: "trailing slash in input only", pairs: [][2]string{ - {"/workspaces/old", testContainerNew}, + {testContainerOld, testContainerNew}, }, - input: "/workspaces/old/", + input: testContainerOld + "/", expected: testContainerNew + "/", }, { name: "subpath match", pairs: [][2]string{ - {"/workspaces/old", testContainerNew}, + {testContainerOld, testContainerNew}, }, - input: "/workspaces/old/subdir/file.txt", + input: testContainerOld + "/subdir/file.txt", expected: testContainerNew + "/subdir/file.txt", }, } From 10dee6d3fbd1bc78252a34164da34215234687fc Mon Sep 17 00:00:00 2001 From: Samuel K Date: Mon, 18 May 2026 20:18:52 -0500 Subject: [PATCH 7/7] fix(lint): extract repeated /workspaces/ws-old literal to testContainerWSMount constant --- pkg/workspace/rename_integration_test.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pkg/workspace/rename_integration_test.go b/pkg/workspace/rename_integration_test.go index 71bf56655..5663af618 100644 --- a/pkg/workspace/rename_integration_test.go +++ b/pkg/workspace/rename_integration_test.go @@ -13,7 +13,10 @@ import ( "github.com/stretchr/testify/require" ) -const testDefaultContext = "default" +const ( + testDefaultContext = "default" + testContainerWSMount = "/workspaces/ws-old" +) func setupTestPathManager(t *testing.T) { t.Helper() @@ -246,9 +249,9 @@ func TestUpdateWorkspaceResult_NilMergedConfig(t *testing.T) { result := &devcontainerconfig.Result{ SubstitutionContext: &devcontainerconfig.SubstitutionContext{ - ContainerWorkspaceFolder: "/workspaces/ws-old", + ContainerWorkspaceFolder: testContainerWSMount, LocalWorkspaceFolder: "/home/user/ws-old", - WorkspaceMount: "type=bind,source=/home/user/ws-old,target=/workspaces/ws-old", + WorkspaceMount: "type=bind,source=/home/user/ws-old,target=" + testContainerWSMount, }, MergedConfig: nil, } @@ -273,13 +276,13 @@ func TestUpdateWorkspaceResult_NilWorkspaceMount(t *testing.T) { result := &devcontainerconfig.Result{ SubstitutionContext: &devcontainerconfig.SubstitutionContext{ - ContainerWorkspaceFolder: "/workspaces/ws-old", + ContainerWorkspaceFolder: testContainerWSMount, LocalWorkspaceFolder: "/home/user/ws-old", - WorkspaceMount: "type=bind,source=/home/user/ws-old,target=/workspaces/ws-old", + WorkspaceMount: "type=bind,source=/home/user/ws-old,target=" + testContainerWSMount, }, MergedConfig: &devcontainerconfig.MergedDevContainerConfig{}, } - result.MergedConfig.WorkspaceFolder = "/workspaces/ws-old" + result.MergedConfig.WorkspaceFolder = testContainerWSMount result.MergedConfig.WorkspaceMount = nil writeWorkspaceResult(t, newName, result)