From 508f6787f0f1bd2bd50f232d9026381bb00a9f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 18 Nov 2019 20:52:34 +0100 Subject: [PATCH 1/4] Have PullRequestForBranch accept "owner:branch" value for forks When on a `patch-1` branch locally, `gh pr view` would happily open the first open PR it finds with "patch-1" as its head, even those coming from forks. --- api/queries_pr.go | 66 +++++++++++++++++++++-------------- command/pr.go | 6 ++-- command/pr_test.go | 6 ++-- test/fixtures/prStatus.json | 12 ++++--- test/fixtures/prView.json | 68 +++++++++++++------------------------ 5 files changed, 77 insertions(+), 81 deletions(-) diff --git a/api/queries_pr.go b/api/queries_pr.go index 2be64e46c..83104db29 100644 --- a/api/queries_pr.go +++ b/api/queries_pr.go @@ -2,6 +2,7 @@ package api import ( "fmt" + "strings" ) type PullRequestsPayload struct { @@ -141,7 +142,6 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st title url headRefName - headRefName headRepositoryOwner { login } @@ -172,7 +172,7 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st } query($owner: String!, $repo: String!, $headRefName: String!, $viewerQuery: String!, $reviewerQuery: String!, $per_page: Int = 10) { repository(owner: $owner, name: $repo) { - pullRequests(headRefName: $headRefName, states: OPEN, first: 1) { + pullRequests(headRefName: $headRefName, states: OPEN, first: $per_page) { edges { node { ...prWithReviews @@ -209,12 +209,17 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st viewerQuery := fmt.Sprintf("repo:%s/%s state:open is:pr author:%s", owner, repo, currentUsername) reviewerQuery := fmt.Sprintf("repo:%s/%s state:open review-requested:%s", owner, repo, currentUsername) + branchWithoutOwner := currentBranch + if idx := strings.Index(currentBranch, ":"); idx >= 0 { + branchWithoutOwner = currentBranch[idx+1:] + } + variables := map[string]interface{}{ "viewerQuery": viewerQuery, "reviewerQuery": reviewerQuery, "owner": owner, "repo": repo, - "headRefName": currentBranch, + "headRefName": branchWithoutOwner, } var resp response @@ -235,7 +240,9 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st var currentPR *PullRequest for _, edge := range resp.Repository.PullRequests.Edges { - currentPR = &edge.Node + if edge.Node.HeadLabel() == currentBranch { + currentPR = &edge.Node + } } payload := PullRequestsPayload{ @@ -289,36 +296,42 @@ func PullRequestByNumber(client *Client, ghRepo Repo, number int) (*PullRequest, return &resp.Repository.PullRequest, nil } -func PullRequestsForBranch(client *Client, ghRepo Repo, branch string) ([]PullRequest, error) { +func PullRequestForBranch(client *Client, ghRepo Repo, branch string) (*PullRequest, error) { type response struct { Repository struct { PullRequests struct { - Edges []struct { - Node PullRequest - } + Nodes []PullRequest } } } query := ` - query($owner: String!, $repo: String!, $headRefName: String!) { - repository(owner: $owner, name: $repo) { - pullRequests(headRefName: $headRefName, states: OPEN, first: 1) { - edges { - node { - number - title - url - } - } - } - } - }` + query($owner: String!, $repo: String!, $headRefName: String!) { + repository(owner: $owner, name: $repo) { + pullRequests(headRefName: $headRefName, states: OPEN, first: 30) { + nodes { + number + title + url + headRefName + headRepositoryOwner { + login + } + isCrossRepository + } + } + } + }` + + branchWithoutOwner := branch + if idx := strings.Index(branch, ":"); idx >= 0 { + branchWithoutOwner = branch[idx+1:] + } variables := map[string]interface{}{ "owner": ghRepo.RepoOwner(), "repo": ghRepo.RepoName(), - "headRefName": branch, + "headRefName": branchWithoutOwner, } var resp response @@ -327,12 +340,13 @@ func PullRequestsForBranch(client *Client, ghRepo Repo, branch string) ([]PullRe return nil, err } - prs := []PullRequest{} - for _, edge := range resp.Repository.PullRequests.Edges { - prs = append(prs, edge.Node) + for _, pr := range resp.Repository.PullRequests.Nodes { + if pr.HeadLabel() == branch { + return &pr, nil + } } - return prs, nil + return nil, fmt.Errorf("no open pull requests found for branch %q", branch) } func CreatePullRequest(client *Client, ghRepo Repo, params map[string]interface{}) (*PullRequest, error) { diff --git a/command/pr.go b/command/pr.go index ab1ad4ad5..64cd6b871 100644 --- a/command/pr.go +++ b/command/pr.go @@ -243,13 +243,11 @@ func prView(cmd *cobra.Command, args []string) error { return err } - prs, err := api.PullRequestsForBranch(apiClient, baseRepo, currentBranch) + pr, err := api.PullRequestForBranch(apiClient, baseRepo, currentBranch) if err != nil { return err - } else if len(prs) < 1 { - return fmt.Errorf("the '%s' branch has no open pull requests", currentBranch) } - openURL = prs[0].URL + openURL = pr.URL } fmt.Printf("Opening %s in your browser.\n", openURL) diff --git a/command/pr_test.go b/command/pr_test.go index 47851a5e8..24cc14735 100644 --- a/command/pr_test.go +++ b/command/pr_test.go @@ -22,7 +22,7 @@ func eq(t *testing.T, got interface{}, expected interface{}) { } func TestPRStatus(t *testing.T) { - initBlankContext("OWNER/REPO", "master") + initBlankContext("OWNER/REPO", "blueberries") http := initFakeHTTP() jsonFile, _ := os.Open("../test/fixtures/prStatus.json") @@ -100,7 +100,7 @@ func TestPRList_filtering(t *testing.T) { } func TestPRView(t *testing.T) { - initBlankContext("OWNER/REPO", "master") + initBlankContext("OWNER/REPO", "blueberries") http := initFakeHTTP() jsonFile, _ := os.Open("../test/fixtures/prView.json") @@ -148,7 +148,7 @@ func TestPRView_NoActiveBranch(t *testing.T) { defer restoreCmd() output, err := test.RunCommand(RootCmd, "pr view") - if err == nil || err.Error() != "the 'master' branch has no open pull requests" { + if err == nil || err.Error() != `no open pull requests found for branch "master"` { t.Errorf("error running command `pr view`: %v", err) } diff --git a/test/fixtures/prStatus.json b/test/fixtures/prStatus.json index 444fa5e01..f6cd8d1cd 100644 --- a/test/fixtures/prStatus.json +++ b/test/fixtures/prStatus.json @@ -7,7 +7,11 @@ "number": 10, "title": "Blueberries are a good fruit", "url": "https://github.com/github/gh-cli/pull/10", - "headRefName": "[blueberries]" + "headRefName": "blueberries", + "headRepositoryOwner": { + "login": "OWNER" + }, + "isCrossRepository": false } } ] @@ -20,7 +24,7 @@ "number": 8, "title": "Strawberries are not actually berries", "url": "https://github.com/github/gh-cli/pull/8", - "headRefName": "[strawberries]" + "headRefName": "strawberries" } } ], @@ -33,7 +37,7 @@ "number": 9, "title": "Apples are tasty", "url": "https://github.com/github/gh-cli/pull/9", - "headRefName": "[apples]" + "headRefName": "apples" } }, { @@ -41,7 +45,7 @@ "number": 11, "title": "Figs are my favorite", "url": "https://github.com/github/gh-cli/pull/1", - "headRefName": "[figs]" + "headRefName": "figs" } } ], diff --git a/test/fixtures/prView.json b/test/fixtures/prView.json index 5ac892498..c8ae23ce6 100644 --- a/test/fixtures/prView.json +++ b/test/fixtures/prView.json @@ -1,50 +1,30 @@ -{"data":{ - "repository": { - "pullRequests": { - "edges": [ - { - "node": { +{ + "data": { + "repository": { + "pullRequests": { + "nodes": [ + { + "number": 12, + "title": "Blueberries are from a fork", + "url": "https://github.com/OWNER/REPO/pull/12", + "headRefName": "blueberries", + "headRepositoryOwner": { + "login": "hubot" + }, + "isCrossRepository": true + }, + { "number": 10, "title": "Blueberries are a good fruit", "url": "https://github.com/OWNER/REPO/pull/10", - "headRefName": "[blueberries]" + "headRefName": "blueberries", + "headRepositoryOwner": { + "login": "OWNER" + }, + "isCrossRepository": false } - } - ] + ] + } } - }, - "viewerCreated": { - "edges": [ - { - "node": { - "number": 8, - "title": "Strawberries are not actually berries", - "url": "https://github.com/OWNER/REPO/pull/8", - "headRefName": "[strawberries]" - } - } - ], - "pageInfo": { "hasNextPage": false } - }, - "reviewRequested": { - "edges": [ - { - "node": { - "number": 9, - "title": "Apples are tasty", - "url": "https://github.com/OWNER/REPO/pull/9", - "headRefName": "[apples]" - } - }, - { - "node": { - "number": 11, - "title": "Figs are my favorite", - "url": "https://github.com/OWNER/REPO/pull/1", - "headRefName": "[figs]" - } - } - ], - "pageInfo": { "hasNextPage": false } } -}} \ No newline at end of file +} From eff8847513256d0730026e4a14a370838cc77bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 18 Nov 2019 23:47:22 +0100 Subject: [PATCH 2/4] Improve detecting PR for the current branch Now reads git branch configuration and handles these cases: branch ["foo"] remote origin merge refs/heads/bar branch ["foo"] remote other-remote merge refs/heads/foo branch ["foo"] remote https://github.com/OWNER/REPO.git merge refs/heads/bar branch ["foo"] remote origin merge refs/pull/123/head --- command/pr.go | 40 +++++++++++++++++++++++++++++++++---- command/pr_test.go | 50 ++++++++++++++++++++++++++++++++++++---------- context/remote.go | 9 +++++++++ git/git.go | 40 +++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 15 deletions(-) diff --git a/command/pr.go b/command/pr.go index 64cd6b871..f42411429 100644 --- a/command/pr.go +++ b/command/pr.go @@ -4,9 +4,12 @@ import ( "fmt" "os" "os/exec" + "regexp" "strconv" + "strings" "github.com/github/gh-cli/api" + "github.com/github/gh-cli/context" "github.com/github/gh-cli/git" "github.com/github/gh-cli/utils" "github.com/spf13/cobra" @@ -243,11 +246,40 @@ func prView(cmd *cobra.Command, args []string) error { return err } - pr, err := api.PullRequestForBranch(apiClient, baseRepo, currentBranch) - if err != nil { - return err + branchConfig := git.ReadBranchConfig(currentBranch) + prHeadRE := regexp.MustCompile(`^refs/pull/(\d+)/head$`) + if m := prHeadRE.FindStringSubmatch(branchConfig.MergeRef); m != nil { + openURL = fmt.Sprintf("https://github.com/%s/%s/pull/%s", baseRepo.RepoOwner(), baseRepo.RepoName(), m[1]) + } else { + branchWithOwner := currentBranch + var owner string + + if branchConfig.RemoteURL != nil { + if r, err := context.RepoFromURL(branchConfig.RemoteURL); err == nil { + owner = r.RepoOwner() + } + } else if branchConfig.RemoteName != "" { + rem, _ := ctx.Remotes() + if r, err := rem.FindByName(branchConfig.RemoteName); err == nil { + owner = r.RepoOwner() + } + } + + if owner != "" { + if strings.HasPrefix(branchConfig.MergeRef, "refs/heads/") { + branchWithOwner = strings.TrimPrefix(branchConfig.MergeRef, "refs/heads/") + } + if !strings.EqualFold(owner, baseRepo.RepoOwner()) { + branchWithOwner = fmt.Sprintf("%s:%s", owner, branchWithOwner) + } + } + + pr, err := api.PullRequestForBranch(apiClient, baseRepo, branchWithOwner) + if err != nil { + return err + } + openURL = pr.URL } - openURL = pr.URL } fmt.Printf("Opening %s in your browser.\n", openURL) diff --git a/command/pr_test.go b/command/pr_test.go index 24cc14735..84d91ce07 100644 --- a/command/pr_test.go +++ b/command/pr_test.go @@ -8,6 +8,7 @@ import ( "os/exec" "reflect" "regexp" + "strings" "testing" "github.com/github/gh-cli/test" @@ -99,7 +100,7 @@ func TestPRList_filtering(t *testing.T) { eq(t, reqBody.Variables.Labels, []string{"one", "two"}) } -func TestPRView(t *testing.T) { +func TestPRView_currentBranch(t *testing.T) { initBlankContext("OWNER/REPO", "blueberries") http := initFakeHTTP() @@ -109,8 +110,13 @@ func TestPRView(t *testing.T) { var seenCmd *exec.Cmd restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable { - seenCmd = cmd - return &outputStub{} + switch strings.Join(cmd.Args, " ") { + case `git config --get-regexp ^branch\.blueberries\.(remote|merge)$`: + return &outputStub{} + default: + seenCmd = cmd + return &outputStub{} + } }) defer restoreCmd() @@ -132,8 +138,8 @@ func TestPRView(t *testing.T) { } } -func TestPRView_NoActiveBranch(t *testing.T) { - initBlankContext("OWNER/REPO", "master") +func TestPRView_noResultsForBranch(t *testing.T) { + initBlankContext("OWNER/REPO", "blueberries") http := initFakeHTTP() jsonFile, _ := os.Open("../test/fixtures/prView_NoActiveBranch.json") @@ -142,22 +148,44 @@ func TestPRView_NoActiveBranch(t *testing.T) { var seenCmd *exec.Cmd restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable { - seenCmd = cmd - return &outputStub{} + switch strings.Join(cmd.Args, " ") { + case `git config --get-regexp ^branch\.blueberries\.(remote|merge)$`: + return &outputStub{} + default: + seenCmd = cmd + return &outputStub{} + } }) defer restoreCmd() - output, err := test.RunCommand(RootCmd, "pr view") - if err == nil || err.Error() != `no open pull requests found for branch "master"` { + _, err := test.RunCommand(RootCmd, "pr view") + if err == nil || err.Error() != `no open pull requests found for branch "blueberries"` { t.Errorf("error running command `pr view`: %v", err) } if seenCmd != nil { t.Fatalf("unexpected command: %v", seenCmd.Args) } +} - // Now run again but provide a PR number - output, err = test.RunCommand(RootCmd, "pr view 23") +func TestPRView_numberArg(t *testing.T) { + initBlankContext("OWNER/REPO", "master") + http := initFakeHTTP() + + http.StubResponse(200, bytes.NewBufferString(` + { "data": { "repository": { "pullRequest": { + "url": "https://github.com/OWNER/REPO/pull/23" + } } } } + `)) + + var seenCmd *exec.Cmd + restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable { + seenCmd = cmd + return &outputStub{} + }) + defer restoreCmd() + + output, err := test.RunCommand(RootCmd, "pr view 23") if err != nil { t.Errorf("error running command `pr view`: %v", err) } diff --git a/context/remote.go b/context/remote.go index 6c41eeaf1..a660a85cb 100644 --- a/context/remote.go +++ b/context/remote.go @@ -72,6 +72,15 @@ func translateRemotes(gitRemotes git.RemoteSet, urlTranslate func(*url.URL) *url return } +// RepoFromURL maps a URL to a GitHubRepository +func RepoFromURL(u *url.URL) (GitHubRepository, error) { + owner, repo, err := repoFromURL(u) + if err != nil { + return nil, err + } + return ghRepo{owner, repo}, nil +} + func repoFromURL(u *url.URL) (string, string, error) { if !strings.EqualFold(u.Hostname(), defaultHostname) { return "", "", fmt.Errorf("unsupported hostname: %s", u.Hostname()) diff --git a/git/git.go b/git/git.go index 8824872a4..b5eba2d59 100644 --- a/git/git.go +++ b/git/git.go @@ -4,9 +4,11 @@ import ( "bytes" "fmt" "io/ioutil" + "net/url" "os" "os/exec" "path/filepath" + "regexp" "strings" "github.com/github/gh-cli/utils" @@ -212,6 +214,44 @@ func Push(remote string, ref string) error { return cmd.Run() } +type BranchConfig struct { + RemoteName string + RemoteURL *url.URL + MergeRef string +} + +// ReadBranchConfig parses the `branch.BRANCH.(remote|merge)` part of git config +func ReadBranchConfig(branch string) (cfg BranchConfig) { + prefix := regexp.QuoteMeta(fmt.Sprintf("branch.%s.", branch)) + configCmd := GitCommand("config", "--get-regexp", fmt.Sprintf("^%s(remote|merge)$", prefix)) + output, err := utils.PrepareCmd(configCmd).Output() + if err != nil { + return + } + for _, line := range outputLines(output) { + parts := strings.SplitN(line, " ", 2) + if len(parts) < 2 { + continue + } + keys := strings.Split(parts[0], ".") + switch keys[len(keys)-1] { + case "remote": + if strings.Contains(parts[1], ":") { + u, err := ParseURL(parts[1]) + if err != nil { + continue + } + cfg.RemoteURL = u + } else { + cfg.RemoteName = parts[1] + } + case "merge": + cfg.MergeRef = parts[1] + } + } + return +} + func outputLines(output []byte) []string { lines := strings.TrimSuffix(string(output), "\n") return strings.Split(lines, "\n") From 3b4c9a530900643d5aa2a4f1fe7db645da3b8c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 2 Dec 2019 20:12:19 +0100 Subject: [PATCH 3/4] Extract finding selector for PR belonging to current branch --- command/pr.go | 81 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/command/pr.go b/command/pr.go index bd7931f09..e0715d639 100644 --- a/command/pr.go +++ b/command/pr.go @@ -220,41 +220,17 @@ func prView(cmd *cobra.Command, args []string) error { return fmt.Errorf("invalid pull request number: '%s'", args[0]) } } else { - apiClient, err := apiClientForContext(ctx) - if err != nil { - return err - } - currentBranch, err := ctx.Branch() + prNumber, branchWithOwner, err := prSelectorForCurrentBranch(ctx) if err != nil { return err } - branchConfig := git.ReadBranchConfig(currentBranch) - prHeadRE := regexp.MustCompile(`^refs/pull/(\d+)/head$`) - if m := prHeadRE.FindStringSubmatch(branchConfig.MergeRef); m != nil { - openURL = fmt.Sprintf("https://github.com/%s/%s/pull/%s", baseRepo.RepoOwner(), baseRepo.RepoName(), m[1]) + if prNumber > 0 { + openURL = fmt.Sprintf("https://github.com/%s/%s/pull/%d", baseRepo.RepoOwner(), baseRepo.RepoName(), prNumber) } else { - branchWithOwner := currentBranch - var owner string - - if branchConfig.RemoteURL != nil { - if r, err := context.RepoFromURL(branchConfig.RemoteURL); err == nil { - owner = r.RepoOwner() - } - } else if branchConfig.RemoteName != "" { - rem, _ := ctx.Remotes() - if r, err := rem.FindByName(branchConfig.RemoteName); err == nil { - owner = r.RepoOwner() - } - } - - if owner != "" { - if strings.HasPrefix(branchConfig.MergeRef, "refs/heads/") { - branchWithOwner = strings.TrimPrefix(branchConfig.MergeRef, "refs/heads/") - } - if !strings.EqualFold(owner, baseRepo.RepoOwner()) { - branchWithOwner = fmt.Sprintf("%s:%s", owner, branchWithOwner) - } + apiClient, err := apiClientForContext(ctx) + if err != nil { + return err } pr, err := api.PullRequestForBranch(apiClient, baseRepo, branchWithOwner) @@ -269,6 +245,51 @@ func prView(cmd *cobra.Command, args []string) error { return utils.OpenInBrowser(openURL) } +func prSelectorForCurrentBranch(ctx context.Context) (prNumber int, prHeadRef string, err error) { + baseRepo, err := ctx.BaseRepo() + if err != nil { + return + } + prHeadRef, err = ctx.Branch() + if err != nil { + return + } + branchConfig := git.ReadBranchConfig(prHeadRef) + + // the branch is configured to merge a special PR head ref + prHeadRE := regexp.MustCompile(`^refs/pull/(\d+)/head$`) + if m := prHeadRE.FindStringSubmatch(branchConfig.MergeRef); m != nil { + prNumber, _ = strconv.Atoi(m[1]) + return + } + + var branchOwner string + if branchConfig.RemoteURL != nil { + // the branch merges from a remote specified by URL + if r, err := context.RepoFromURL(branchConfig.RemoteURL); err == nil { + branchOwner = r.RepoOwner() + } + } else if branchConfig.RemoteName != "" { + // the branch merges from a remote specified by name + rem, _ := ctx.Remotes() + if r, err := rem.FindByName(branchConfig.RemoteName); err == nil { + branchOwner = r.RepoOwner() + } + } + + if branchOwner != "" { + if strings.HasPrefix(branchConfig.MergeRef, "refs/heads/") { + prHeadRef = strings.TrimPrefix(branchConfig.MergeRef, "refs/heads/") + } + // prepend `OWNER:` if this branch is pushed to a fork + if !strings.EqualFold(branchOwner, baseRepo.RepoOwner()) { + prHeadRef = fmt.Sprintf("%s:%s", branchOwner, prHeadRef) + } + } + + return +} + func prCheckout(cmd *cobra.Command, args []string) error { prNumber, err := strconv.Atoi(args[0]) if err != nil { From 3e06cfff0d5cb345ad4a33776c3f7eef81f5145c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 2 Dec 2019 20:40:14 +0100 Subject: [PATCH 4/4] Improve mapping current branch to a PR in `pr status` --- api/queries_pr.go | 60 +++++++++++++++++++++++++++++++---------------- command/pr.go | 6 ++--- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/api/queries_pr.go b/api/queries_pr.go index 83104db29..3eeae1cee 100644 --- a/api/queries_pr.go +++ b/api/queries_pr.go @@ -117,7 +117,7 @@ type Repo interface { RepoOwner() string } -func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername string) (*PullRequestsPayload, error) { +func PullRequests(client *Client, ghRepo Repo, currentPRNumber int, currentPRHeadRef, currentUsername string) (*PullRequestsPayload, error) { type edges struct { Edges []struct { Node PullRequest @@ -131,12 +131,13 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st type response struct { Repository struct { PullRequests edges + PullRequest *PullRequest } ViewerCreated edges ReviewRequested edges } - query := ` + fragments := ` fragment pr on PullRequest { number title @@ -170,16 +171,32 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st ...pr reviewDecision } - query($owner: String!, $repo: String!, $headRefName: String!, $viewerQuery: String!, $reviewerQuery: String!, $per_page: Int = 10) { - repository(owner: $owner, name: $repo) { - pullRequests(headRefName: $headRefName, states: OPEN, first: $per_page) { - edges { - node { - ...prWithReviews - } - } - } - } + ` + + queryPrefix := ` + query($owner: String!, $repo: String!, $headRefName: String!, $viewerQuery: String!, $reviewerQuery: String!, $per_page: Int = 10) { + repository(owner: $owner, name: $repo) { + pullRequests(headRefName: $headRefName, states: OPEN, first: $per_page) { + edges { + node { + ...prWithReviews + } + } + } + } + ` + if currentPRNumber > 0 { + queryPrefix = ` + query($owner: String!, $repo: String!, $number: Int!, $viewerQuery: String!, $reviewerQuery: String!, $per_page: Int = 10) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $number) { + ...prWithReviews + } + } + ` + } + + query := fragments + queryPrefix + ` viewerCreated: search(query: $viewerQuery, type: ISSUE, first: $per_page) { edges { node { @@ -201,7 +218,7 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st } } } - ` + ` owner := ghRepo.RepoOwner() repo := ghRepo.RepoName() @@ -209,9 +226,9 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st viewerQuery := fmt.Sprintf("repo:%s/%s state:open is:pr author:%s", owner, repo, currentUsername) reviewerQuery := fmt.Sprintf("repo:%s/%s state:open review-requested:%s", owner, repo, currentUsername) - branchWithoutOwner := currentBranch - if idx := strings.Index(currentBranch, ":"); idx >= 0 { - branchWithoutOwner = currentBranch[idx+1:] + branchWithoutOwner := currentPRHeadRef + if idx := strings.Index(currentPRHeadRef, ":"); idx >= 0 { + branchWithoutOwner = currentPRHeadRef[idx+1:] } variables := map[string]interface{}{ @@ -220,6 +237,7 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st "owner": owner, "repo": repo, "headRefName": branchWithoutOwner, + "number": currentPRNumber, } var resp response @@ -238,10 +256,12 @@ func PullRequests(client *Client, ghRepo Repo, currentBranch, currentUsername st reviewRequested = append(reviewRequested, edge.Node) } - var currentPR *PullRequest - for _, edge := range resp.Repository.PullRequests.Edges { - if edge.Node.HeadLabel() == currentBranch { - currentPR = &edge.Node + var currentPR = resp.Repository.PullRequest + if currentPR == nil { + for _, edge := range resp.Repository.PullRequests.Edges { + if edge.Node.HeadLabel() == currentPRHeadRef { + currentPR = &edge.Node + } } } diff --git a/command/pr.go b/command/pr.go index e0715d639..122fbbe9c 100644 --- a/command/pr.go +++ b/command/pr.go @@ -68,7 +68,7 @@ func prStatus(cmd *cobra.Command, args []string) error { if err != nil { return err } - currentBranch, err := ctx.Branch() + currentPRNumber, currentPRHeadRef, err := prSelectorForCurrentBranch(ctx) if err != nil { return err } @@ -77,7 +77,7 @@ func prStatus(cmd *cobra.Command, args []string) error { return err } - prPayload, err := api.PullRequests(apiClient, baseRepo, currentBranch, currentUser) + prPayload, err := api.PullRequests(apiClient, baseRepo, currentPRNumber, currentPRHeadRef, currentUser) if err != nil { return err } @@ -88,7 +88,7 @@ func prStatus(cmd *cobra.Command, args []string) error { if prPayload.CurrentPR != nil { printPrs(out, *prPayload.CurrentPR) } else { - message := fmt.Sprintf(" There is no pull request associated with %s", utils.Cyan("["+currentBranch+"]")) + message := fmt.Sprintf(" There is no pull request associated with %s", utils.Cyan("["+currentPRHeadRef+"]")) printMessage(out, message) } fmt.Fprintln(out)