Skip to content

Commit 82c6830

Browse files
author
Nate Smith
authored
Merge pull request cli#1548 from cli/auth-check
new auth flow UX
2 parents b9292f5 + 451ece1 commit 82c6830

File tree

11 files changed

+139
-18
lines changed

11 files changed

+139
-18
lines changed

cmd/gh/main.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"path"
1111
"strings"
1212

13+
"github.com/cli/cli/api"
1314
"github.com/cli/cli/command"
1415
"github.com/cli/cli/internal/config"
1516
"github.com/cli/cli/internal/ghinstance"
@@ -91,10 +92,41 @@ func main() {
9192
}
9293
}
9394

95+
authCheckEnabled := cmdutil.IsAuthCheckEnabled(cmd)
96+
97+
// TODO support other names
98+
ghtoken := os.Getenv("GITHUB_TOKEN")
99+
if ghtoken != "" {
100+
authCheckEnabled = false
101+
}
102+
103+
if authCheckEnabled {
104+
hasAuth := false
105+
106+
cfg, err := cmdFactory.Config()
107+
if err == nil {
108+
hasAuth = cmdutil.CheckAuth(cfg)
109+
}
110+
111+
if !hasAuth {
112+
fmt.Fprintln(stderr, utils.Bold("Welcome to GitHub CLI!"))
113+
fmt.Fprintln(stderr)
114+
fmt.Fprintln(stderr, "To authenticate, please run `gh auth login`.")
115+
fmt.Fprintln(stderr, "You can also set the GITHUB_TOKEN environment variable, if preferred.")
116+
os.Exit(4)
117+
}
118+
}
119+
94120
rootCmd.SetArgs(expandedArgs)
95121

96122
if cmd, err := rootCmd.ExecuteC(); err != nil {
97123
printError(stderr, err, cmd, hasDebug)
124+
125+
var httpErr api.HTTPError
126+
if errors.As(err, &httpErr) && httpErr.StatusCode == 401 {
127+
fmt.Println("hint: try authenticating with `gh auth login`")
128+
}
129+
98130
os.Exit(1)
99131
}
100132
if root.HasFailed() {

pkg/cmd/alias/alias.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ func NewCmdAlias(f *cmdutil.Factory) *cobra.Command {
2020
`),
2121
}
2222

23+
cmdutil.DisableAuthCheck(cmd)
24+
2325
cmd.AddCommand(deleteCmd.NewCmdDelete(f, nil))
2426
cmd.AddCommand(listCmd.NewCmdList(f, nil))
2527
cmd.AddCommand(setCmd.NewCmdSet(f, nil))

pkg/cmd/auth/auth.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ func NewCmdAuth(f *cmdutil.Factory) *cobra.Command {
1616
Long: `Manage gh's authentication state.`,
1717
}
1818

19+
cmdutil.DisableAuthCheck(cmd)
20+
1921
cmd.AddCommand(authLoginCmd.NewCmdLogin(f, nil))
2022
cmd.AddCommand(authLogoutCmd.NewCmdLogout(f, nil))
2123
cmd.AddCommand(authStatusCmd.NewCmdStatus(f, nil))

pkg/cmd/auth/login/login.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
5454
# => read token from mytoken.txt and authenticate against github.com
5555
5656
$ gh auth login --hostname enterprise.internal --with-token < mytoken.txt
57-
# => read token from mytoken.txt and authenticate against a GitHub Enterprise instance
57+
# => read token from mytoken.txt and authenticate against a GitHub Enterprise Server instance
5858
`),
5959
RunE: func(cmd *cobra.Command, args []string) error {
6060
isTTY := opts.IO.IsStdinTTY()
@@ -142,7 +142,7 @@ func loginRun(opts *LoginOptions) error {
142142
Message: "What account do you want to log into?",
143143
Options: []string{
144144
"GitHub.com",
145-
"GitHub Enterprise",
145+
"GitHub Enterprise Server",
146146
},
147147
}, &hostType)
148148

pkg/cmd/config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ func NewCmdConfig(f *cmdutil.Factory) *cobra.Command {
2121
`),
2222
}
2323

24+
cmdutil.DisableAuthCheck(cmd)
25+
2426
cmd.AddCommand(NewCmdConfigGet(f))
2527
cmd.AddCommand(NewCmdConfigSet(f))
2628

pkg/cmd/factory/http.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package factory
22

33
import (
4-
"errors"
54
"fmt"
65
"net/http"
76
"os"
@@ -30,20 +29,9 @@ func httpClient(io *iostreams.IOStreams, cfg config.Config, appVersion string, s
3029

3130
hostname := ghinstance.NormalizeHostname(req.URL.Hostname())
3231
token, err := cfg.Get(hostname, "oauth_token")
33-
if token == "" {
34-
var notFound *config.NotFoundError
35-
// TODO: check if stdout is TTY too
36-
if errors.As(err, &notFound) && io.IsStdinTTY() {
37-
// interactive OAuth flow
38-
token, err = config.AuthFlowWithConfig(cfg, hostname, "Notice: authentication required", nil)
39-
}
40-
if err != nil {
41-
return "", err
42-
}
43-
if token == "" {
44-
// TODO: instruct user how to manually authenticate
45-
return "", fmt.Errorf("authentication required for %s", hostname)
46-
}
32+
if err != nil || token == "" {
33+
// Users shouldn't see this because of the pre-execute auth check on commands
34+
return "", fmt.Errorf("authentication required for %s; please run `gh auth login -h %s`", hostname, hostname)
4735
}
4836

4937
return fmt.Sprintf("token %s", token), nil

pkg/cmd/factory/remote_resolver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (rr *remoteResolver) Resolver() func() (context.Remotes, error) {
7272
}
7373

7474
if len(cachedRemotes) == 0 {
75-
remotesError = errors.New("none of the git remotes point to a known GitHub host")
75+
remotesError = errors.New("none of the git remotes configured for this repository point to a known GitHub host. To tell gh about a new GitHub host, please use `gh auth login`")
7676
return nil, remotesError
7777
}
7878
return cachedRemotes, nil

pkg/cmd/root/completion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ func NewCmdCompletion(io *iostreams.IOStreams) *cobra.Command {
5656
},
5757
}
5858

59+
cmdutil.DisableAuthCheck(cmd)
60+
5961
cmd.Flags().StringVarP(&shellType, "shell", "s", "", "Shell type: {bash|zsh|fish|powershell}")
6062

6163
return cmd

pkg/cmd/root/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ func NewCmdRoot(f *cmdutil.Factory, version, buildDate string) *cobra.Command {
9898
return &cmdutil.FlagError{Err: err}
9999
})
100100

101+
cmdutil.DisableAuthCheck(cmd)
102+
101103
// CHILD COMMANDS
102104

103105
cmd.AddCommand(aliasCmd.NewCmdAlias(f))

pkg/cmdutil/auth_check.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cmdutil
2+
3+
import (
4+
"github.com/cli/cli/internal/config"
5+
"github.com/spf13/cobra"
6+
)
7+
8+
// TODO can have this set a PersistentPreRun so we don't have to set for all child commands of auth,
9+
// config
10+
11+
func DisableAuthCheck(cmd *cobra.Command) {
12+
if cmd.Annotations == nil {
13+
cmd.Annotations = map[string]string{}
14+
}
15+
16+
cmd.Annotations["skipAuthCheck"] = "true"
17+
}
18+
19+
func CheckAuth(cfg config.Config) bool {
20+
hosts, err := cfg.Hosts()
21+
if err != nil {
22+
return false
23+
}
24+
25+
for _, hostname := range hosts {
26+
token, _ := cfg.Get(hostname, "oauth_token")
27+
if token != "" {
28+
return true
29+
}
30+
}
31+
32+
return false
33+
}
34+
35+
func IsAuthCheckEnabled(cmd *cobra.Command) bool {
36+
if !cmd.Runnable() {
37+
return false
38+
}
39+
for c := cmd; c.Parent() != nil; c = c.Parent() {
40+
if c.Annotations != nil && c.Annotations["skipAuthCheck"] == "true" {
41+
return false
42+
}
43+
}
44+
45+
return true
46+
}

0 commit comments

Comments
 (0)