| 166 | } |
| 167 | |
| 168 | func loginRun(opts *LoginOptions) error { |
| 169 | cfg, err := opts.Config() |
| 170 | if err != nil { |
| 171 | return err |
| 172 | } |
| 173 | authCfg := cfg.Authentication() |
| 174 | |
| 175 | hostname := opts.Hostname |
| 176 | if opts.Interactive && hostname == "" { |
| 177 | var err error |
| 178 | hostname, err = promptForHostname(opts) |
| 179 | if err != nil { |
| 180 | return err |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | // The go-gh Config object currently does not support case-insensitive lookups for host names, |
| 185 | // so normalize the host name case here before performing any lookups with it or persisting it. |
| 186 | // https://github.com/cli/go-gh/pull/105 |
| 187 | hostname = strings.ToLower(hostname) |
| 188 | |
| 189 | if src, writeable := shared.AuthTokenWriteable(authCfg, hostname); !writeable { |
| 190 | fmt.Fprintf(opts.IO.ErrOut, "The value of the %s environment variable is being used for authentication.\n", src) |
| 191 | fmt.Fprint(opts.IO.ErrOut, "To have GitHub CLI store credentials instead, first clear the value from the environment.\n") |
| 192 | return cmdutil.SilentError |
| 193 | } |
| 194 | |
| 195 | plainHTTPClient, err := opts.PlainHttpClient() |
| 196 | if err != nil { |
| 197 | return err |
| 198 | } |
| 199 | |
| 200 | httpClient, err := opts.HttpClient() |
| 201 | if err != nil { |
| 202 | return err |
| 203 | } |
| 204 | |
| 205 | if opts.Token != "" { |
| 206 | if err := shared.HasMinimumScopes(httpClient, hostname, opts.Token); err != nil { |
| 207 | return fmt.Errorf("error validating token: %w", err) |
| 208 | } |
| 209 | username, err := shared.GetCurrentLogin(httpClient, hostname, opts.Token) |
| 210 | if err != nil { |
| 211 | return fmt.Errorf("error retrieving current user: %w", err) |
| 212 | } |
| 213 | |
| 214 | // Adding a user key ensures that a nonempty host section gets written to the config file. |
| 215 | _, loginErr := authCfg.Login(hostname, username, opts.Token, opts.GitProtocol, !opts.InsecureStorage) |
| 216 | return loginErr |
| 217 | } |
| 218 | |
| 219 | return shared.Login(&shared.LoginOptions{ |
| 220 | IO: opts.IO, |
| 221 | Config: authCfg, |
| 222 | HTTPClient: httpClient, |
| 223 | PlainHTTPClient: plainHTTPClient, |
| 224 | Hostname: hostname, |
| 225 | Interactive: opts.Interactive, |