Skip to content

feat(rust): port stack list + stack open to native Rust#1524

Draft
jd wants to merge 1 commit into
devs/jd/feat/rust-stack-new/port-stack-sync-native-rust--7f75be87from
devs/jd/feat/rust-stack-new/port-stack-list-stack-open-native-rust--0a12ccb2
Draft

feat(rust): port stack list + stack open to native Rust#1524
jd wants to merge 1 commit into
devs/jd/feat/rust-stack-new/port-stack-sync-native-rust--7f75be87from
devs/jd/feat/rust-stack-new/port-stack-list-stack-open-native-rust--0a12ccb2

Conversation

@jd
Copy link
Copy Markdown
Member

@jd jd commented Jun 3, 2026

The Rust binary now serves mergify stack list [--json] [--verbose] and mergify stack open [<commit>] natively.
The Python implementations
(mergify_cli/stack/list.py,
mergify_cli/stack/list_schema.py,
mergify_cli/stack/open.py, the click registrations, and
test_{list,open}.py) are removed.

New shared infrastructure that the remaining slices
(stack push) will reuse:

  • mergify_stack::changes::classify — full per-commit
    classifier that buckets each local commit as
    Create / Update / SkipMerged / SkipUpToDate,
    the same shape Python's get_changes returns. Also
    surfaces orphan PRs (open remote changes that don't match
    any local commit). The merged-vs-remaining sync_status
    module stays for stack sync since sync only needs the
    bucket; the full classifier here is what list, open,
    and push need.

  • StackContext + resolve_stack_context in the binary
    — bundles token / GitHub server / repo slug / author /
    branch prefix / trunk resolution that every API-backed stack
    subcommand runs. checkout and sync will pick this up
    in a follow-up cleanup; for now they keep their inline
    copies.

mergify stack list:

  1. Runs the shared stack-context preamble.
  2. Walks the local stack via local_commits::read, fetches
    the matching remote PRs via remote_changes::get_remote_changes,
    classifies via changes::classify.
  3. For each entry, computes the display status
    (open / draft / merged / no_pr) from the
    classifier's action plus the PR's merged_at / draft
    fields.
  4. Optionally fans out per-PR /check-runs and /reviews
    fetches and folds them into the entry's ci_* / review_*
    fields. Sequential (not concurrent) — GitHub's secondary
    rate limit on the same endpoint pool starts firing around
    ~80 concurrent calls, and a typical stack is well under
    that. stack open passes include_status=false to
    skip this.
  5. Renders either JSON (serde_json::to_string_pretty of
    StackListOutput, byte-compatible with the pre-port
    --json output) or a plain-text table.

mergify stack open:

  1. Runs stack::list with include_status=false.
  2. None commit → leaf entry (the Python interactive picker
    defaulted there too; we leave the picker out of the port for
    now).
  3. Explicit commit → git rev-parse --verify then look up
    the matching StackListEntry.
  4. Hand the html_url to the OS opener: open (macOS),
    xdg-open (other Unix), cmd /C start "" (Windows).
  5. PR-less commits surface StackNotFound with a hint to
    run stack push first.

Coverage: 7 changes::tests for the classifier (create /
skip-merged / amended-after-merge / skip-up-to-date / update /
orphan / closed-unmatched), 6 commands::list::tests for
the CI / review status reducers (passing / failing-over-pending
/ pending / approved / changes-requested / pending-from-comments).

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

Depends-On: #1523

The Rust binary now serves ``mergify stack list [--json]
[--verbose]`` and ``mergify stack open [<commit>]`` natively.
The Python implementations
(``mergify_cli/stack/list.py``,
``mergify_cli/stack/list_schema.py``,
``mergify_cli/stack/open.py``, the click registrations, and
``test_{list,open}.py``) are removed.

New shared infrastructure that the remaining slices
(``stack push``) will reuse:

- ``mergify_stack::changes::classify`` — full per-commit
  classifier that buckets each local commit as
  ``Create`` / ``Update`` / ``SkipMerged`` / ``SkipUpToDate``,
  the same shape Python's ``get_changes`` returns. Also
  surfaces orphan PRs (open remote changes that don't match
  any local commit). The merged-vs-remaining ``sync_status``
  module stays for ``stack sync`` since sync only needs the
  bucket; the full classifier here is what ``list``, ``open``,
  and ``push`` need.

- ``StackContext`` + ``resolve_stack_context`` in the binary
  — bundles token / GitHub server / repo slug / author /
  branch prefix / trunk resolution that every API-backed stack
  subcommand runs. ``checkout`` and ``sync`` will pick this up
  in a follow-up cleanup; for now they keep their inline
  copies.

``mergify stack list``:

1. Runs the shared stack-context preamble.
2. Walks the local stack via ``local_commits::read``, fetches
   the matching remote PRs via ``remote_changes::get_remote_changes``,
   classifies via ``changes::classify``.
3. For each entry, computes the display status
   (``open`` / ``draft`` / ``merged`` / ``no_pr``) from the
   classifier's action plus the PR's ``merged_at`` / ``draft``
   fields.
4. Optionally fans out per-PR ``/check-runs`` and ``/reviews``
   fetches and folds them into the entry's ``ci_*`` / ``review_*``
   fields. Sequential (not concurrent) — GitHub's secondary
   rate limit on the same endpoint pool starts firing around
   ~80 concurrent calls, and a typical stack is well under
   that. ``stack open`` passes ``include_status=false`` to
   skip this.
5. Renders either JSON (``serde_json::to_string_pretty`` of
   ``StackListOutput``, byte-compatible with the pre-port
   ``--json`` output) or a plain-text table.

``mergify stack open``:

1. Runs ``stack::list`` with ``include_status=false``.
2. ``None`` commit → leaf entry (the Python interactive picker
   defaulted there too; we leave the picker out of the port for
   now).
3. Explicit commit → ``git rev-parse --verify`` then look up
   the matching ``StackListEntry``.
4. Hand the ``html_url`` to the OS opener: ``open`` (macOS),
   ``xdg-open`` (other Unix), ``cmd /C start ""`` (Windows).
5. PR-less commits surface ``StackNotFound`` with a hint to
   run ``stack push`` first.

Coverage: 7 ``changes::tests`` for the classifier (create /
skip-merged / amended-after-merge / skip-up-to-date / update /
orphan / closed-unmatched), 6 ``commands::list::tests`` for
the CI / review status reducers (passing / failing-over-pending
/ pending / approved / changes-requested / pending-from-comments).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Change-Id: I0a12ccb23061dceba00b94cbddf93df388452657
@jd
Copy link
Copy Markdown
Member Author

jd commented Jun 3, 2026

This pull request is part of a Mergify stack:

# Pull Request Link
1 feat(rust): port stack note to native Rust #1515
2 feat(rust): port stack edit + add rebase-todo machinery #1516
3 feat(rust): port stack drop to native Rust #1517
4 feat(rust): port stack fixup to native Rust #1518
5 feat(rust): port stack reword to native Rust #1519
6 feat(rust): port stack reorder + stack move to native Rust #1520
7 feat(rust): port stack squash to native Rust #1521
8 feat(rust): port stack checkout to native Rust #1522
9 feat(rust): port stack sync to native Rust #1523
10 feat(rust): port stack list + stack open to native Rust #1524 👈

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Jun 3, 2026

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

🔴 🤖 Continuous Integration

Waiting for

  • check-success=ci-gate
This rule is failing.
  • all of:
    • check-success=ci-gate

🔴 👀 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]

🟢 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)(?:\(.+\))?:

🟢 🔎 Reviews

Wonderful, this rule succeeded.
  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 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