support auth login --web

This commit is contained in:
vilmibm 2020-09-10 20:58:06 -05:00 committed by vilmibm
parent 5a8df475b9
commit 2345f49ccb
2 changed files with 113 additions and 52 deletions

View file

@ -24,8 +24,11 @@ type LoginOptions struct {
IO *iostreams.IOStreams
Config func() (config.Config, error)
Interactive bool
Hostname string
Token string
Web bool
}
func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Command {
@ -51,6 +54,9 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
$ gh auth login
# => do an interactive setup
$ gh auth login --web
# => open a browser to authenticate and do a non-interactive setup
$ gh auth login --with-token < mytoken.txt
# => read token from mytoken.txt and authenticate against github.com
@ -58,6 +64,14 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
# => read token from mytoken.txt and authenticate against a GitHub Enterprise Server instance
`),
RunE: func(cmd *cobra.Command, args []string) error {
if !opts.IO.CanPrompt() && !(tokenStdin || opts.Web) {
return &cmdutil.FlagError{Err: errors.New("--web or --with-token required when not running interactively")}
}
if tokenStdin && opts.Web {
return &cmdutil.FlagError{Err: errors.New("specify only one of --web or --with-token")}
}
if tokenStdin {
defer opts.IO.In.Close()
token, err := ioutil.ReadAll(opts.IO.In)
@ -67,15 +81,8 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
opts.Token = strings.TrimSpace(string(token))
}
if opts.Token != "" {
// Assume non-interactive if a token is specified
if opts.Hostname == "" {
opts.Hostname = ghinstance.Default()
}
} else {
if !opts.IO.CanPrompt() {
return &cmdutil.FlagError{Err: errors.New("--with-token required when not running interactively")}
}
if opts.IO.CanPrompt() && opts.Token == "" && !opts.Web {
opts.Interactive = true
}
if cmd.Flags().Changed("hostname") {
@ -84,6 +91,12 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
}
}
if !opts.Interactive {
if opts.Hostname == "" {
opts.Hostname = ghinstance.Default()
}
}
if runF != nil {
return runF(opts)
}
@ -94,6 +107,7 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
cmd.Flags().StringVarP(&opts.Hostname, "hostname", "h", "", "The hostname of the GitHub instance to authenticate with")
cmd.Flags().BoolVar(&tokenStdin, "with-token", false, "Read token from standard input")
cmd.Flags().BoolVarP(&opts.Web, "web", "w", false, "Open a browser to authenticate")
return cmd
}
@ -168,24 +182,26 @@ func loginRun(opts *LoginOptions) error {
return err
}
username, err := api.CurrentLoginName(apiClient, hostname)
if err != nil {
return fmt.Errorf("error using api: %w", err)
}
var keepGoing bool
err = prompt.SurveyAskOne(&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 opts.Interactive {
username, err := api.CurrentLoginName(apiClient, hostname)
if err != nil {
return fmt.Errorf("error using api: %w", err)
}
var keepGoing bool
err = prompt.SurveyAskOne(&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
if !keepGoing {
return nil
}
}
}
}
@ -195,15 +211,19 @@ func loginRun(opts *LoginOptions) error {
}
var authMode int
err = prompt.SurveyAskOne(&survey.Select{
Message: "How would you like to authenticate?",
Options: []string{
"Login with a web browser",
"Paste an authentication token",
},
}, &authMode)
if err != nil {
return fmt.Errorf("could not prompt: %w", err)
if opts.Web {
authMode = 0
} else {
err = prompt.SurveyAskOne(&survey.Select{
Message: "How would you like to authenticate?",
Options: []string{
"Login with a web browser",
"Paste an authentication token",
},
}, &authMode)
if err != nil {
return fmt.Errorf("could not prompt: %w", err)
}
}
if authMode == 0 {
@ -239,19 +259,21 @@ func loginRun(opts *LoginOptions) error {
}
}
var gitProtocol string
err = prompt.SurveyAskOne(&survey.Select{
Message: "Choose default git protocol",
Options: []string{
"HTTPS",
"SSH",
},
}, &gitProtocol)
if err != nil {
return fmt.Errorf("could not prompt: %w", err)
}
gitProtocol := "https"
if opts.Interactive {
err = prompt.SurveyAskOne(&survey.Select{
Message: "Choose default git protocol",
Options: []string{
"HTTPS",
"SSH",
},
}, &gitProtocol)
if err != nil {
return fmt.Errorf("could not prompt: %w", err)
}
gitProtocol = strings.ToLower(gitProtocol)
gitProtocol = strings.ToLower(gitProtocol)
}
fmt.Fprintf(opts.IO.ErrOut, "- gh config set -h %s git_protocol %s\n", hostname, gitProtocol)
err = cfg.Set(hostname, "git_protocol", gitProtocol)

View file

@ -81,8 +81,9 @@ func Test_NewCmdLogin(t *testing.T) {
stdinTTY: true,
cli: "--hostname barry.burton",
wants: LoginOptions{
Hostname: "barry.burton",
Token: "",
Hostname: "barry.burton",
Token: "",
Interactive: true,
},
},
{
@ -90,10 +91,33 @@ func Test_NewCmdLogin(t *testing.T) {
stdinTTY: true,
cli: "",
wants: LoginOptions{
Hostname: "",
Token: "",
Hostname: "",
Token: "",
Interactive: true,
},
},
{
name: "tty web",
stdinTTY: true,
cli: "--web",
wants: LoginOptions{
Hostname: "github.com",
Web: true,
},
},
{
name: "nontty web",
cli: "--web",
wants: LoginOptions{
Hostname: "github.com",
Web: true,
},
},
{
name: "web and with-token",
cli: "--web --with-token",
wantsErr: true,
},
}
for _, tt := range tests {
@ -134,6 +158,8 @@ func Test_NewCmdLogin(t *testing.T) {
assert.Equal(t, tt.wants.Token, gotOpts.Token)
assert.Equal(t, tt.wants.Hostname, gotOpts.Hostname)
assert.Equal(t, tt.wants.Web, gotOpts.Web)
assert.Equal(t, tt.wants.Interactive, gotOpts.Interactive)
})
}
}
@ -262,6 +288,9 @@ func Test_loginRun_Survey(t *testing.T) {
}{
{
name: "already authenticated",
opts: &LoginOptions{
Interactive: true,
},
cfg: func(cfg config.Config) {
_ = cfg.Set("github.com", "oauth_token", "ghi789")
},
@ -280,7 +309,8 @@ func Test_loginRun_Survey(t *testing.T) {
{
name: "hostname set",
opts: &LoginOptions{
Hostname: "rebecca.chambers",
Hostname: "rebecca.chambers",
Interactive: true,
},
wantHosts: "rebecca.chambers:\n oauth_token: def456\n git_protocol: https\n user: jillv\n",
askStubs: func(as *prompt.AskStubber) {
@ -298,6 +328,9 @@ func Test_loginRun_Survey(t *testing.T) {
{
name: "choose enterprise",
wantHosts: "brad.vickers:\n oauth_token: def456\n git_protocol: https\n user: jillv\n",
opts: &LoginOptions{
Interactive: true,
},
askStubs: func(as *prompt.AskStubber) {
as.StubOne(1) // host type enterprise
as.StubOne("brad.vickers") // hostname
@ -315,6 +348,9 @@ func Test_loginRun_Survey(t *testing.T) {
{
name: "choose github.com",
wantHosts: "github.com:\n oauth_token: def456\n git_protocol: https\n user: jillv\n",
opts: &LoginOptions{
Interactive: true,
},
askStubs: func(as *prompt.AskStubber) {
as.StubOne(0) // host type github.com
as.StubOne(1) // auth mode: token
@ -325,6 +361,9 @@ func Test_loginRun_Survey(t *testing.T) {
{
name: "sets git_protocol",
wantHosts: "github.com:\n oauth_token: def456\n git_protocol: ssh\n user: jillv\n",
opts: &LoginOptions{
Interactive: true,
},
askStubs: func(as *prompt.AskStubber) {
as.StubOne(0) // host type github.com
as.StubOne(1) // auth mode: token