diff --git a/command/pr_checkout.go b/command/pr_checkout.go index 2c12cb6c3..256a3dfe8 100644 --- a/command/pr_checkout.go +++ b/command/pr_checkout.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "os/exec" + "strings" "github.com/spf13/cobra" @@ -46,6 +47,9 @@ func prCheckout(cmd *cobra.Command, args []string) error { var cmdQueue [][]string newBranchName := pr.HeadRefName + if strings.HasPrefix(newBranchName, "-") { + return fmt.Errorf("invalid branch name: %q", newBranchName) + } if headRemote != nil { // there is an existing git remote for PR head diff --git a/command/pr_checkout_test.go b/command/pr_checkout_test.go index d7f0e3e18..eeda8cee9 100644 --- a/command/pr_checkout_test.go +++ b/command/pr_checkout_test.go @@ -11,6 +11,7 @@ import ( "github.com/cli/cli/internal/run" "github.com/cli/cli/pkg/httpmock" "github.com/cli/cli/test" + "github.com/stretchr/testify/assert" ) func TestPRCheckout_sameRepo(t *testing.T) { @@ -464,6 +465,47 @@ func TestPRCheckout_differentRepo_currentBranch(t *testing.T) { eq(t, strings.Join(ranCommands[1], " "), "git merge --ff-only FETCH_HEAD") } +func TestPRCheckout_differentRepo_invalidBranchName(t *testing.T) { + ctx := context.NewBlank() + ctx.SetBranch("feature") + ctx.SetRemotes(map[string]string{ + "origin": "OWNER/REPO", + }) + initContext = func() context.Context { + return ctx + } + http := initFakeHTTP() + defer http.Verify(t) + http.StubRepoResponse("OWNER", "REPO") + + http.Register(httpmock.GraphQL(`query PullRequestByNumber\b`), httpmock.StringResponse(` + { "data": { "repository": { "pullRequest": { + "number": 123, + "headRefName": "-foo", + "headRepositoryOwner": { + "login": "hubot" + }, + "headRepository": { + "name": "REPO" + }, + "isCrossRepository": true, + "maintainerCanModify": false + } } } } + `)) + + restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable { + t.Errorf("unexpected external invocation: %v", cmd.Args) + return &test.OutputStub{} + }) + defer restoreCmd() + + output, err := RunCommand(`pr checkout 123`) + if assert.Errorf(t, err, "expected command to fail") { + assert.Equal(t, `invalid branch name: "-foo"`, err.Error()) + } + assert.Equal(t, "", output.Stderr()) +} + func TestPRCheckout_maintainerCanModify(t *testing.T) { ctx := context.NewBlank() ctx.SetBranch("master")