-
Notifications
You must be signed in to change notification settings - Fork 899
feat: add --branch option to clone or checkout different dotfiles branch #8331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
d67d482
5428aca
0556893
c2988f5
1dfffc4
011b2b3
e1d7dc3
d03730c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -1,6 +1,7 @@ | ||||
package cli | ||||
|
||||
import ( | ||||
"bytes" | ||||
"errors" | ||||
"fmt" | ||||
"io/fs" | ||||
|
@@ -18,6 +19,8 @@ import ( | |||
|
||||
func (r *RootCmd) dotfiles() *clibase.Cmd { | ||||
var symlinkDir string | ||||
var gitbranch string | ||||
|
||||
cmd := &clibase.Cmd{ | ||||
Use: "dotfiles <git_repo_url>", | ||||
Middleware: clibase.RequireNArgs(1), | ||||
|
@@ -102,6 +105,9 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { | |||
} | ||||
gitCmdDir = cfgDir | ||||
subcommands = []string{"clone", inv.Args[0], dotfilesRepoDir} | ||||
if gitbranch != "" { | ||||
subcommands = append(subcommands, "--branch", gitbranch) | ||||
} | ||||
promptText = fmt.Sprintf("Cloning %s into directory %s.\n\n Continue?", gitRepo, dotfilesDir) | ||||
} | ||||
|
||||
|
@@ -140,6 +146,23 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { | |||
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Failed to update repo, continuing...")) | ||||
} | ||||
|
||||
if dotfilesExists && gitbranch != "" { | ||||
// If the repo exists and the git-branch is specified, we need to check out the branch. We do this after | ||||
// git pull to make sure the branch was pulled down locally. If we do this before the pull, we could be | ||||
// trying to checkout a branch that does not yet exist locally and get a git error. | ||||
_, _ = fmt.Fprintf(inv.Stdout, "Dotfiles git branch %q specified\n", gitbranch) | ||||
err := ensureCorrectGitBranch(inv, ensureCorrectGitBranchParams{ | ||||
repoDir: dotfilesDir, | ||||
gitSSHCommand: gitsshCmd, | ||||
gitBranch: gitbranch, | ||||
}) | ||||
if err != nil { | ||||
// Do not block on this error, just log it and continue | ||||
_, _ = fmt.Fprintln(inv.Stdout, | ||||
cliui.DefaultStyles.Error.Render(fmt.Sprintf("Failed to use branch %q (%s), continuing...", err.Error(), gitbranch))) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to use a non-zero exit code if this happens? Otherwise the user might expect one thing but receive another due to the silent failure. (Not saying we can't continue from here, but set a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is an idea. I am not sure, I was copying the existing behavior. See this: Line 142 in e1d7dc3
If the If we decide to exit code 1, we should go back and also change the previous behavior. |
||||
} | ||||
} | ||||
|
||||
// save git repo url so we can detect changes next time | ||||
err = cfg.DotfilesURL().Write(gitRepo) | ||||
if err != nil { | ||||
|
@@ -246,11 +269,60 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { | |||
Description: "Specifies the directory for the dotfiles symlink destinations. If empty, will use $HOME.", | ||||
Value: clibase.StringOf(&symlinkDir), | ||||
}, | ||||
{ | ||||
Flag: "branch", | ||||
FlagShorthand: "b", | ||||
Description: "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.", | ||||
Value: clibase.StringOf(&gitbranch), | ||||
}, | ||||
cliui.SkipPromptOption(), | ||||
} | ||||
return cmd | ||||
} | ||||
|
||||
type ensureCorrectGitBranchParams struct { | ||||
repoDir string | ||||
gitSSHCommand string | ||||
gitBranch string | ||||
} | ||||
|
||||
func ensureCorrectGitBranch(baseInv *clibase.Invocation, params ensureCorrectGitBranchParams) error { | ||||
dotfileCmd := func(cmd string, args ...string) *exec.Cmd { | ||||
c := exec.CommandContext(baseInv.Context(), cmd, args...) | ||||
c.Dir = params.repoDir | ||||
c.Env = append(baseInv.Environ.ToOS(), fmt.Sprintf(`GIT_SSH_COMMAND=%s -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no`, params.gitSSHCommand)) | ||||
var out bytes.Buffer | ||||
Emyrk marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
c.Stdout = &out | ||||
c.Stderr = baseInv.Stderr | ||||
return c | ||||
} | ||||
c := dotfileCmd("git", "branch", "--show-current") | ||||
// Save the output | ||||
var out bytes.Buffer | ||||
c.Stdout = &out | ||||
err := c.Run() | ||||
if err != nil { | ||||
return xerrors.Errorf("getting current git branch: %w", err) | ||||
} | ||||
|
||||
if strings.TrimSpace(out.String()) != params.gitBranch { | ||||
// Checkout and pull the branch | ||||
c := dotfileCmd("git", "checkout", params.gitBranch) | ||||
Emyrk marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
err := c.Run() | ||||
if err != nil { | ||||
return xerrors.Errorf("checkout git branch %q: %w", params.gitBranch, err) | ||||
} | ||||
|
||||
c = dotfileCmd("git", "pull", "--ff-only") | ||||
err = c.Run() | ||||
if err != nil { | ||||
return xerrors.Errorf("pull git branch %q: %w", params.gitBranch, err) | ||||
} | ||||
} | ||||
return nil | ||||
} | ||||
|
||||
// dirExists checks if the path exists and is a directory. | ||||
func dirExists(name string) (bool, error) { | ||||
fi, err := os.Stat(name) | ||||
|
Uh oh!
There was an error while loading. Please reload this page.