diff --git a/pkg/cmd/pr/checkout/checkout.go b/pkg/cmd/pr/checkout/checkout.go index 23c4bb70b..d4249740e 100644 --- a/pkg/cmd/pr/checkout/checkout.go +++ b/pkg/cmd/pr/checkout/checkout.go @@ -3,11 +3,6 @@ package checkout import ( "errors" "fmt" - "net/http" - "os" - "os/exec" - "strings" - "github.com/cli/cli/api" "github.com/cli/cli/context" "github.com/cli/cli/git" @@ -18,6 +13,10 @@ import ( "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" "github.com/spf13/cobra" + "net/http" + "os" + "os/exec" + "strings" ) type CheckoutOptions struct { @@ -28,7 +27,8 @@ type CheckoutOptions struct { Remotes func() (context.Remotes, error) Branch func() (string, error) - SelectorArg string + SelectorArg string + RecurseSubmodules bool } func NewCmdCheckout(f *cmdutil.Factory, runF func(*CheckoutOptions) error) *cobra.Command { @@ -64,6 +64,8 @@ func NewCmdCheckout(f *cmdutil.Factory, runF func(*CheckoutOptions) error) *cobr }, } + cmd.Flags().BoolVarP(&opts.RecurseSubmodules, "recurse-submodules", "", false, "Update all active submodules (recursively)") + return cmd } @@ -166,6 +168,11 @@ func checkoutRun(opts *CheckoutOptions) error { } } + if opts.RecurseSubmodules { + cmdQueue = append(cmdQueue, []string{"git", "submodule", "sync", "--recursive"}) + cmdQueue = append(cmdQueue, []string{"git", "submodule", "update", "--init", "--recursive"}) + } + for _, args := range cmdQueue { cmd := exec.Command(args[0], args[1:]...) cmd.Stdout = os.Stdout diff --git a/pkg/cmd/pr/checkout/checkout_test.go b/pkg/cmd/pr/checkout/checkout_test.go index 847702c77..c49fef7e0 100644 --- a/pkg/cmd/pr/checkout/checkout_test.go +++ b/pkg/cmd/pr/checkout/checkout_test.go @@ -565,3 +565,45 @@ func TestPRCheckout_maintainerCanModify(t *testing.T) { eq(t, strings.Join(ranCommands[2], " "), "git config branch.feature.remote https://github.com/hubot/REPO.git") eq(t, strings.Join(ranCommands[3], " "), "git config branch.feature.merge refs/heads/feature") } + +func TestPRCheckout_recurseSubmodules(t *testing.T) { + http := &httpmock.Registry{} + + http.Register(httpmock.GraphQL(`query PullRequestByNumber\b`), httpmock.StringResponse(` + { "data": { "repository": { "pullRequest": { + "number": 123, + "headRefName": "feature", + "headRepositoryOwner": { + "login": "hubot" + }, + "headRepository": { + "name": "REPO" + }, + "isCrossRepository": false, + "maintainerCanModify": false + } } } } + `)) + + ranCommands := [][]string{} + restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable { + switch strings.Join(cmd.Args, " ") { + case "git show-ref --verify -- refs/heads/feature": + return &test.OutputStub{} + default: + ranCommands = append(ranCommands, cmd.Args) + return &test.OutputStub{} + } + }) + defer restoreCmd() + + output, err := runCommand(http, nil, "master", `123 --recurse-submodules`) + eq(t, err, nil) + eq(t, output.String(), "") + + eq(t, len(ranCommands), 5) + eq(t, strings.Join(ranCommands[0], " "), "git fetch origin +refs/heads/feature:refs/remotes/origin/feature") + eq(t, strings.Join(ranCommands[1], " "), "git checkout feature") + eq(t, strings.Join(ranCommands[2], " "), "git merge --ff-only refs/remotes/origin/feature") + eq(t, strings.Join(ranCommands[3], " "), "git submodule sync --recursive") + eq(t, strings.Join(ranCommands[4], " "), "git submodule update --init --recursive") +}