Fix forge pr find-by-head / branch resolution returning the wrong PR #106

Merged
vnprc merged 1 commit from agent/fix-forge-find-by-head into master 2026-07-17 18:08:15 +01:00
Member

Fix forge pr find-by-head (and the shared branch→PR resolver) returning the wrong PR.

The Gitea/Forgejo pulls-list endpoint does not support a head query filter, so GET /repos/{repo}/pulls?state=open&head=<branch> silently ignored the filter and returned every open PR. Both pr_find_by_head and resolve_pr_target then took the first element, so they resolved any branch name to whichever open PR happened to sort first. With two or more open PRs in a repo this returns the wrong PR — forge pr find-by-head <branch> returns an unrelated PR, forge pr close <branch> / pr view <branch> could target the wrong PR, and allod change submit refuses to open a second concurrent PR in a repo (false "PR already exists").

Fix: drop the ignored head= query param and match .head.ref client-side in jq.

The test mock had faked server-side head= filtering (returning a hand-picked PR per head), which hid the bug. The mock now mirrors the real API — the open-PR list ignores head and returns all PRs — and its fixtures carry two PRs with distinct head refs. New regression cases assert find-by-head matches the correct (non-first) PR by head and returns nothing for an unmatched branch.

Risk

The forge change is limited to the two list-and-match spots; urlencode is unchanged and still used for other query params (milestone/label/search/branch-delete). Numeric and URL PR targets are untouched.

Validation

Full forge test suite passes (read, pr-close, mutations, validation, help, auth, token, issue-close). Verified against the live forge: the fixed forge pr find-by-head returns the PR whose head actually matches (and empty for an unknown branch), whereas the installed build returns whichever PR lists first regardless of the branch argument.

Fix `forge pr find-by-head` (and the shared branch→PR resolver) returning the wrong PR. The Gitea/Forgejo pulls-list endpoint does not support a `head` query filter, so `GET /repos/{repo}/pulls?state=open&head=<branch>` silently ignored the filter and returned every open PR. Both `pr_find_by_head` and `resolve_pr_target` then took the first element, so they resolved *any* branch name to whichever open PR happened to sort first. With two or more open PRs in a repo this returns the wrong PR — `forge pr find-by-head <branch>` returns an unrelated PR, `forge pr close <branch>` / `pr view <branch>` could target the wrong PR, and `allod change submit` refuses to open a second concurrent PR in a repo (false "PR already exists"). Fix: drop the ignored `head=` query param and match `.head.ref` client-side in jq. The test mock had faked server-side `head=` filtering (returning a hand-picked PR per head), which hid the bug. The mock now mirrors the real API — the open-PR list ignores head and returns all PRs — and its fixtures carry two PRs with distinct head refs. New regression cases assert `find-by-head` matches the correct (non-first) PR by head and returns nothing for an unmatched branch. ## Risk The `forge` change is limited to the two list-and-match spots; `urlencode` is unchanged and still used for other query params (milestone/label/search/branch-delete). Numeric and URL PR targets are untouched. ## Validation Full forge test suite passes (read, pr-close, mutations, validation, help, auth, token, issue-close). Verified against the live forge: the fixed `forge pr find-by-head` returns the PR whose head actually matches (and empty for an unknown branch), whereas the installed build returns whichever PR lists first regardless of the branch argument.
vnprc approved these changes 2026-07-17 18:08:10 +01:00
vnprc merged commit 7154edc137 into master 2026-07-17 18:08:15 +01:00
vnprc deleted branch agent/fix-forge-find-by-head 2026-07-17 18:08:15 +01:00
Sign in to join this conversation.
No description provided.