func loginRun()

in commands/auth/login/login.go [143:454]


func loginRun(opts *LoginOptions) error {
	c := opts.IO.Color()
	cfg, err := opts.Config()
	if err != nil {
		return err
	}

	if opts.Token != "" {
		if opts.Hostname == "" {
			return errors.New("empty hostname would leak `oauth_token`")
		}

		if opts.UseKeyring {
			return keyring.Set("glab:"+opts.Hostname, "", opts.Token)
		} else {
			err := cfg.Set(opts.Hostname, "token", opts.Token)
			if err != nil {
				return err
			}

			if token := config.GetFromEnv("token"); token != "" {
				fmt.Fprintf(opts.IO.StdErr, "%s One of %s environment variables is set. If you don't want to use it for glab, unset it.\n", c.Yellow("WARNING:"), strings.Join(config.EnvKeyEquivalence("token"), ", "))
			}
			if opts.ApiHost != "" {
				err = cfg.Set(opts.Hostname, "api_host", opts.ApiHost)
				if err != nil {
					return err
				}
			}

			if opts.ApiProtocol != "" {
				err = cfg.Set(opts.Hostname, "api_protocol", opts.ApiProtocol)
				if err != nil {
					return err
				}
			}

			if opts.GitProtocol != "" {
				err = cfg.Set(opts.Hostname, "git_protocol", opts.GitProtocol)
				if err != nil {
					return err
				}
			}

			return cfg.Write()
		}

	}

	if opts.JobToken != "" {
		if opts.Hostname == "" {
			return errors.New("empty hostname would leak `oauth_token`")
		}

		if opts.UseKeyring {
			return keyring.Set("glab:"+opts.Hostname, "", opts.JobToken)
		} else {
			err := cfg.Set(opts.Hostname, "job_token", opts.JobToken)
			if err != nil {
				return err
			}

			if opts.ApiHost != "" {
				err = cfg.Set(opts.Hostname, "api_host", opts.ApiHost)
				if err != nil {
					return err
				}
			}

			if opts.ApiProtocol != "" {
				err = cfg.Set(opts.Hostname, "api_protocol", opts.ApiProtocol)
				if err != nil {
					return err
				}
			}

			if opts.GitProtocol != "" {
				err = cfg.Set(opts.Hostname, "git_protocol", opts.GitProtocol)
				if err != nil {
					return err
				}
			}

			return cfg.Write()
		}
	}

	hostname := opts.Hostname
	apiHostname := opts.Hostname

	if opts.ApiHost != "" {
		apiHostname = opts.ApiHost
	}

	defaultHostname := glinstance.OverridableDefault()
	isSelfHosted := false

	if hostname == "" {
		var hostType int
		err := survey.AskOne(&survey.Select{
			Message: "What GitLab instance do you want to sign in to?",
			Options: []string{
				defaultHostname,
				"GitLab Self-Managed or GitLab Dedicated instance",
			},
		}, &hostType)
		if err != nil {
			return fmt.Errorf("could not prompt: %w", err)
		}

		isSelfHosted = hostType == 1

		hostname = defaultHostname
		apiHostname = hostname
		if isSelfHosted {
			err := survey.AskOne(&survey.Input{
				Message: "GitLab hostname:",
			}, &hostname, survey.WithValidator(hostnameValidator))
			if err != nil {
				return fmt.Errorf("could not prompt: %w", err)
			}
			err = survey.AskOne(&survey.Input{
				Message: "API hostname:",
				Help:    "For instances with a different hostname for the API endpoint.",
				Default: hostname,
			}, &apiHostname, survey.WithValidator(hostnameValidator))
			if err != nil {
				return fmt.Errorf("could not prompt: %w", err)
			}
		}
	} else {
		isSelfHosted = glinstance.IsSelfHosted(hostname)
	}

	fmt.Fprintf(opts.IO.StdErr, "- Signing into %s\n", hostname)

	if token := config.GetFromEnv("token"); token != "" {
		fmt.Fprintf(opts.IO.StdErr, "%s One of %s environment variables is set. If you don't want to use it for glab, unset it.\n", c.Yellow("WARNING:"), strings.Join(config.EnvKeyEquivalence("token"), ", "))
	}
	existingToken, _, _ := cfg.GetWithSource(hostname, "token", false)

	if existingToken != "" && opts.Interactive {
		apiClient, err := cmdutils.LabClientFunc(hostname, cfg, false)
		if err != nil {
			return err
		}

		user, err := api.CurrentUser(apiClient)
		if err == nil {
			username := user.Username
			var keepGoing bool
			err = survey.AskOne(&survey.Confirm{
				Message: fmt.Sprintf(
					"You're already logged into %s as %s. Do you want to re-authenticate?",
					hostname,
					username),
				Default: false,
			}, &keepGoing)
			if err != nil {
				return fmt.Errorf("could not prompt: %w", err)
			}

			if !keepGoing {
				return nil
			}
		}
	}

	var loginType string

	if opts.Interactive {
		err := survey.AskOne(&survey.Select{
			Message: "How would you like to sign in?",
			Options: []string{
				"Token",
				"Web",
			},
		}, &loginType)
		if err != nil {
			return fmt.Errorf("could not get sign-in type: %w", err)
		}
	}

	var token string
	if strings.EqualFold(loginType, "token") {
		token, err = showTokenPrompt(opts.IO, hostname)
		if err != nil {
			return err
		}
	} else {
		token, err = oauth2.StartFlow(cfg, opts.IO, hostname)
		if err != nil {
			return err
		}
	}

	if opts.UseKeyring {
		err = keyring.Set("glab:"+hostname, "", token)
		if err != nil {
			return err
		}
	} else {
		err = cfg.Set(hostname, "token", token)
		if err != nil {
			return err
		}
	}

	if hostname == "" {
		return errors.New("empty hostname would leak the token")
	}

	err = cfg.Set(hostname, "api_host", apiHostname)
	if err != nil {
		return err
	}

	gitProtocol := "https"
	apiProtocol := "https"

	glabExecutable := "glab"
	if exe, err := os.Executable(); err == nil {
		glabExecutable = exe
	}
	credentialFlow := &authutils.GitCredentialFlow{Executable: glabExecutable}

	if opts.Interactive {
		err = survey.AskOne(&survey.Select{
			Message: "Choose default Git protocol:",
			Options: []string{
				"SSH",
				"HTTPS",
				"HTTP",
			},
			Default: "HTTPS",
		}, &gitProtocol)
		if err != nil {
			return fmt.Errorf("could not prompt: %w", err)
		}

		gitProtocol = strings.ToLower(gitProtocol)
		if opts.Interactive && gitProtocol != "ssh" {
			if err := credentialFlow.Prompt(hostname, gitProtocol); err != nil {
				return err
			}
		}

		if isSelfHosted {
			err = survey.AskOne(&survey.Select{
				Message: "Choose host API protocol:",
				Options: []string{
					"HTTPS",
					"HTTP",
				},
				Default: "HTTPS",
			}, &apiProtocol)
			if err != nil {
				return fmt.Errorf("could not prompt: %w", err)
			}

			apiProtocol = strings.ToLower(apiProtocol)
		}

		fmt.Fprintf(opts.IO.StdErr, "- glab config set -h %s git_protocol %s\n", hostname, gitProtocol)
		err = cfg.Set(hostname, "git_protocol", gitProtocol)
		if err != nil {
			return err
		}

		fmt.Fprintf(opts.IO.StdErr, "%s Configured Git protocol.\n", c.GreenCheck())

		fmt.Fprintf(opts.IO.StdErr, "- glab config set -h %s api_protocol %s\n", hostname, apiProtocol)
		err = cfg.Set(hostname, "api_protocol", apiProtocol)
		if err != nil {
			return err
		}

		fmt.Fprintf(opts.IO.StdErr, "%s Configured API protocol.\n", c.GreenCheck())
	}
	apiClient, err := cmdutils.LabClientFunc(hostname, cfg, false)
	if err != nil {
		return err
	}

	user, err := api.CurrentUser(apiClient)
	if err != nil {
		return fmt.Errorf("error using API: %w", err)
	}
	username := user.Username

	err = cfg.Set(hostname, "user", username)
	if err != nil {
		return err
	}

	err = cfg.Write()
	if err != nil {
		return err
	}

	if credentialFlow.ShouldSetup() {
		err := credentialFlow.Setup(hostname, gitProtocol, username, token)
		if err != nil {
			return err
		}
	}

	fmt.Fprintf(opts.IO.StdErr, "%s Logged in as %s\n", c.GreenCheck(), c.Bold(username))
	fmt.Fprintf(opts.IO.StdErr, "%s Configuration saved to %s\n", c.GreenCheck(), config.ConfigFile())

	return nil
}