Merge pull request #727 from thefotios/respect-clone-target

Respect clone target

Closes #721
This commit is contained in:
Mislav Marohnić 2020-04-03 19:18:05 +02:00 committed by GitHub
commit 43b28f769b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 20 deletions

View file

@ -51,12 +51,12 @@ A repository can be supplied as an argument in any of the following formats:
}
var repoCloneCmd = &cobra.Command{
Use: "clone <repo>",
Use: "clone <repo> [<directory>]",
Args: cobra.MinimumNArgs(1),
Short: "Clone a repository locally",
Long: `Clone a GitHub repository locally.
To pass 'git clone' options, separate them with '--'.`,
To pass 'git clone' flags, separate them with '--'.`,
RunE: repoClone,
}
@ -87,6 +87,41 @@ With no argument, the repository for the current directory is displayed.`,
RunE: repoView,
}
func parseCloneArgs(extraArgs []string) (args []string, target string) {
args = extraArgs
if len(args) > 0 {
if !strings.HasPrefix(args[0], "-") {
target, args = args[0], args[1:]
}
}
return
}
func runClone(cloneURL string, args []string) (target string, err error) {
cloneArgs, target := parseCloneArgs(args)
cloneArgs = append(cloneArgs, cloneURL)
// If the args contain an explicit target, pass it to clone
// otherwise, parse the URL to determine where git cloned it to so we can return it
if target != "" {
cloneArgs = append(cloneArgs, target)
} else {
target = path.Base(strings.TrimSuffix(cloneURL, ".git"))
}
cloneArgs = append([]string{"clone"}, cloneArgs...)
cloneCmd := git.GitCommand(cloneArgs...)
cloneCmd.Stdin = os.Stdin
cloneCmd.Stdout = os.Stdout
cloneCmd.Stderr = os.Stderr
err = run.PrepareCmd(cloneCmd).Run()
return
}
func repoClone(cmd *cobra.Command, args []string) error {
cloneURL := args[0]
if !strings.Contains(cloneURL, ":") {
@ -115,21 +150,13 @@ func repoClone(cmd *cobra.Command, args []string) error {
}
}
cloneArgs := []string{"clone"}
cloneArgs = append(cloneArgs, args[1:]...)
cloneArgs = append(cloneArgs, cloneURL)
cloneCmd := git.GitCommand(cloneArgs...)
cloneCmd.Stdin = os.Stdin
cloneCmd.Stdout = os.Stdout
cloneCmd.Stderr = os.Stderr
err := run.PrepareCmd(cloneCmd).Run()
cloneDir, err := runClone(cloneURL, args[1:])
if err != nil {
return err
}
if parentRepo != nil {
err := addUpstreamRemote(parentRepo, cloneURL)
err := addUpstreamRemote(parentRepo, cloneDir)
if err != nil {
return err
}
@ -138,10 +165,9 @@ func repoClone(cmd *cobra.Command, args []string) error {
return nil
}
func addUpstreamRemote(parentRepo ghrepo.Interface, cloneURL string) error {
func addUpstreamRemote(parentRepo ghrepo.Interface, cloneDir string) error {
// TODO: support SSH remote URLs
upstreamURL := fmt.Sprintf("https://github.com/%s.git", ghrepo.FullName(parentRepo))
cloneDir := path.Base(strings.TrimSuffix(cloneURL, ".git"))
cloneCmd := git.GitCommand("-C", cloneDir, "remote", "add", "upstream", upstreamURL)
cloneCmd.Stdout = os.Stdout
@ -425,16 +451,12 @@ func repoFork(cmd *cobra.Command, args []string) error {
}
}
if cloneDesired {
cloneCmd := git.GitCommand("clone", forkedRepo.CloneURL)
cloneCmd.Stdin = os.Stdin
cloneCmd.Stdout = os.Stdout
cloneCmd.Stderr = os.Stderr
err = run.PrepareCmd(cloneCmd).Run()
cloneDir, err := runClone(forkedRepo.CloneURL, []string{})
if err != nil {
return fmt.Errorf("failed to clone fork: %w", err)
}
err = addUpstreamRemote(toFork, forkedRepo.CloneURL)
err = addUpstreamRemote(toFork, cloneDir)
if err != nil {
return err
}

View file

@ -5,6 +5,7 @@ import (
"encoding/json"
"io/ioutil"
"os/exec"
"reflect"
"regexp"
"strings"
"testing"
@ -337,6 +338,65 @@ func TestRepoFork_in_parent_survey_no(t *testing.T) {
}
}
func TestParseExtraArgs(t *testing.T) {
type Wanted struct {
args []string
dir string
}
tests := []struct {
name string
args []string
want Wanted
}{
{
name: "args and target",
args: []string{"target_directory", "-o", "upstream", "--depth", "1"},
want: Wanted{
args: []string{"-o", "upstream", "--depth", "1"},
dir: "target_directory",
},
},
{
name: "only args",
args: []string{"-o", "upstream", "--depth", "1"},
want: Wanted{
args: []string{"-o", "upstream", "--depth", "1"},
dir: "",
},
},
{
name: "only target",
args: []string{"target_directory"},
want: Wanted{
args: []string{},
dir: "target_directory",
},
},
{
name: "no args",
args: []string{},
want: Wanted{
args: []string{},
dir: "",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
args, dir := parseCloneArgs(tt.args)
got := Wanted{
args: args,
dir: dir,
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("got %#v want %#v", got, tt.want)
}
})
}
}
func TestRepoClone(t *testing.T) {
tests := []struct {
name string
@ -348,11 +408,21 @@ func TestRepoClone(t *testing.T) {
args: "repo clone OWNER/REPO",
want: "git clone https://github.com/OWNER/REPO.git",
},
{
name: "shorthand with directory",
args: "repo clone OWNER/REPO target_directory",
want: "git clone https://github.com/OWNER/REPO.git target_directory",
},
{
name: "clone arguments",
args: "repo clone OWNER/REPO -- -o upstream --depth 1",
want: "git clone -o upstream --depth 1 https://github.com/OWNER/REPO.git",
},
{
name: "clone arguments with directory",
args: "repo clone OWNER/REPO target_directory -- -o upstream --depth 1",
want: "git clone -o upstream --depth 1 https://github.com/OWNER/REPO.git target_directory",
},
{
name: "HTTPS URL",
args: "repo clone https://github.com/OWNER/REPO",