| 131 | } |
| 132 | |
| 133 | func runCopilot(opts *CopilotOptions) error { |
| 134 | if opts.Remove { |
| 135 | if err := removeCopilot(copilotInstallDir()); err != nil { |
| 136 | return err |
| 137 | } |
| 138 | |
| 139 | if opts.IO.IsStdoutTTY() { |
| 140 | fmt.Fprintln(opts.IO.ErrOut, "Copilot CLI removed successfully") |
| 141 | } |
| 142 | return nil |
| 143 | } |
| 144 | |
| 145 | copilotPath := findCopilotBinaryFunc() |
| 146 | foundInPath := copilotPath != "" |
| 147 | if !foundInPath { |
| 148 | if opts.IO.CanPrompt() { |
| 149 | confirmed, err := opts.Prompter.Confirm("GitHub Copilot CLI is not installed. Would you like to install it?", true) |
| 150 | if err != nil { |
| 151 | return err |
| 152 | } |
| 153 | if !confirmed { |
| 154 | fmt.Fprintf(opts.IO.ErrOut, "%s Copilot CLI was not installed", opts.IO.ColorScheme().WarningIcon()) |
| 155 | return cmdutil.SilentError |
| 156 | } |
| 157 | } else if !ci.IsCI() { |
| 158 | fmt.Fprintf(opts.IO.ErrOut, "%s Copilot CLI not installed", opts.IO.ColorScheme().WarningIcon()) |
| 159 | return cmdutil.SilentError |
| 160 | } |
| 161 | |
| 162 | httpClient, err := opts.HttpClient() |
| 163 | if err != nil { |
| 164 | return err |
| 165 | } |
| 166 | |
| 167 | copilotPath, err = downloadCopilot(httpClient, opts.IO, copilotInstallDir(), copilotBinaryPath()) |
| 168 | if err != nil { |
| 169 | return err |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | externalCmd := exec.Command(copilotPath, opts.CopilotArgs...) |
| 174 | externalCmd.Stdin = opts.IO.In |
| 175 | externalCmd.Stdout = opts.IO.Out |
| 176 | externalCmd.Stderr = opts.IO.ErrOut |
| 177 | externalCmd.Env = append(os.Environ(), "COPILOT_GH=true") |
| 178 | |
| 179 | if err := runExternalCmdFunc(externalCmd); err != nil { |
| 180 | if exitErr, ok := err.(*exec.ExitError); ok { |
| 181 | // We terminate with os.Exit here, preserving the exit code from Copilot CLI, |
| 182 | // and also preventing stdio writes by callers up the stack. |
| 183 | os.Exit(exitErr.ExitCode()) |
| 184 | } |
| 185 | if foundInPath { |
| 186 | // We found a `copilot` binary but exec failed, possibly due to |
| 187 | // unusual characters in the path (see https://github.com/cli/cli/issues/13106). |
| 188 | // Suggest running copilot directly as a workaround. |
| 189 | return fmt.Errorf("%w\nFailed to run '%s', try running `copilot` directly without `gh`.", err, copilotPath) |
| 190 | } |