cli/pkg/cmd/auth/refresh/refresh.go
Mislav Marohnić c80292c2e8 Extend Config object with GITHUB_TOKEN support
Adding GITHUB_TOKEN & GITHUB_ENTERPRISE_TOKEN support orthogonal to
Config was getting out of hand, especially in `auth` commands that
adjust their messaging and error status based on the presence of these
environment variables.

The new approach builds in support for tokens from environment straight
into Config object by composition. Thus, commands need not ever be
concerned with any specific environment variables.
2020-09-07 21:33:26 +02:00

115 lines
3 KiB
Go

package refresh
import (
"fmt"
"github.com/AlecAivazis/survey/v2"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/internal/config"
"github.com/cli/cli/pkg/cmdutil"
"github.com/cli/cli/pkg/iostreams"
"github.com/cli/cli/pkg/prompt"
"github.com/spf13/cobra"
)
type RefreshOptions struct {
IO *iostreams.IOStreams
Config func() (config.Config, error)
Hostname string
Scopes []string
AuthFlow func(config.Config, string, []string) error
}
func NewCmdRefresh(f *cmdutil.Factory, runF func(*RefreshOptions) error) *cobra.Command {
opts := &RefreshOptions{
IO: f.IOStreams,
Config: f.Config,
AuthFlow: func(cfg config.Config, hostname string, scopes []string) error {
_, err := config.AuthFlowWithConfig(cfg, hostname, "", scopes)
return err
},
}
cmd := &cobra.Command{
Use: "refresh",
Args: cobra.ExactArgs(0),
Short: "Refresh stored authentication credentials",
Long: heredoc.Doc(`Expand or fix the permission scopes for stored credentials
The --scopes flag accepts a comma separated list of scopes you want your gh credentials to have. If
absent, this command ensures that gh has access to a minimum set of scopes.
`),
Example: heredoc.Doc(`
$ gh auth refresh --scopes write:org,read:public_key
# => open a browser to add write:org and read:public_key scopes for use with gh api
$ gh auth refresh
# => open a browser to ensure your authentication credentials have the correct minimum scopes
`),
RunE: func(cmd *cobra.Command, args []string) error {
if runF != nil {
return runF(opts)
}
return refreshRun(opts)
},
}
cmd.Flags().StringVarP(&opts.Hostname, "hostname", "h", "", "The GitHub host to use for authentication")
cmd.Flags().StringSliceVarP(&opts.Scopes, "scopes", "s", nil, "Additional authentication scopes for gh to have")
return cmd
}
func refreshRun(opts *RefreshOptions) error {
isTTY := opts.IO.IsStdinTTY() && opts.IO.IsStdoutTTY()
if !isTTY {
return fmt.Errorf("not attached to a terminal; in headless environments, GITHUB_TOKEN is recommended")
}
cfg, err := opts.Config()
if err != nil {
return err
}
candidates, err := cfg.Hosts()
if err != nil {
return fmt.Errorf("not logged in to any hosts. Use 'gh auth login' to authenticate with a host")
}
hostname := opts.Hostname
if hostname == "" {
if len(candidates) == 1 {
hostname = candidates[0]
} else {
err := prompt.SurveyAskOne(&survey.Select{
Message: "What account do you want to refresh auth for?",
Options: candidates,
}, &hostname)
if err != nil {
return fmt.Errorf("could not prompt: %w", err)
}
}
} else {
var found bool
for _, c := range candidates {
if c == hostname {
found = true
break
}
}
if !found {
return fmt.Errorf("not logged in to %s. use 'gh auth login' to authenticate with this host", hostname)
}
}
if err := cfg.CheckWriteable(hostname, "oauth_token"); err != nil {
return err
}
return opts.AuthFlow(cfg, hostname, opts.Scopes)
}