Skip to content

feat(stack): port stack push approvals decision to Rust#1536

Closed
jd wants to merge 1 commit into
devs/jd/feat/rust-stack-detect-change-type/port-revisionhistorycomment-rust--dbfde92bfrom
devs/jd/feat/rust-stack-detect-change-type/port-stack-push-approvals-decision-rust--57e70b92
Closed

feat(stack): port stack push approvals decision to Rust#1536
jd wants to merge 1 commit into
devs/jd/feat/rust-stack-detect-change-type/port-revisionhistorycomment-rust--dbfde92bfrom
devs/jd/feat/rust-stack-detect-change-type/port-stack-push-approvals-decision-rust--57e70b92

Conversation

@jd

@jd jd commented Jun 4, 2026

Copy link
Copy Markdown
Member

mergify stack push skips its trunk-rebase whenever any PR in
the stack is already approved — a rebase force-pushes every
branch in the stack and would dismiss the reviews. The exception:
when the bottom PR has a real merge conflict with trunk, the
rebase has to happen anyway so the conflict gets surfaced. Both
--skip-rebase and --force-rebase are absolute overrides.

Port mergify_cli/stack/approvals.py to
mergify-stack::approvals:

  • pull_is_approvedGET /repos/{u}/{r}/pulls/{n}/reviews
    with the same "latest review per reviewer wins" semantics as
    Python. A reviewer who once APPROVED and later requested
    changes counts as requested-changes; without that, a stale
    approve would falsely keep the PR in the approved set and a
    legitimate change request would get dismissed.
  • fetch_approved_pull_numbers — sequential fan-out across the
    stack's live PRs (same secondary-rate-limit trade-off as
    remote_changes).
  • bottom_pull_has_conflict — single GET with a 1s
    retry-once-on-null-mergeable to match GitHub's lazy mergeable
    computation. Any HTTP error coerces to false so a transient
    API hiccup can't force a surprise rebase.
  • decide_rebase — the orchestrator: precedence is
    skip_rebaseforce_rebase → approvals/conflict check.
    Returns a RebaseDecision with a typed RebaseReason enum
    for the CLI's "skipped because …" log line.

Coverage: 12 wiremock tests covering every branch of
decide_rebase plus the latest-review-wins semantics and the
HTTP-error coercion. Adds tokio (time feature only) and
url to mergify-stack's prod deps for the
mergeable-retry sleep and the wiremock test base-URL parse.

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

Depends-On: #1535

`mergify stack push` skips its trunk-rebase whenever any PR in
the stack is already approved — a rebase force-pushes every
branch in the stack and would dismiss the reviews. The exception:
when the bottom PR has a real merge conflict with trunk, the
rebase has to happen anyway so the conflict gets surfaced. Both
`--skip-rebase` and `--force-rebase` are absolute overrides.

Port `mergify_cli/stack/approvals.py` to
`mergify-stack::approvals`:

- `pull_is_approved` — `GET /repos/{u}/{r}/pulls/{n}/reviews`
  with the same "latest review per reviewer wins" semantics as
  Python. A reviewer who once APPROVED and later requested
  changes counts as requested-changes; without that, a stale
  approve would falsely keep the PR in the approved set and a
  legitimate change request would get dismissed.
- `fetch_approved_pull_numbers` — sequential fan-out across the
  stack's live PRs (same secondary-rate-limit trade-off as
  `remote_changes`).
- `bottom_pull_has_conflict` — single GET with a 1s
  retry-once-on-null-mergeable to match GitHub's lazy mergeable
  computation. Any HTTP error coerces to `false` so a transient
  API hiccup can't force a surprise rebase.
- `decide_rebase` — the orchestrator: precedence is
  `skip_rebase` → `force_rebase` → approvals/conflict check.
  Returns a `RebaseDecision` with a typed `RebaseReason` enum
  for the CLI's "skipped because …" log line.

Coverage: 12 wiremock tests covering every branch of
`decide_rebase` plus the latest-review-wins semantics and the
HTTP-error coercion. Adds `tokio` (time feature only) and
`url` to `mergify-stack`'s prod deps for the
mergeable-retry sleep and the wiremock test base-URL parse.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Change-Id: I57e70b924fd12d0f2d6b9b9a4935a9454b8d4644
@jd

jd commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

This pull request is part of a Mergify stack:

# Pull Request Link
1 feat(stack): port detect_change_type + patch-id helpers to Rust #1532
2 feat(stack): port StackComment renderer to Rust #1533
3 feat(stack): port replay git helpers (merge-tree + diff-tree) to Rust #1534
4 feat(stack): port RevisionHistoryComment to Rust #1535
5 feat(stack): port stack push approvals decision to Rust #1536 👈
6 feat(stack): port replay HTTP upload + orchestrator to Rust #1537
7 feat(stack): port stack push git plumbing (notes fetch + push) to Rust #1539
8 feat(stack): port stack push rebase log lines to Rust #1540
9 feat(stack): port format_pull_description + build_change_tasks to Rust #1541
10 feat(stack): port create_or_update_pr + orphan branch delete to Rust #1542
11 feat(stack): port per-PR stack + revision-history comment upserters to Rust #1543
12 feat(stack): port stack push planner (get_changes) to Rust #1544
13 feat(stack): port stack push orchestrator to Rust #1545
14 feat(rust): wire native stack push + delete Python push.py #1546
15 chore: delete Python tree + simplify wheel/CI for pure-Rust binary #1547

@mergify

mergify Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🔴 ⛓️ Depends-On Requirements

Waiting for

This rule is failing.

Requirement based on the presence of Depends-On in the body of the pull request

🔴 👀 Review Requirements

Waiting for

  • #approved-reviews-by>=2
This rule is failing.
  • any of:
    • #approved-reviews-by>=2
    • author = dependabot[bot]
    • author = mergify-ci-bot
    • author = renovate[bot]

🔴 🔎 Reviews

Waiting for

  • #review-requested = 0
This rule is failing.
  • #review-requested = 0
  • #changes-requested-reviews-by = 0
  • #review-threads-unresolved = 0

🟢 🤖 Continuous Integration

Wonderful, this rule succeeded.
  • all of:
    • check-success=ci-gate

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?:

🟢 📕 PR description

Wonderful, this rule succeeded.
  • body ~= (?ms:.{48,})

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant