1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
package setupgit
import (
"fmt"
"strings"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/pkg/cmd/auth/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/spf13/cobra"
)
type gitConfigurator interface {
Setup(hostname, username, authToken string) error
}
type SetupGitOptions struct {
IO *iostreams.IOStreams
Config func() (config.Config, error)
Hostname string
Force bool
gitConfigure gitConfigurator
}
func NewCmdSetupGit(f *cmdutil.Factory, runF func(*SetupGitOptions) error) *cobra.Command {
opts := &SetupGitOptions{
IO: f.IOStreams,
Config: f.Config,
}
cmd := &cobra.Command{
Use: "setup-git",
Short: "Setup git with GitHub CLI",
Long: heredoc.Docf(`
This command configures %[1]sgit%[1]s to use GitHub CLI as a credential helper.
For more information on git credential helpers please reference:
https://git-scm.com/docs/gitcredentials.
By default, GitHub CLI will be set as the credential helper for all authenticated hosts.
If there is no authenticated hosts the command fails with an error.
Alternatively, use the %[1]s--hostname%[1]s flag to specify a single host to be configured.
If the host is not authenticated with, the command fails with an error.
`, "`"),
Example: heredoc.Doc(`
# Configure git to use GitHub CLI as the credential helper for all authenticated hosts
$ gh auth setup-git
# Configure git to use GitHub CLI as the credential helper for enterprise.internal host
$ gh auth setup-git --hostname enterprise.internal
`),
RunE: func(cmd *cobra.Command, args []string) error {
opts.gitConfigure = &shared.GitCredentialFlow{
Executable: f.Executable(),
GitClient: f.GitClient,
}
if opts.Hostname == "" && opts.Force {
return cmdutil.FlagErrorf("`--force` must be used in conjunction with `--hostname`")
}
if runF != nil {
return runF(opts)
}
return setupGitRun(opts)
},
}
cmd.Flags().StringVarP(&opts.Hostname, "hostname", "h", "", "The hostname to configure git for")
cmd.Flags().BoolVarP(&opts.Force, "force", "f", false, "Force setup even if the host is not known. Must be used in conjunction with `--hostname`")
return cmd
}
func setupGitRun(opts *SetupGitOptions) error {
cfg, err := opts.Config()
if err != nil {
return err
}
authCfg := cfg.Authentication()
hostnames := authCfg.Hosts()
stderr := opts.IO.ErrOut
cs := opts.IO.ColorScheme()
// If a hostname was provided, we'll set up just that one
if opts.Hostname != "" {
if !opts.Force && !has(opts.Hostname, hostnames) {
return fmt.Errorf("You are not logged into the GitHub host %q. Run %s to authenticate or provide `--force`",
opts.Hostname,
cs.Bold(fmt.Sprintf("gh auth login -h %s", opts.Hostname)),
)
}
if err := opts.gitConfigure.Setup(opts.Hostname, "", ""); err != nil {
return fmt.Errorf("failed to set up git credential helper: %s", err)
}
return nil
}
// Otherwise we'll set up any known hosts
if len(hostnames) == 0 {
fmt.Fprintf(
stderr,
"You are not logged into any GitHub hosts. Run %s to authenticate.\n",
cs.Bold("gh auth login"),
)
return cmdutil.SilentError
}
for _, hostname := range hostnames {
if err := opts.gitConfigure.Setup(hostname, "", ""); err != nil {
return fmt.Errorf("failed to set up git credential helper: %s", err)
}
}
return nil
}
func has(needle string, haystack []string) bool {
for _, s := range haystack {
if strings.EqualFold(s, needle) {
return true
}
}
return false
}
|