Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions acceptance/testdata/pr/pr-view-same-org-fork.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Setup environment variables used for testscript
env REPO=${SCRIPT_NAME}-${RANDOM_STRING}
env FORK=${REPO}-fork

# Use gh as a credential helper
exec gh auth setup-git

# Create a repository to act as upstream with a file so it has a default branch
exec gh repo create ${ORG}/${REPO} --add-readme --private

# Defer repo cleanup of upstream
defer gh repo delete --yes ${ORG}/${REPO}
exec gh repo view ${ORG}/${REPO} --json id --jq '.id'
stdout2env REPO_ID

# Create a fork in the same org
exec gh repo fork ${ORG}/${REPO} --org ${ORG} --fork-name ${FORK}

# Defer repo cleanup of fork
defer gh repo delete --yes ${ORG}/${FORK}
sleep 1
exec gh repo view ${ORG}/${FORK} --json id --jq '.id'
stdout2env FORK_ID

# Clone the fork
exec gh repo clone ${ORG}/${FORK}
cd ${FORK}

# Prepare a branch
exec git checkout -b feature-branch
exec git commit --allow-empty -m 'Empty Commit'
exec git push -u origin feature-branch

# Create the PR spanning upstream and fork repositories, gh pr create does not support headRepositoryId needed for private forks
exec gh api graphql -F repositoryId="${REPO_ID}" -F headRepositoryId="${FORK_ID}" -F query='mutation CreatePullRequest($headRepositoryId: ID!, $repositoryId: ID!) { createPullRequest(input:{ baseRefName: "main", body: "Feature Body", draft: false, headRefName: "feature-branch", headRepositoryId: $headRepositoryId, repositoryId: $repositoryId, title:"Feature Title" }){ pullRequest{ id url } } }'

# View the PR
exec gh pr view
stdout 'Feature Title'
29 changes: 22 additions & 7 deletions pkg/cmd/pr/shared/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,27 +246,36 @@ func (f *finder) parseCurrentBranch() (string, int, error) {
return "", prNumber, nil
}

var branchOwner string
var gitRemoteRepo ghrepo.Interface
if branchConfig.RemoteURL != nil {
// the branch merges from a remote specified by URL
if r, err := ghrepo.FromURL(branchConfig.RemoteURL); err == nil {
branchOwner = r.RepoOwner()
gitRemoteRepo = r
}
} else if branchConfig.RemoteName != "" {
// the branch merges from a remote specified by name
rem, _ := f.remotesFn()
if r, err := rem.FindByName(branchConfig.RemoteName); err == nil {
branchOwner = r.RepoOwner()
gitRemoteRepo = r
}
}

if branchOwner != "" {
if gitRemoteRepo != nil {
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, f.repo.RepoOwner()) {
prHeadRef = fmt.Sprintf("%s:%s", branchOwner, prHeadRef)
// This is determined by:
// - The repo having a different owner
// - The repo having the same owner but a different name (private org fork)
// I suspect that the implementation of the second case may be broken in the face
// of a repo rename, where the remote hasn't been updated locally. This is a
// frequent issue in commands that use SmartBaseRepoFunc. It's not any worse than not
// supporting this case at all though.
sameOwner := strings.EqualFold(gitRemoteRepo.RepoOwner(), f.repo.RepoOwner())
sameOwnerDifferentRepoName := sameOwner && !strings.EqualFold(gitRemoteRepo.RepoName(), f.repo.RepoName())
if !sameOwner || sameOwnerDifferentRepoName {
prHeadRef = fmt.Sprintf("%s:%s", gitRemoteRepo.RepoOwner(), prHeadRef)
}
}

Expand Down Expand Up @@ -355,7 +364,13 @@ func findForBranch(httpClient *http.Client, repo ghrepo.Interface, baseBranch, h
})

for _, pr := range prs {
if pr.HeadLabel() == headBranch && (baseBranch == "" || pr.BaseRefName == baseBranch) && (pr.State == "OPEN" || resp.Repository.DefaultBranchRef.Name != headBranch) {
headBranchMatches := pr.HeadLabel() == headBranch
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change of logic here, just trying to give some words to this conditional.

baseBranchEmptyOrMatches := baseBranch == "" || pr.BaseRefName == baseBranch
// When the head is the default branch, it doesn't really make sense to show merged or closed PRs.
// https://github.com/cli/cli/issues/4263
isNotClosedOrMergedWhenHeadIsDefault := pr.State == "OPEN" || resp.Repository.DefaultBranchRef.Name != headBranch

if headBranchMatches && baseBranchEmptyOrMatches && isNotClosedOrMergedWhenHeadIsDefault {
return &pr, nil
}
}
Expand Down
43 changes: 42 additions & 1 deletion pkg/cmd/pr/shared/finder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ func TestFind(t *testing.T) {
wantRepo: "https://github.com/OWNER/REPO",
},
{
name: "current branch with upstream configuration",
name: "current branch with upstream RemoteURL configuration",
args: args{
selector: "",
fields: []string{"id", "number"},
Expand Down Expand Up @@ -384,6 +384,47 @@ func TestFind(t *testing.T) {
wantPR: 13,
wantRepo: "https://github.com/OWNER/REPO",
},
{
name: "current branch with upstream and fork in same org",
args: args{
selector: "",
fields: []string{"id", "number"},
baseRepoFn: func() (ghrepo.Interface, error) {
return ghrepo.FromFullName("OWNER/REPO")
},
branchFn: func() (string, error) {
return "blueberries", nil
},
branchConfig: func(branch string) (c git.BranchConfig) {
c.RemoteName = "origin"
return
},
remotesFn: func() (context.Remotes, error) {
return context.Remotes{{
Remote: &git.Remote{Name: "origin"},
Repo: ghrepo.New("OWNER", "REPO-FORK"),
}}, nil
},
},
httpStub: func(r *httpmock.Registry) {
r.Register(
httpmock.GraphQL(`query PullRequestForBranch\b`),
httpmock.StringResponse(`{"data":{"repository":{
"pullRequests":{"nodes":[
{
"number": 13,
"state": "OPEN",
"baseRefName": "main",
"headRefName": "blueberries",
"isCrossRepository": true,
"headRepositoryOwner": {"login":"OWNER"}
}
]}
}}}`))
},
wantPR: 13,
wantRepo: "https://github.com/OWNER/REPO",
},
{
name: "current branch made by pr checkout",
args: args{
Expand Down