diff --git a/cli/dotfiles.go b/cli/dotfiles.go index c0473dae336a1..6185ebae97948 100644 --- a/cli/dotfiles.go +++ b/cli/dotfiles.go @@ -225,6 +225,10 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { } } + // attempt to delete the file before creating a new symlink. This overwrites any existing symlinks + // which are typically leftover from a previous call to coder dotfiles. We do this best effort and + // ignore errors because the symlink may or may not exist. Any regular files are backed up above. + _ = os.Remove(to) err = os.Symlink(from, to) if err != nil { return xerrors.Errorf("symlinking %s to %s: %w", from, to, err) diff --git a/cli/dotfiles_test.go b/cli/dotfiles_test.go index e579010912306..eb051726dc07f 100644 --- a/cli/dotfiles_test.go +++ b/cli/dotfiles_test.go @@ -116,6 +116,17 @@ func TestDotfiles(t *testing.T) { b, err = os.ReadFile(filepath.Join(string(root), ".bashrc.bak")) require.NoError(t, err) require.Equal(t, string(b), "backup") + + // check for idempotency + inv, _ = clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo) + err = inv.Run() + require.NoError(t, err) + b, err = os.ReadFile(filepath.Join(string(root), ".bashrc")) + require.NoError(t, err) + require.Equal(t, string(b), "wow") + b, err = os.ReadFile(filepath.Join(string(root), ".bashrc.bak")) + require.NoError(t, err) + require.Equal(t, string(b), "backup") }) }