You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(runway): reject changes that disagree on provider
## Summary
### Why?
The merger decides which provider a change came from by its URI scheme, and rejects a scheme it has no parser for. That part works, and it happens before any git command runs.
What it does not do is check that the changes in one request agree with each other. `resolveChange` determines the provider per URI and then discards it, so a request whose steps are addressed through different providers is resolved by different parsers and applied as though nothing were unusual. SubmitQueue already refuses that within a single change, but a Runway request carries one step per SubmitQueue request, so nothing covers the request as a whole.
### What?
Keeps `Provider` on `changeRef` — the scheme the change was addressed through — rather than parsing it and throwing it away.
`resolveAndValidate` now compares every change against the first and rejects a request that mixes providers, naming both and the steps they came from. It already walked every URI to validate it, and it runs before the mutex and before any git command, so an incoherent request costs nothing and leaves the checkout untouched.
This cannot refuse a legitimate request: there is no way to address one merge through two providers, and the apply paths would otherwise have to reason about changes resolved by different parsers.
Also names the change, not just the commit, in the unavailable-commit error, so the reader is not sent looking for a deleted commit when the likelier cause is a change this remote was never going to serve.
Whether a change belongs to the repository this merger serves is deliberately not checked. The merger is already constrained to its checkout and remote by configuration, and a change it cannot fetch is refused on those grounds.
## Test Plan
✅ `bazel test //runway/...` — all targets pass (git suite 70s)
✅ `make lint`, `make check-tidy`, `make check-gazelle`, `make test`
New cases: two steps using different providers, one change spanning two providers, and an unsupported provider — each asserted terminal and not a conflict. A multi-step multi-URI request through one provider is asserted to still succeed, guarding against over-rejecting.
The rejection cases run against a Merger whose git executable does not exist, so any git invocation would fail as an exec error. Getting `ErrInvalidRequest` back proves the request was refused before the merger reached for git.
Copy file name to clipboardExpand all lines: runway/extension/merger/git/README.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,14 @@ Every URI is reduced to three things: the commit to apply, the ref the provider
19
19
20
20
An unrecognized scheme is a terminal invalid request.
21
21
22
+
## What a request must agree on
23
+
24
+
The supported providers are a property of this merger, not of the queue or of the wire contract: the URI scheme selects the parser, and a scheme with no case is a terminal invalid request. Nothing upstream filters on it, so an unsupported provider is first refused here.
25
+
26
+
Beyond the scheme, every change in one request must come from the same provider. There is no sense in one merge being addressed through two of them, and the check runs before any git command, so an incoherent request costs nothing and leaves the checkout untouched.
27
+
28
+
Whether a change actually belongs to the repository this merger serves is not checked here — the merger is constrained to its checkout and remote by configuration, and a change it cannot fetch is refused on those grounds.
29
+
22
30
## Object availability
23
31
24
32
The default fetch refspec is `+refs/heads/*`, which does not cover a provider's change refs — a pull request head never also pushed as a branch, the normal case for a fork, is simply absent locally. Every referenced commit is therefore fetched and verified before any step is applied, so a request naming an unreachable commit fails without having touched the checkout.
0 commit comments