feat(runway): resolve merge targets per queue and provision their checkouts - #544
Merged
Conversation
This was referenced Aug 7, 2026
behinddwalls
marked this pull request as ready for review
August 7, 2026 18:23
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 7, 2026 18:36
46d6ad4 to
b976f26
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 7, 2026 21:21
b976f26 to
d7ebb8b
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 7, 2026 22:05
d7ebb8b to
33afcf6
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 7, 2026 22:20
33afcf6 to
ed99818
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 7, 2026 23:24
ed99818 to
d1274fe
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 11, 2026 21:06
d1274fe to
34be0c1
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 11, 2026 22:39
34be0c1 to
4a9fc63
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 11, 2026 22:52
4a9fc63 to
5abb77f
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
2 times, most recently
from
August 12, 2026 05:47
9350959 to
8ddf806
Compare
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 12, 2026 19:04
8ddf806 to
543fb1e
Compare
mnoah1
approved these changes
Aug 12, 2026
mnoah1
left a comment
Contributor
There was a problem hiding this comment.
Approving - comment below seems like an edge case we may want to consider.
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
2 times, most recently
from
August 12, 2026 20:47
123dfdb to
9e5bb3b
Compare
…ckouts ## Summary ### Why? Three things stopped Runway from performing a real merge. It resolved one merger for the whole process, so a deployment could serve only one repository. Nothing created the checkout the git merger requires, which it declares must already exist. And the container had no `git` binary, while the merger demanded three absolute runtime paths — so enabling it failed at startup with `git runtime executable is required` rather than working. ### What? Merge targets come from `MERGE_CONFIG_PATH`, a YAML file with a `defaults` block and per-queue overrides. Each git target is provisioned at startup — repository initialised, remote configured, credential written, target branch checked out — idempotently, so a restart against a persisted volume costs nothing and a rotated token takes effect. The existing `MERGE_*` environment variables still configure a single target when no file is given. Two queues naming one checkout resolve to the *same* merger instance, which is what serializes them: a git merger locks the working tree it owns, and two instances over one tree would reset it out from under each other mid-merge. That instance is built from whichever queue is reached first, so queues sharing a checkout have to agree on every field it is built from — not merely on the target. Any disagreement is rejected at startup, naming the field, because the alternative is a queue that asked for `SQUASH_REBASE` quietly merging with `REBASE` and reporting nothing. The comparison is structural rather than a list of fields to remember, so a field added to the merger later is covered on its own. The credential never enters the remote URL. The merger folds git's stderr into the errors it returns, so a URL-embedded token would be reprinted into logs and dead-letter payloads by any failed fetch. It is written as an HTTP `Authorization` header into a `0600` config fragment the repository includes — which keeps it off the command line too. SSH needs no code at all: the merger already passes `SSH_AUTH_SOCK` and `GIT_SSH_COMMAND` through its scrubbed environment. The git runtime is derived from the installed git when unset — executable from `PATH`, exec path from `git --exec-path`, templates from the matching install prefix — so the pinning safeguard stops being a boot-time trap. `git` is installed in the image. ## Test Plan ✅ `bazel test //service/runway/server:go_default_test` — provisioning runs against real git (pinned, as the merger does): clone into an empty directory, idempotent re-run, drifted remote URL corrected, non-default target branch, credential written `0600` and absent from the remote URL, stale fragment removed, unset token rejected, and git-runtime derivation with and without the environment overrides. ✅ Sharing a checkout is now judged on the whole merger configuration, not just the target: two queues that agree everywhere still share one instance, two that disagree in `defaultStrategy`, `updateHeadBranch`, `checkStaleness`, `maxPushAttempts`, the committer identity or the refspecs are rejected at load, and a queue spelling a default explicitly still counts as agreeing.
behinddwalls
force-pushed
the
sq/runway-merge-targets
branch
from
August 12, 2026 21:29
9e5bb3b to
3347419
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why?
Three things stopped Runway from performing a real merge. It resolved one merger for the whole process, so a deployment could serve only one repository. Nothing created the checkout the git merger requires, which it declares must already exist. And the container had no
gitbinary, while the merger demanded three absolute runtime paths — so enabling it failed at startup withgit runtime executable is requiredrather than working.What?
Merge targets come from
MERGE_CONFIG_PATH, a YAML file with adefaultsblock and per-queue overrides. Each git target is provisioned at startup — repository initialised, remote configured, credential written, target branch checked out — idempotently, so a restart against a persisted volume costs nothing and a rotated token takes effect. The existingMERGE_*environment variables still configure a single target when no file is given.Two queues naming one checkout resolve to the same merger instance, which is what serializes them: a git merger locks the working tree it owns, and two instances over one tree would reset it out from under each other mid-merge. That instance is built from whichever queue is reached first, so queues sharing a checkout have to agree on every field it is built from — not merely on the target. Any disagreement is rejected at startup, naming the field, because the alternative is a queue that asked for
SQUASH_REBASEquietly merging withREBASEand reporting nothing. The comparison is structural rather than a list of fields to remember, so a field added to the merger later is covered on its own.The credential never enters the remote URL. The merger folds git's stderr into the errors it returns, so a URL-embedded token would be reprinted into logs and dead-letter payloads by any failed fetch. It is written as an HTTP
Authorizationheader into a0600config fragment the repository includes — which keeps it off the command line too. SSH needs no code at all: the merger already passesSSH_AUTH_SOCKandGIT_SSH_COMMANDthrough its scrubbed environment.The git runtime is derived from the installed git when unset — executable from
PATH, exec path fromgit --exec-path, templates from the matching install prefix — so the pinning safeguard stops being a boot-time trap.gitis installed in the image.Test Plan
✅
bazel test //service/runway/server:go_default_test— provisioning runs against real git (pinned, as the merger does): clone into an empty directory, idempotent re-run, drifted remote URL corrected, non-default target branch, credential written0600and absent from the remote URL, stale fragment removed, unset token rejected, and git-runtime derivation with and without the environment overrides.✅ Sharing a checkout is now judged on the whole merger configuration, not just the target: two queues that agree everywhere still share one instance, two that disagree in
defaultStrategy,updateHeadBranch,checkStaleness,maxPushAttempts, the committer identity or the refspecs are rejected at load, and a queue spelling a default explicitly still counts as agreeing.