Bug Description
In src/view/reviewManager.ts, the resolvePullRequest method calls hasBranch(pr.base.name) to verify a pull request's base branch exists. However, pr.base is a GitHubRef where:
.ref = the branch name (e.g., "main")
.name = the repository name (e.g., "vscode-pull-request-github")
This means hasBranch() receives the repository name instead of the branch name, and queries refs/heads/<repo-name> — which will never match an actual branch (unless the repo name happens to coincide with a branch name).
Location
src/view/reviewManager.ts in resolvePullRequest():
https://github.com/microsoft/vscode-pull-request-github/blob/main/src/view/reviewManager.ts
let pr = await this._folderRepoManager.resolvePullRequest(owner, repositoryName, metadata.prNumber, useCache);
if (!pr || !pr.isResolved() || !(await pr.githubRepository.hasBranch(pr.base.name))) {
await this.clear(true);
this._prNumber = undefined;
Logger.appendLine('This PR is no longer valid', this.id);
return;
}
Root Cause
In src/github/pullRequestModel.ts, the doUpdate() method constructs GitHubRef objects:
if (item.base) {
this.base = new GitHubRef(item.base.ref, item.base!.label, item.base!.sha,
item.base!.repo.cloneUrl, item.base.repo.owner, item.base.repo.name,
item.base.repo.isInOrganization);
}
The GitHubRef constructor signature maps:
- 1st param (
item.base.ref) → this.ref (branch name)
- 6th param (
item.base.repo.name) → this.name (repository name)
So pr.base.ref is the branch name, but pr.base.name is the repository name. The call site in reviewManager.ts uses .name when it should use .ref.
Impact
The actual impact depends on which data path populates pr.base:
REST API path (convertRESTHeadToIGitHubRef in utils.ts): pr.base.name is correctly set to the repository name (e.g., "vscode-pull-request-github"). In this case, hasBranch() queries refs/heads/vscode-pull-request-github, which will never match an actual branch. This causes resolvePullRequest() to clear state and log "This PR is no longer valid" even when the PR and its base branch are perfectly valid, breaking review mode activation.
GraphQL path (parseRef in utils.ts): This path has a separate bug — parseRef sets repo.name = refName, where refName is the branch name, not the repository name. So pr.base.name accidentally equals the branch name, and hasBranch(pr.base.name) happens to work by coincidence. This masks the reviewManager.ts bug on this path, but pr.base.name is still semantically wrong (it's supposed to be the repo name per GitHubRef's contract).
The fix (.ref instead of .name) is correct for both paths.
Related: parseRef bug in utils.ts
While investigating, I found that parseRef in src/github/utils.ts has its own latent bug: it sets repo.name to the branch name instead of the repository name. This violates the GitHubRef contract where .name should be the repo name. It currently doesn't cause visible breakage because no code path reads .name from a parseRef-constructed GitHubRef expecting the repo name (other than this hasBranch call, where the error cancels out). But it is a correctness issue that could cause subtle bugs if .name is relied upon in the future.
Suggested Fix
- if (!pr || !pr.isResolved() || !(await pr.githubRepository.hasBranch(pr.base.name))) {
+ if (!pr || !pr.isResolved() || !(await pr.githubRepository.hasBranch(pr.base.ref))) {
Version
Observed in v0.132.2.
Bug Description
In
src/view/reviewManager.ts, theresolvePullRequestmethod callshasBranch(pr.base.name)to verify a pull request's base branch exists. However,pr.baseis aGitHubRefwhere:.ref= the branch name (e.g.,"main").name= the repository name (e.g.,"vscode-pull-request-github")This means
hasBranch()receives the repository name instead of the branch name, and queriesrefs/heads/<repo-name>— which will never match an actual branch (unless the repo name happens to coincide with a branch name).Location
src/view/reviewManager.tsinresolvePullRequest():https://github.com/microsoft/vscode-pull-request-github/blob/main/src/view/reviewManager.ts
Root Cause
In
src/github/pullRequestModel.ts, thedoUpdate()method constructsGitHubRefobjects:The
GitHubRefconstructor signature maps:item.base.ref) →this.ref(branch name)item.base.repo.name) →this.name(repository name)So
pr.base.refis the branch name, butpr.base.nameis the repository name. The call site inreviewManager.tsuses.namewhen it should use.ref.Impact
The actual impact depends on which data path populates
pr.base:REST API path (
convertRESTHeadToIGitHubRefinutils.ts):pr.base.nameis correctly set to the repository name (e.g.,"vscode-pull-request-github"). In this case,hasBranch()queriesrefs/heads/vscode-pull-request-github, which will never match an actual branch. This causesresolvePullRequest()to clear state and log"This PR is no longer valid"even when the PR and its base branch are perfectly valid, breaking review mode activation.GraphQL path (
parseRefinutils.ts): This path has a separate bug —parseRefsetsrepo.name = refName, whererefNameis the branch name, not the repository name. Sopr.base.nameaccidentally equals the branch name, andhasBranch(pr.base.name)happens to work by coincidence. This masks thereviewManager.tsbug on this path, butpr.base.nameis still semantically wrong (it's supposed to be the repo name perGitHubRef's contract).The fix (
.refinstead of.name) is correct for both paths.Related:
parseRefbug inutils.tsWhile investigating, I found that
parseRefinsrc/github/utils.tshas its own latent bug: it setsrepo.nameto the branch name instead of the repository name. This violates theGitHubRefcontract where.nameshould be the repo name. It currently doesn't cause visible breakage because no code path reads.namefrom aparseRef-constructedGitHubRefexpecting the repo name (other than thishasBranchcall, where the error cancels out). But it is a correctness issue that could cause subtle bugs if.nameis relied upon in the future.Suggested Fix
Version
Observed in v0.132.2.