Skip to content

hasBranch called with repository name (pr.base.name) instead of branch name (pr.base.ref) in reviewManager.ts #8668

@smit-p

Description

@smit-p

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions