Merge pull request #13393 from cli/babakks/improve-gh-copilot-error
fix(copilot): hint to run copilot directly when exec fails
This commit is contained in:
commit
fe996d33ac
2 changed files with 45 additions and 3 deletions
|
|
@ -142,8 +142,9 @@ func runCopilot(opts *CopilotOptions) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
copilotPath := findCopilotBinary()
|
||||
if copilotPath == "" {
|
||||
copilotPath := findCopilotBinaryFunc()
|
||||
foundInPath := copilotPath != ""
|
||||
if !foundInPath {
|
||||
if opts.IO.CanPrompt() {
|
||||
confirmed, err := opts.Prompter.Confirm("GitHub Copilot CLI is not installed. Would you like to install it?", true)
|
||||
if err != nil {
|
||||
|
|
@ -175,12 +176,18 @@ func runCopilot(opts *CopilotOptions) error {
|
|||
externalCmd.Stderr = opts.IO.ErrOut
|
||||
externalCmd.Env = append(os.Environ(), "COPILOT_GH=true")
|
||||
|
||||
if err := externalCmd.Run(); err != nil {
|
||||
if err := runExternalCmdFunc(externalCmd); err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
// We terminate with os.Exit here, preserving the exit code from Copilot CLI,
|
||||
// and also preventing stdio writes by callers up the stack.
|
||||
os.Exit(exitErr.ExitCode())
|
||||
}
|
||||
if foundInPath {
|
||||
// We found a `copilot` binary but exec failed, possibly due to
|
||||
// unusual characters in the path (see https://github.com/cli/cli/issues/13106).
|
||||
// Suggest running copilot directly as a workaround.
|
||||
return fmt.Errorf("%w\nFailed to run '%s', try running `copilot` directly without `gh`.", err, copilotPath)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
@ -200,6 +207,14 @@ func copilotBinaryPath() string {
|
|||
return filepath.Join(copilotInstallDir(), binaryName)
|
||||
}
|
||||
|
||||
var runExternalCmdFunc = runExternalCmd
|
||||
|
||||
func runExternalCmd(cmd *exec.Cmd) error {
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
var findCopilotBinaryFunc = findCopilotBinary
|
||||
|
||||
// findCopilotBinary returns the path to the Copilot CLI binary, if installed,
|
||||
// with the following order of precedence:
|
||||
// 1. `copilot` in the PATH
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
|
@ -589,6 +590,32 @@ func TestDownloadCopilot(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestRunCopilot_execFailureHint(t *testing.T) {
|
||||
ios, _, _, _ := iostreams.Test()
|
||||
opts := &CopilotOptions{
|
||||
IO: ios,
|
||||
CopilotArgs: []string{},
|
||||
}
|
||||
|
||||
origFind := findCopilotBinaryFunc
|
||||
findCopilotBinaryFunc = func() string {
|
||||
return "/usr/bin/copilot"
|
||||
}
|
||||
t.Cleanup(func() { findCopilotBinaryFunc = origFind })
|
||||
|
||||
execErr := fmt.Errorf("exec failed: something went wrong")
|
||||
origRun := runExternalCmdFunc
|
||||
runExternalCmdFunc = func(_ *exec.Cmd) error {
|
||||
return execErr
|
||||
}
|
||||
t.Cleanup(func() { runExternalCmdFunc = origRun })
|
||||
|
||||
err := runCopilot(opts)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, execErr)
|
||||
require.Contains(t, err.Error(), "try running `copilot` directly without `gh`.")
|
||||
}
|
||||
|
||||
func TestCopilotCommandIsSampledAt100(t *testing.T) {
|
||||
spy := &telemetry.CommandRecorderSpy{}
|
||||
factory := &cmdutil.Factory{}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue