Skip to content

fix: ignore associated pull requests of other repositories - #1329

Open
aerodeval wants to merge 1 commit into
semantic-release:masterfrom
aerodeval:fix/associated-prs-other-repositories
Open

aerodeval wants to merge 1 commit into
semantic-release:masterfrom
aerodeval:fix/associated-prs-other-repositories

Conversation

@aerodeval

@aerodeval aerodeval commented Oct 29, 2026 •

Copy link
Copy Markdown

Problem

When a release is cut from a branch that is not the default branch (e.g. releases from main while develop is the default), the success step crashes and posts no comment at all:

HttpError: Not Found
GET /repos/frappe/helpdesk/pulls/66/commits

Root cause: the GraphQL field associatedPullRequests returns every pull request that contains the commit, including pull requests opened in other repositories. For commits on the default branch GitHub only returns the merged PR, but for commits on other branches it also returns open PRs from forks (for example a fork's pull[bot] sync PR fork-owner/fork#66). The plugin then calls GET /repos/<owner>/<repo>/pulls/66/commits on the released repository, where #66 is an unrelated issue, gets a 404, and the pFilter over all associated PRs rejects.

Verified with the GraphQL API on frappe/helpdesk commit c295efa8e: associatedPullRequests returns #66 (repository jango-blockchained/desk, a fork) next to #3882, #3897 and #3931 (repository frappe/helpdesk). This happens on every release while such a fork PR stays open.

Same bug as reported in #1032 and #1092. #1292 proposed the same approach but was closed by its author before review; this PR adds the regression test and the pagination fix below.

Fix

  • Request repository { nameWithOwner } for each associated PR and drop PRs whose repository is not the released one. The comparison uses the owner/repo the plugin already resolves via GET /repos/{owner}/{repo}, so renamed repositories keep working.
  • The filter runs before uniqBy(…, "number"), so a foreign PR can no longer shadow a same-numbered PR of this repository.
  • While touching the loop: the pagination branch for commits with more than 100 associated PRs referenced an undefined variable (response.commit.oid) and threw a ReferenceError. The per-commit pagination now lives in a small loadAllAssociatedPRs helper (while (pageInfo.hasNextPage)) that passes the commit's oid, which also removes the manual cursor/hasNextPage flags and the duplicated push site. The existing "multipaged associatedPRs" test never reached that branch because its second postOnce on the same URL used overwriteRoutes: true and replaced the first mock; it now matches on the query name and asserts the sha and cursor variables.
  • The PR field selection was copied in all three queries; it is now one prFields fragment, so repository cannot be present on page 1 but missing on page 2. The two flatten() calls on already-flat arrays are gone with it.

Note: the pagination path is live for the first time. On a heavily forked repository a non-default-branch commit can carry hundreds of fork PRs, which now means a few sequential 100-node pages per commit instead of a crash.

Edge cases considered

  • PRs opened from a fork into this repository have repository = this repository (only headRepository is the fork), so contributor PRs are still commented on. Filtering on headRepository would be wrong.
  • Same-repository PRs targeting non-default branches (e.g. backport PRs) are kept, as before.
  • Releasing from a fork (the Failure to get associated PRs for forked repo #1032 scenario): the upstream repository's PRs are now dropped, as they should be.
  • Renamed or transferred repositories: both sides of the comparison come from GitHub's canonical name.
  • Issues referenced in commit or PR bodies are unaffected; that path already filters on the owner/repo slug.

Tests

  • New test: a fork PR #66 is returned next to PR #1 of this repository; only #1 is looked up and commented on (no mock exists for #66, so any request for it fails the test).
  • "multipaged associatedPRs" test now exercises the second GraphQL query and the four PRs returned across both pages.

For commits that are not on the default branch, the GraphQL field
`associatedPullRequests` also returns pull requests opened in other
repositories, e.g. forks that sync from this one. Their numbers do not
exist in the released repository, so looking them up fails with a 404
and no success comment is posted at all.

Also pass the commit sha when loading more than 100 associated pull
requests of a commit (`response` was undefined) and make the multipaged
test exercise that path: its second mock replaced the first one. The PR
fields shared by the three queries are now one fragment, so a field
cannot be missing from one of them.

Fixes semantic-release#1032
Fixes semantic-release#1092
@aerodeval

aerodeval commented Oct 30, 2026 •

Copy link
Copy Markdown
Author

@babblebey @jedwards1211 please check this out, this has been long pending or tell me some other alternative to fix it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant