Merge pull request #12686 from 4RH1T3CT0R7/add-no-upstream-flag
Add --no-upstream flag to repo clone
This commit is contained in:
commit
6e979c6b32
2 changed files with 116 additions and 24 deletions
|
|
@ -27,6 +27,7 @@ type CloneOptions struct {
|
|||
GitArgs []string
|
||||
Repository string
|
||||
UpstreamName string
|
||||
NoUpstream bool
|
||||
}
|
||||
|
||||
func NewCmdClone(f *cmdutil.Factory, runF func(*CloneOptions) error) *cobra.Command {
|
||||
|
|
@ -60,6 +61,7 @@ func NewCmdClone(f *cmdutil.Factory, runF func(*CloneOptions) error) *cobra.Comm
|
|||
the remote after the owner of the parent repository.
|
||||
|
||||
If the repository is a fork, its parent repository will be set as the default remote repository.
|
||||
To skip this behavior, use %[1]s--no-upstream%[1]s.
|
||||
`, "`"),
|
||||
Example: heredoc.Doc(`
|
||||
# Clone a repository from a specific org
|
||||
|
|
@ -77,6 +79,9 @@ func NewCmdClone(f *cmdutil.Factory, runF func(*CloneOptions) error) *cobra.Comm
|
|||
|
||||
# Clone a repository with additional git clone flags
|
||||
$ gh repo clone cli/cli -- --depth=1
|
||||
|
||||
# Clone a fork without adding an upstream remote
|
||||
$ gh repo clone myfork --no-upstream
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
opts.Repository = args[0]
|
||||
|
|
@ -91,6 +96,8 @@ func NewCmdClone(f *cmdutil.Factory, runF func(*CloneOptions) error) *cobra.Comm
|
|||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.UpstreamName, "upstream-remote-name", "u", "upstream", "Upstream remote name when cloning a fork")
|
||||
cmd.Flags().BoolVar(&opts.NoUpstream, "no-upstream", false, "Do not add an upstream remote when cloning a fork")
|
||||
cmd.MarkFlagsMutuallyExclusive("upstream-remote-name", "no-upstream")
|
||||
cmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
|
||||
if err == pflag.ErrHelp {
|
||||
return err
|
||||
|
|
@ -187,37 +194,43 @@ func cloneRun(opts *CloneOptions) error {
|
|||
|
||||
// If the repo is a fork, add the parent as an upstream remote and set the parent as the default repo.
|
||||
if canonicalRepo.Parent != nil {
|
||||
protocol := cfg.GitProtocol(canonicalRepo.Parent.RepoHost()).Value
|
||||
upstreamURL := ghrepo.FormatRemoteURL(canonicalRepo.Parent, protocol)
|
||||
|
||||
upstreamName := opts.UpstreamName
|
||||
if opts.UpstreamName == "@owner" {
|
||||
upstreamName = canonicalRepo.Parent.RepoOwner()
|
||||
}
|
||||
|
||||
gc := gitClient.Copy()
|
||||
gc.RepoDir = cloneDir
|
||||
|
||||
if _, err := gc.AddRemote(ctx, upstreamName, upstreamURL, []string{canonicalRepo.Parent.DefaultBranchRef.Name}); err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.NoUpstream {
|
||||
if err := gc.SetRemoteResolution(ctx, "origin", "base"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
protocol := cfg.GitProtocol(canonicalRepo.Parent.RepoHost()).Value
|
||||
upstreamURL := ghrepo.FormatRemoteURL(canonicalRepo.Parent, protocol)
|
||||
|
||||
if err := gc.Fetch(ctx, upstreamName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
upstreamName := opts.UpstreamName
|
||||
if opts.UpstreamName == "@owner" {
|
||||
upstreamName = canonicalRepo.Parent.RepoOwner()
|
||||
}
|
||||
|
||||
if err := gc.SetRemoteBranches(ctx, upstreamName, `*`); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := gc.AddRemote(ctx, upstreamName, upstreamURL, []string{canonicalRepo.Parent.DefaultBranchRef.Name}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = gc.SetRemoteResolution(ctx, upstreamName, "base"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gc.Fetch(ctx, upstreamName, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
connectedToTerminal := opts.IO.IsStdoutTTY()
|
||||
if connectedToTerminal {
|
||||
cs := opts.IO.ColorScheme()
|
||||
fmt.Fprintf(opts.IO.ErrOut, "%s Repository %s set as the default repository. To learn more about the default repository, run: gh repo set-default --help\n", cs.WarningIcon(), cs.Bold(ghrepo.FullName(canonicalRepo.Parent)))
|
||||
if err := gc.SetRemoteBranches(ctx, upstreamName, `*`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gc.SetRemoteResolution(ctx, upstreamName, "base"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
connectedToTerminal := opts.IO.IsStdoutTTY()
|
||||
if connectedToTerminal {
|
||||
cs := opts.IO.ColorScheme()
|
||||
fmt.Fprintf(opts.IO.ErrOut, "%s Repository %s set as the default repository. To learn more about the default repository, run: gh repo set-default --help\n", cs.WarningIcon(), cs.Bold(ghrepo.FullName(canonicalRepo.Parent)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -54,6 +54,20 @@ func TestNewCmdClone(t *testing.T) {
|
|||
GitArgs: []string{"--depth", "1", "--recurse-submodules"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no-upstream flag",
|
||||
args: "OWNER/REPO --no-upstream",
|
||||
wantOpts: CloneOptions{
|
||||
Repository: "OWNER/REPO",
|
||||
GitArgs: []string{},
|
||||
NoUpstream: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no-upstream with upstream-remote-name",
|
||||
args: "OWNER/REPO --no-upstream --upstream-remote-name test",
|
||||
wantErr: "if any flags in the group [upstream-remote-name no-upstream] are set none of the others can be; [no-upstream upstream-remote-name] were all set",
|
||||
},
|
||||
{
|
||||
name: "unknown argument",
|
||||
args: "OWNER/REPO --depth 1",
|
||||
|
|
@ -92,6 +106,7 @@ func TestNewCmdClone(t *testing.T) {
|
|||
|
||||
assert.Equal(t, tt.wantOpts.Repository, opts.Repository)
|
||||
assert.Equal(t, tt.wantOpts.GitArgs, opts.GitArgs)
|
||||
assert.Equal(t, tt.wantOpts.NoUpstream, opts.NoUpstream)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -344,6 +359,70 @@ func Test_RepoClone_withoutUsername(t *testing.T) {
|
|||
assert.Equal(t, "", output.Stderr())
|
||||
}
|
||||
|
||||
func Test_RepoClone_hasParent_noUpstream(t *testing.T) {
|
||||
reg := &httpmock.Registry{}
|
||||
defer reg.Verify(t)
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query RepositoryInfo\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": {
|
||||
"name": "REPO",
|
||||
"owner": {
|
||||
"login": "OWNER"
|
||||
},
|
||||
"parent": {
|
||||
"name": "ORIG",
|
||||
"owner": {
|
||||
"login": "hubot"
|
||||
},
|
||||
"defaultBranchRef": {
|
||||
"name": "trunk"
|
||||
}
|
||||
}
|
||||
} } }
|
||||
`))
|
||||
|
||||
httpClient := &http.Client{Transport: reg}
|
||||
|
||||
cs, cmdTeardown := run.Stub()
|
||||
defer cmdTeardown(t)
|
||||
|
||||
cs.Register(`git clone https://github.com/OWNER/REPO.git`, 0, "")
|
||||
cs.Register(`git -C REPO config --add remote.origin.gh-resolved base`, 0, "")
|
||||
|
||||
_, err := runCloneCommand(httpClient, "OWNER/REPO --no-upstream")
|
||||
if err != nil {
|
||||
t.Fatalf("error running command `repo clone`: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RepoClone_noParent_noUpstream(t *testing.T) {
|
||||
reg := &httpmock.Registry{}
|
||||
defer reg.Verify(t)
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query RepositoryInfo\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": {
|
||||
"name": "REPO",
|
||||
"owner": {
|
||||
"login": "OWNER"
|
||||
}
|
||||
} } }
|
||||
`))
|
||||
|
||||
httpClient := &http.Client{Transport: reg}
|
||||
|
||||
cs, cmdTeardown := run.Stub()
|
||||
defer cmdTeardown(t)
|
||||
|
||||
cs.Register(`git clone https://github.com/OWNER/REPO.git`, 0, "")
|
||||
|
||||
_, err := runCloneCommand(httpClient, "OWNER/REPO --no-upstream")
|
||||
if err != nil {
|
||||
t.Fatalf("error running command `repo clone`: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimplifyURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue