diff --git a/command/alias_test.go b/command/alias_test.go index 753e94055..ca1832c16 100644 --- a/command/alias_test.go +++ b/command/alias_test.go @@ -195,7 +195,7 @@ aliases: t.Fatalf("unexpected error: %s", err) } - expected := []string{"sh", "-c", "gh issue list | grep cool"} + expected := []string{"/usr/bin/sh", "-c", "gh issue list | grep cool"} assert.Equal(t, expected, expanded) } @@ -218,7 +218,7 @@ aliases: t.Fatalf("unexpected error: %s", err) } - expected := []string{"sh", "-c", "gh issue list --label=$1 | grep", "--", "bug", "foo"} + expected := []string{"/usr/bin/sh", "-c", "gh issue list --label=$1 | grep", "--", "bug", "foo"} assert.Equal(t, expected, expanded) } diff --git a/command/root.go b/command/root.go index 71de36589..2b3aa6a4d 100644 --- a/command/root.go +++ b/command/root.go @@ -382,6 +382,32 @@ func ExecuteShellAlias(args []string) error { return nil } +func findSh() (string, error) { + shPath, err := exec.LookPath("sh") + if err == nil { + return shPath, nil + } + + if runtime.GOOS == "windows" { + winNotFoundErr := errors.New("unable to locate sh to execute the shell alias with. The sh.exe interpreter is typically distributed with Git for Windows.") + // We can try and find a sh executable in a Git for Windows install + gitPath, err := exec.LookPath("git") + if err != nil { + return "", winNotFoundErr + } + + shPath = filepath.Join(filepath.Dir(gitPath), "..", "bin", "sh.exe") + _, err = os.Stat(shPath) + if err != nil { + return "", winNotFoundErr + } + + return shPath, nil + } + + return "", errors.New("unable to locate sh to execute shell alias with") +} + // ExpandAlias processes argv to see if it should be rewritten according to a user's aliases. The // second return value indicates whether the alias should be executed in a new shell process instead // of running gh itself. @@ -409,22 +435,14 @@ func ExpandAlias(args []string) (expanded []string, isShell bool, err error) { if ok { if strings.HasPrefix(expansion, "!") { isShell = true - expanded = []string{"sh", "-c", expansion[1:]} - if runtime.GOOS == "windows" { - // Need to use absolute path for sh on windows - shPath, lookErr := exec.LookPath("sh") - if lookErr != nil { - gitPath, lookErr := exec.LookPath("git") - if lookErr != nil { - // TODO this error could be better probably - err = fmt.Errorf("unable to find sh. you will not be able to use shell aliases on this platform.") - return - } - shPath = filepath.Join(filepath.Dir(gitPath), "..", "bin", "sh.exe") - } - expanded[0] = shPath + shPath, shErr := findSh() + if shErr != nil { + err = shErr + return } + expanded = []string{shPath, "-c", expansion[1:]} + if len(args[2:]) > 0 { expanded = append(expanded, "--") expanded = append(expanded, args[2:]...)