cli/pkg/cmd/repo/clone/clone.go
vilmibm 1831d95433 isolated clone command
This commit hacks the existing repo clone tests into something usable by
the new isolated command. It went ok and was less effort than trying to
introduce the same kind of test format as repo view and gist create.
2020-07-23 16:40:31 -05:00

126 lines
2.7 KiB
Go

package clone
import (
"net/http"
"strings"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/api"
"github.com/cli/cli/git"
"github.com/cli/cli/internal/config"
"github.com/cli/cli/internal/ghrepo"
"github.com/cli/cli/pkg/cmdutil"
"github.com/cli/cli/pkg/iostreams"
"github.com/spf13/cobra"
)
type CloneOptions struct {
HttpClient func() (*http.Client, error)
Config func() (config.Config, error)
IO *iostreams.IOStreams
GitArgs []string
Directory string
Repository string
}
func NewCmdClone(f *cmdutil.Factory, runF func(*CloneOptions) error) *cobra.Command {
opts := &CloneOptions{
IO: f.IOStreams,
HttpClient: f.HttpClient,
Config: f.Config,
}
cmd := &cobra.Command{
Use: "clone <repository> [<directory>]",
Args: cobra.MinimumNArgs(1),
Short: "Clone a repository locally",
Long: heredoc.Doc(
`Clone a GitHub repository locally.
If the "OWNER/" portion of the "OWNER/REPO" repository argument is omitted, it
defaults to the name of the authenticating user.
To pass 'git clone' flags, separate them with '--'.
`),
RunE: func(cmd *cobra.Command, args []string) error {
opts.Repository = args[0]
opts.GitArgs = args[1:]
if runF != nil {
return runF(opts)
}
return cloneRun(opts)
},
}
return cmd
}
func cloneRun(opts *CloneOptions) error {
httpClient, err := opts.HttpClient()
if err != nil {
return err
}
// TODO This is overly wordy and I'd like to streamline this.
cfg, err := opts.Config()
if err != nil {
return err
}
protocol, err := cfg.Get("", "git_protocol")
if err != nil {
return err
}
apiClient := api.NewClientFromHTTP(httpClient)
cloneURL := opts.Repository
if !strings.Contains(cloneURL, ":") {
if !strings.Contains(cloneURL, "/") {
currentUser, err := api.CurrentLoginName(apiClient)
if err != nil {
return err
}
cloneURL = currentUser + "/" + cloneURL
}
repo, err := ghrepo.FromFullName(cloneURL)
if err != nil {
return err
}
cloneURL = ghrepo.FormatRemoteURL(repo, protocol)
}
var repo ghrepo.Interface
var parentRepo ghrepo.Interface
// TODO: consider caching and reusing `git.ParseSSHConfig().Translator()`
// here to handle hostname aliases in SSH remotes
if u, err := git.ParseURL(cloneURL); err == nil {
repo, _ = ghrepo.FromURL(u)
}
if repo != nil {
parentRepo, err = api.RepoParent(apiClient, repo)
if err != nil {
return err
}
}
cloneDir, err := git.RunClone(cloneURL, opts.GitArgs)
if err != nil {
return err
}
if parentRepo != nil {
upstreamURL := ghrepo.FormatRemoteURL(parentRepo, protocol)
err := git.AddUpstreamRemote(upstreamURL, cloneDir)
if err != nil {
return err
}
}
return nil
}