feat(stack): drop the Depends-On header once GitHub holds the stack - #1780
Conversation
Merge Protections🟢 All 6 merge protections satisfied — ready to merge. Show 6 satisfied protections🟢 🤖 Continuous Integration
🟢 👀 Review Requirements
🟢 Enforce conventional commitMake sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
🟢 🔎 Reviews
🟢 📕 PR description
🟢 🚦 Auto-queueWhen all merge protections are satisfied, this pull request will be queued automatically. |
There was a problem hiding this comment.
Pull request overview
This PR updates mergify stack push --github-native so that when a stack is successfully registered with GitHub’s native Stacks API (i.e., GitHub itself holds the ordering), the CLI no longer writes the redundant Depends-On: header into PR descriptions; if registration ends up not happening, the same push restores the suppressed headers to preserve Mergify’s ordering signal.
Changes:
- Suppress
Depends-On:rendering during PR upsert when--github-nativeis enabled, and restore suppressed markers if the stack ends the push unregistered. - Add
pr_upserthelpers to ensure restore renders from the same source used by the upsert (commit message vs existing PR body under--keep-pull-request-title-and-body). - Update CLI help/docs and extend end-to-end tests to cover header suppression vs restoration behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| skills/mergify-stack/SKILL.md | Documents --github-native behavior change re: Depends-On: and restoration. |
| crates/mergify-stack/src/pr_upsert.rs | Adds shared description source selection and a body-only PATCH helper to restore Depends-On:. |
| crates/mergify-stack/src/native_stack.rs | Expands module docs to explain why ordering markers are suppressed for registered stacks. |
| crates/mergify-stack/src/commands/push.rs | Implements suppression tracking and conditional restoration based on registration outcome. |
| crates/mergify-cli/tests/stack_push_github_native.rs | Adds tests asserting marker presence/absence under registered vs unregistered outcomes. |
| crates/mergify-cli/src/snapshots/mergify__tests__cli_schema_golden.snap | Updates CLI schema snapshot to reflect updated --github-native help text. |
| crates/mergify-cli/src/main.rs | Updates --github-native flag help text to mention ordering + Depends-On: removal. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Revision history
|
393df6b to
e0d7867
Compare
|
Pushed the review round:
|
|
The two red checks here are not from this diff. #1778 bumps Everything this PR owns is done: 19/21 checks green (including |
With `--github-native`, `mergify stack push` registers the stack with GitHub's Stacks API, and that registration *is* the dependency between two pull requests. The `Depends-On: #<n>` header the CLI writes on top of it records the same edge a second time, in the copy users actually read — so it is now left out. Keyed off the registration, never off the flag. `--github-native` degrades silently by design: `native_stack::register` returns `None` on a 404 (old GHES, feature off for the repo), a chain with a hole in it, or a stack below GitHub's 2-PR floor, and the push carries on as an ordinary Mergify stack. Dropping the header on the flag alone would leave those pushes with the edge recorded nowhere at all, and Mergify reconstructs a stack from `Depends-On` chains (`engine/stacks/detection.py`) — a mid-stack pull request would lose the gate holding it behind its predecessor. Registration happens after the bodies are written, so the removal is optimistic and settled inside the same push: every header the upsert skips is remembered, and `pr_upsert::restore_depends_on` writes it back (body only, no `base` key) if the stack ends the push unregistered. That path is fatal on failure — every other way this feature degrades lands in the state a flag-off push produces, and a stack that is neither registered nor chained would not. Nothing writes `Depends-On` into a commit; it only ever existed in the rendered PR description, so no commit message changes shape. What still reads the header, checked against the engine rather than assumed: - `stacks/detection.py` walks CLI stacks by branch chain **and** the marker; its native counterpart `stacks/github_native.py` walks the mirrored `stack` object instead, and `get_stack_predecessor_state` unions the two. The native half is behind `GITHUB_STACK_QUEUE_FOR_ORGS`, but an org without that flag cannot merge a registered stack at all — `merge_helpers` keeps it off the merge-async path and GitHub 403s the classic endpoint for every member — so the marker there gates a merge that cannot happen. - The queue's `build_stack_groups` and `find_direct_open_successors_by_head_ref` use head/base refs only. - The browser extension reads its own `mergify-stack-data` comment. - The stacks-analytics endpoint detects stack PRs by `Change-Id` (which we still write); only its bottom-vs-upper first-review split reads the marker, so native stacks will read as all-bottom there. Metrics skew on an opt-in flag, not a merge regression — worth its own fix. MRGFY-8772 Change-Id: Ia15a76dec74d7799bf891ab5c0d14211aba2bb9e
e0d7867 to
9ed18bb
Compare
|
Rebased onto #1778 landed, so
|
Merge Queue Status
This pull request spent 7 minutes in the queue, including 6 minutes 39 seconds running CI. Required conditions to merge
|
With
--github-native,mergify stack pushregisters the stack withGitHub's Stacks API, and that registration is the dependency between
two pull requests. The
<n>header the CLI writes on topof it records the same edge a second time, in the copy users actually
read — so it is now left out.
Keyed off the registration, never off the flag.
--github-nativedegrades silently by design:
native_stack::registerreturnsNoneona 404 (old GHES, feature off for the repo), a chain with a hole in it,
or a stack below GitHub's 2-PR floor, and the push carries on as an
ordinary Mergify stack. Dropping the header on the flag alone would
leave those pushes with the edge recorded nowhere at all, and Mergify
reconstructs a stack from
Depends-Onchains(
engine/stacks/detection.py) — a mid-stack pull request would losethe gate holding it behind its predecessor.
Registration happens after the bodies are written, so the removal is
optimistic and settled inside the same push: every header the upsert
skips is remembered, and
pr_upsert::restore_depends_onwrites it back(body only, no
basekey) if the stack ends the push unregistered.That path is fatal on failure — every other way this feature degrades
lands in the state a flag-off push produces, and a stack that is
neither registered nor chained would not.
Nothing writes
Depends-Oninto a commit; it only ever existed in therendered PR description, so no commit message changes shape.
What still reads the header, checked against the engine rather than
assumed:
stacks/detection.pywalks CLI stacks by branch chain and themarker; its native counterpart
stacks/github_native.pywalks themirrored
stackobject instead, andget_stack_predecessor_stateunions the two. The native half is behind
GITHUB_STACK_QUEUE_FOR_ORGS, but an org without that flag cannotmerge a registered stack at all —
merge_helperskeeps it off themerge-async path and GitHub 403s the classic endpoint for every
member — so the marker there gates a merge that cannot happen.
build_stack_groupsandfind_direct_open_successors_by_head_refuse head/base refs only.mergify-stack-datacomment.Change-Id(whichwe still write); only its bottom-vs-upper first-review split reads
the marker, so native stacks will read as all-bottom there. Metrics
skew on an opt-in flag, not a merge regression — worth its own fix.
MRGFY-8772