diff --git a/pkg/cmd/pr/checkout/checkout.go b/pkg/cmd/pr/checkout/checkout.go index 0647aebb2..f267dd9b4 100644 --- a/pkg/cmd/pr/checkout/checkout.go +++ b/pkg/cmd/pr/checkout/checkout.go @@ -96,7 +96,9 @@ func checkoutRun(opts *CheckoutOptions) error { } headRemote := baseRemote - if pr.IsCrossRepository { + if pr.HeadRepository == nil { + headRemote = nil + } else if pr.IsCrossRepository { headRemote, _ = remotes.FindByRepo(pr.HeadRepositoryOwner.Login, pr.HeadRepository.Name) } @@ -207,7 +209,7 @@ func cmdsForMissingRemote(pr *api.PullRequest, baseURLOrName, repoHost, defaultB remote := baseURLOrName mergeRef := ref - if pr.MaintainerCanModify { + if pr.MaintainerCanModify && pr.HeadRepository != nil { headRepo := ghrepo.NewWithHost(pr.HeadRepositoryOwner.Login, pr.HeadRepository.Name, repoHost) remote = ghrepo.FormatRemoteURL(headRepo, protocol) mergeRef = fmt.Sprintf("refs/heads/%s", pr.HeadRefName) diff --git a/pkg/cmd/pr/checkout/checkout_test.go b/pkg/cmd/pr/checkout/checkout_test.go index 48150ff84..cffa3f4d9 100644 --- a/pkg/cmd/pr/checkout/checkout_test.go +++ b/pkg/cmd/pr/checkout/checkout_test.go @@ -2,6 +2,7 @@ package checkout import ( "bytes" + "errors" "io/ioutil" "net/http" "strings" @@ -59,6 +60,99 @@ func stubPR(repo, prHead string) (ghrepo.Interface, *api.PullRequest) { } } +func Test_checkoutRun(t *testing.T) { + tests := []struct { + name string + opts *CheckoutOptions + httpStubs func(*httpmock.Registry) + runStubs func(*run.CommandStubber) + remotes map[string]string + wantStdout string + wantStderr string + wantErr bool + }{ + { + name: "fork repo was deleted", + opts: &CheckoutOptions{ + SelectorArg: "123", + Finder: func() shared.PRFinder { + baseRepo, pr := stubPR("OWNER/REPO:master", "hubot/REPO:feature") + pr.MaintainerCanModify = true + pr.HeadRepository = nil + finder := shared.NewMockFinder("123", pr, baseRepo) + return finder + }(), + Config: func() (config.Config, error) { + return config.NewBlankConfig(), nil + }, + Branch: func() (string, error) { + return "main", nil + }, + }, + remotes: map[string]string{ + "origin": "OWNER/REPO", + }, + runStubs: func(cs *run.CommandStubber) { + cs.Register(`git fetch origin refs/pull/123/head:feature`, 0, "") + cs.Register(`git config branch\.feature\.merge`, 1, "") + cs.Register(`git checkout feature`, 0, "") + cs.Register(`git config branch\.feature\.remote origin`, 0, "") + cs.Register(`git config branch\.feature\.merge refs/pull/123/head`, 0, "") + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + opts := tt.opts + + io, _, stdout, stderr := iostreams.Test() + opts.IO = io + + httpReg := &httpmock.Registry{} + defer httpReg.Verify(t) + if tt.httpStubs != nil { + tt.httpStubs(httpReg) + } + opts.HttpClient = func() (*http.Client, error) { + return &http.Client{Transport: httpReg}, nil + } + + cmdStubs, cmdTeardown := run.Stub() + defer cmdTeardown(t) + if tt.runStubs != nil { + tt.runStubs(cmdStubs) + } + + opts.Remotes = func() (context.Remotes, error) { + if len(tt.remotes) == 0 { + return nil, errors.New("no remotes") + } + var remotes context.Remotes + for name, repo := range tt.remotes { + r, err := ghrepo.FromFullName(repo) + if err != nil { + return remotes, err + } + remotes = append(remotes, &context.Remote{ + Remote: &git.Remote{Name: name}, + Repo: r, + }) + } + return remotes, nil + } + + err := checkoutRun(opts) + if (err != nil) != tt.wantErr { + t.Errorf("want error: %v, got: %v", tt.wantErr, err) + } + assert.Equal(t, tt.wantStdout, stdout.String()) + assert.Equal(t, tt.wantStderr, stderr.String()) + }) + } +} + +/** LEGACY TESTS **/ + func runCommand(rt http.RoundTripper, remotes context.Remotes, branch string, cli string) (*test.CmdOut, error) { io, _, stdout, stderr := iostreams.Test()