Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Make av auth status output less confusing #217

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 59 additions & 17 deletions cmd/av/auth_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import (
"fmt"
"os"

"emperror.dev/errors"
"github.com/aviator-co/av/internal/actions"
"github.com/aviator-co/av/internal/gh"

"github.com/aviator-co/av/internal/avgql"
"github.com/aviator-co/av/internal/utils/colors"
"github.com/spf13/cobra"
Expand All @@ -16,26 +20,64 @@ var authStatusCmd = &cobra.Command{
SilenceUsage: true,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
client, err := avgql.NewClient()
if err != nil {
return err
}

var query struct {
avgql.ViewerSubquery
exitCode := 0
if err := checkAviatorAuthStatus(); err != nil {
_, _ = fmt.Fprintln(os.Stderr, colors.Failure(err.Error()))
exitCode = 1
}

if err := client.Query(context.Background(), &query, nil); err != nil {
return err
if err := checkGitHubAuthStatus(); err != nil {
_, _ = fmt.Fprintln(os.Stderr, colors.Failure(err.Error()))
exitCode = 1
}
if err := query.CheckViewer(); err != nil {
return err
if exitCode != 0 {
return actions.ErrExitSilently{ExitCode: exitCode}
}

_, _ = fmt.Fprint(os.Stderr,
"Logged in as ", colors.UserInput(query.Viewer.FullName),
" (", colors.UserInput(query.Viewer.Email), ").\n",
)
return nil
},
}

func checkAviatorAuthStatus() error {
avClient, err := avgql.NewClient()
if err != nil {
return err
}

var query struct{ avgql.ViewerSubquery }
if err := avClient.Query(context.Background(), &query, nil); err != nil {
return err
}
if err := query.CheckViewer(); err != nil {
return err
}

_, _ = fmt.Fprint(os.Stderr,
"Logged in to Aviator as ", colors.UserInput(query.Viewer.FullName),
" (", colors.UserInput(query.Viewer.Email), ").\n",
)
return nil
}

func checkGitHubAuthStatus() error {
ghClient, err := getGitHubClient()
if err != nil {
return err
}

viewer, err := ghClient.Viewer(context.Background())
if err != nil {
// GitHub API returns 401 Unauthorized if the token is invalid or
// expired.
if gh.IsHTTPUnauthorized(err) {
return errors.New(
"You are not logged in to GitHub. Please verify that your API token is correct.",
)
}
return errors.Wrap(err, "Failed to query GitHub")
}

_, _ = fmt.Fprint(os.Stderr,
"Logged in to GitHub as ", colors.UserInput(viewer.Name),
" (", colors.UserInput(viewer.Login), ").\n",
)
return nil
}
4 changes: 3 additions & 1 deletion cmd/av/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,12 @@ func discoverGitHubAPIToken() string {
return ""
}

var errNoGitHubToken = errors.New("No GitHub token is set (do you need to configure one?).")

func getGitHubClient() (*gh.Client, error) {
token := discoverGitHubAPIToken()
if token == "" {
return nil, errors.New("github token must be set")
return nil, errNoGitHubToken
}
var err error
once.Do(func() {
Expand Down
2 changes: 1 addition & 1 deletion internal/avgql/viewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type ViewerSubquery struct {
}

var ErrNotAuthenticated = errors.New(
"You are not logged in. Please verify that your API token is correct.",
"You are not logged in to Aviator. Please verify that your API token is correct.",
)

// CheckViewer checks whether or not the viewer is authenticated.
Expand Down
11 changes: 11 additions & 0 deletions internal/gh/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package gh

import "strings"

// IsHTTPUnauthorized returns true if the given error is an HTTP 401 Unauthorized error.
func IsHTTPUnauthorized(err error) bool {
// This is a bit fragile because it relies on the error message from the
// GraphQL package. It doesn't export proper error types so we have to check
// the string.
return strings.Contains(err.Error(), "status code: 401")
}
19 changes: 19 additions & 0 deletions internal/gh/viewer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package gh

import "context"

type Viewer struct {
Name string `graphql:"name"`
Login string `graphql:"login"`
}

func (c *Client) Viewer(ctx context.Context) (*Viewer, error) {
var query struct {
Viewer Viewer `graphql:"viewer"`
}
err := c.query(ctx, &query, nil)
if err != nil {
return nil, err
}
return &query.Viewer, nil
}