diff --git a/cli/dotfiles.go b/cli/dotfiles.go index cf3b1391d5..f3d1551558 100644 --- a/cli/dotfiles.go +++ b/cli/dotfiles.go @@ -22,6 +22,7 @@ import ( func (r *RootCmd) dotfiles() *clibase.Cmd { var symlinkDir string var gitbranch string + var dotfilesRepoDir string cmd := &clibase.Cmd{ Use: "dotfiles ", @@ -35,11 +36,10 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { ), Handler: func(inv *clibase.Invocation) error { var ( - dotfilesRepoDir = "dotfiles" - gitRepo = inv.Args[0] - cfg = r.createConfig() - cfgDir = string(cfg) - dotfilesDir = filepath.Join(cfgDir, dotfilesRepoDir) + gitRepo = inv.Args[0] + cfg = r.createConfig() + cfgDir = string(cfg) + dotfilesDir = filepath.Join(cfgDir, dotfilesRepoDir) // This follows the same pattern outlined by others in the market: // https://github.com/coder/coder/pull/1696#issue-1245742312 installScriptSet = []string{ @@ -290,6 +290,13 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { "If empty, will default to cloning the default branch or using the existing branch in the cloned repo on disk.", Value: clibase.StringOf(&gitbranch), }, + { + Flag: "repo-dir", + Default: "dotfiles", + Env: "CODER_DOTFILES_REPO_DIR", + Description: "Specifies the directory for the dotfiles repository, relative to global config directory.", + Value: clibase.StringOf(&dotfilesRepoDir), + }, cliui.SkipPromptOption(), } return cmd diff --git a/cli/dotfiles_test.go b/cli/dotfiles_test.go index d5511c986a..6726f35b78 100644 --- a/cli/dotfiles_test.go +++ b/cli/dotfiles_test.go @@ -50,6 +50,68 @@ func TestDotfiles(t *testing.T) { require.NoError(t, err) require.Equal(t, string(b), "wow") }) + t.Run("SwitchRepoDir", func(t *testing.T) { + t.Parallel() + _, root := clitest.New(t) + testRepo := testGitRepo(t, root) + + // nolint:gosec + err := os.WriteFile(filepath.Join(testRepo, ".bashrc"), []byte("wow"), 0o750) + require.NoError(t, err) + + c := exec.Command("git", "add", ".bashrc") + c.Dir = testRepo + err = c.Run() + require.NoError(t, err) + + c = exec.Command("git", "commit", "-m", `"add .bashrc"`) + c.Dir = testRepo + out, err := c.CombinedOutput() + require.NoError(t, err, string(out)) + + inv, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "--repo-dir", "testrepo", "-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") + + stat, staterr := os.Stat(filepath.Join(string(root), "testrepo")) + require.NoError(t, staterr) + require.True(t, stat.IsDir()) + }) + t.Run("SwitchRepoDirRelative", func(t *testing.T) { + t.Parallel() + _, root := clitest.New(t) + testRepo := testGitRepo(t, root) + + // nolint:gosec + err := os.WriteFile(filepath.Join(testRepo, ".bashrc"), []byte("wow"), 0o750) + require.NoError(t, err) + + c := exec.Command("git", "add", ".bashrc") + c.Dir = testRepo + err = c.Run() + require.NoError(t, err) + + c = exec.Command("git", "commit", "-m", `"add .bashrc"`) + c.Dir = testRepo + out, err := c.CombinedOutput() + require.NoError(t, err, string(out)) + + inv, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "--repo-dir", "./relrepo", "-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") + + stat, staterr := os.Stat(filepath.Join(string(root), "relrepo")) + require.NoError(t, staterr) + require.True(t, stat.IsDir()) + }) t.Run("InstallScript", func(t *testing.T) { t.Parallel() if runtime.GOOS == "windows" { diff --git a/cli/testdata/coder_dotfiles_--help.golden b/cli/testdata/coder_dotfiles_--help.golden index a54e576b25..1499151212 100644 --- a/cli/testdata/coder_dotfiles_--help.golden +++ b/cli/testdata/coder_dotfiles_--help.golden @@ -15,6 +15,10 @@ OPTIONS: default branch or using the existing branch in the cloned repo on disk. + --repo-dir string, $CODER_DOTFILES_REPO_DIR (default: dotfiles) + Specifies the directory for the dotfiles repository, relative to + global config directory. + --symlink-dir string, $CODER_SYMLINK_DIR Specifies the directory for the dotfiles symlink destinations. If empty, will use $HOME. diff --git a/docs/cli/dotfiles.md b/docs/cli/dotfiles.md index 59446a8b84..2ed5ab1525 100644 --- a/docs/cli/dotfiles.md +++ b/docs/cli/dotfiles.md @@ -28,6 +28,16 @@ coder dotfiles [flags] Specifies which branch to clone. If empty, will default to cloning the default branch or using the existing branch in the cloned repo on disk. +### --repo-dir + +| | | +| ----------- | ------------------------------------- | +| Type | string | +| Environment | $CODER_DOTFILES_REPO_DIR | +| Default | dotfiles | + +Specifies the directory for the dotfiles repository, relative to global config directory. + ### --symlink-dir | | |