feat(rust): port ci git-refs and ci queue-info to native Rust#1353
Conversation
Member
Author
|
This pull request is part of a Mergify stack:
|
This was referenced May 5, 2026
Contributor
Merge ProtectionsYour pull request matches the following merge protections and will not be merged until they are valid. 🔴 ⛓️ Depends-On RequirementsWaiting for
This rule is failing.Requirement based on the presence of
🔴 👀 Review RequirementsWaiting for
This rule is failing.
🔴 🔎 ReviewsWaiting for
This rule is failing.
🟢 🤖 Continuous IntegrationWonderful, this rule succeeded.
🟢 Enforce conventional commitWonderful, this rule succeeded.Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
🟢 📕 PR descriptionWonderful, this rule succeeded.
|
253835c to
1ae9f28
Compare
0ca3459 to
9d6db8e
Compare
Member
Author
Revision history
|
9d6db8e to
a2714b7
Compare
1ae9f28 to
1670fa1
Compare
a2714b7 to
742d92c
Compare
1670fa1 to
8afcb9c
Compare
742d92c to
839ea5a
Compare
839ea5a to
4ddd589
Compare
7e85a94 to
9478efd
Compare
4ddd589 to
3df5705
Compare
mergify Bot
pushed a commit
that referenced
this pull request
May 6, 2026
#1357) The 2026.5.5.x release shipped a ``ci scopes-send`` regression (fixed in #1356): the Rust port deserialized the response body via ``let _: serde_json::Value = client.post(...)`` while the Python original ignored the body, and the Mergify endpoint returns an empty body on success. ``Value`` still requires valid JSON, so the Rust version surfaced ``parse response JSON: error decoding response body`` to every user once it shipped. Test mocks used ``set_body_json(json!({}))`` instead of an empty body, so the bug hid through unit tests too. The fix is structural — split the HTTP client so callers pick ``post`` (parses) vs ``post_no_response`` (drops) up front — but the bug class is broader than this one command. Capturing the lessons in AGENTS.md so the next porter (human or assistant) walks through them before opening a PR. Three categories of pitfall, all observed during the port so far: 1. **HTTP response handling** — match the Python original. If Python ignores the response, Rust must use ``post_no_response`` etc.; if Python parses, optional/nullable fields must be ``Option<T>`` + ``#[serde(default)]``. 2. **Test fixtures** — mirror the real server. ``ResponseTemplate`` bodies must match what the endpoint actually returns; an empty body is not the same as ``json!({})``. 3. **UX parity with click** — char-counted validators use ``chars().count()`` (not ``len()``); confirmation prompts go to stderr; resolve all required state before prompting. Audit of existing/in-flight ports against the checklist: - ``config validate``, ``config simulate`` (main): match - ``ci scopes-send`` (main): regressed, fix in #1356 - ``queue pause`` / ``unpause`` (#1352): match - ``ci git-refs`` / ``queue-info`` (#1353): no HTTP, no risk Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
c3fc948 to
6421363
Compare
This was referenced May 6, 2026
6421363 to
ece765d
Compare
01e7be5 to
dd391d3
Compare
ece765d to
cc96b9a
Compare
cc96b9a to
45c9d93
Compare
…ands Reported by user: ``mergify queue status --help`` rejected the flag with ``error: unexpected argument '--help' found``. Root cause: ``CliRoot`` had ``disable_help_flag = true``, so clap's auto-generated ``--help`` machinery wasn't wired up — and our ``detect_native`` then surfaced the resulting parser error (because ``looks_native`` matched) instead of falling through. Three changes: 1. Drop ``disable_help_flag = true`` from ``CliRoot``. clap now auto-recognizes ``-h`` / ``--help`` at every level and generates its standard help blurb listing flags + subcommands. 2. ``detect_native`` catches the special help-error kinds (``DisplayHelp`` and ``DisplayHelpOnMissingArgumentOrSubcommand``) explicitly and calls ``err.exit()`` regardless of the ``looks_native`` heuristic. ``err.exit()`` prints help to stdout and calls ``process::exit(0)``. The previous flow also called ``err.exit()`` on parser errors when ``looks_native``, but it only fired when the argv contained a (group, subcommand) pair — root-level ``mergify --help`` had no such pair so it would have leaked to the Python shim. 3. Honor ``MERGIFY_CLI_TESTING_UTF8_MODE`` from the Rust binary. ``test_binary_build.py`` runs ``mergify --help`` against the wheel-installed binary to verify UTF-8 emoji output works (particularly on Windows). The marker used to be printed by ``mergify_cli/cli.py::main``, but now that ``--help`` is handled natively the Python path no longer fires. Mirror the marker from the Rust binary: the binary is UTF-8 native on every platform (no ``os.execv`` re-exec needed), so report ``utf8_mode=1`` on Windows (matching the post-re-exec value the test expects) and ``utf8_mode=0`` elsewhere. Verified locally: - ``mergify --help`` lists the three native top-level groups (``config`` / ``ci`` / ``queue``). - ``mergify queue --help`` lists the native queue subcommands (``pause`` / ``unpause`` / ``status``). - ``mergify queue status --help`` shows ``--branch`` / ``--json`` / ``--token`` / ``--api-url`` / ``--repository`` with their doc-strings. - ``MERGIFY_CLI_TESTING_UTF8_MODE=1 mergify --help`` prints ``utf8_mode=0`` and ``✅`` before the help text. Known follow-up: ``mergify queue --help`` doesn't list ``show`` because it's still shimmed (no clap variant). Fixable by registering opaque clap stubs for shimmed commands; deferred to the PR that ports ``queue show``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Change-Id: I2922aa2d83af6c99cb551f2a95bf5a4959832375
Two queue commands in one PR — both are idempotent one-shot API
calls that share the same auth + repository resolution. Pause
exercises the new PUT method; unpause exercises the new
DELETE-with-status-check method.
PUTs ``{"reason": "..."}`` to
``/v1/repos/<repo>/merge-queue/pause``, prints a confirmation line
with the reason and timestamp.
Safety rails match Python:
- ``--yes-i-am-sure`` skips confirmation outright.
- Interactive (TTY): prompts "Proceed? [y/N]". Anything other than
``y``/``yes`` aborts as a generic error.
- Non-interactive without the flag: refuses with INVALID_STATE
(exit 7), matching Python's
``raise SystemExit(ExitCode.INVALID_STATE)``.
``--reason`` has a 255-char cap enforced by clap's ``value_parser``
— bad input exits 2.
DELETEs the same path. On 404 the API is telling us the queue
wasn't paused, so the command prints "Queue is not currently
paused" and exits MERGIFY_API_ERROR (matches Python). On 2xx it
prints "Queue resumed." and exits 0.
Two new methods on ``mergify_core::HttpClient``:
- ``put<B, T>(path, body) -> Result<T, CliError>`` — mirror of
``post``, different verb.
- ``delete_if_exists(path) -> Result<DeleteOutcome, CliError>`` —
returns ``Deleted`` on 2xx, ``NotFound`` on 404, errors on any
other non-success status. Lets commands like ``unpause`` give
a friendlier 404 message without parsing error strings.
Auth resolution (token / api-url / repository) goes through the
shared ``mergify_core::auth`` module added earlier in the stack —
no per-crate copy of the resolvers in ``mergify-queue``.
5 new unit tests in the queue crate:
- ``parse_reason`` accepts short strings and rejects > 255 chars
- ``run`` pauses and prints the API-returned reason + timestamp
- ``run`` prints "Queue resumed" on 2xx
- ``run`` errors with MERGIFY_API_ERROR on 404 carrying the
"not currently paused" message
End-to-end smoke tested three paths:
``queue pause --reason X -r owner/repo`` → exit 8 (missing token),
``queue unpause -r owner/repo`` → exit 8 (missing token),
``echo n | queue pause --reason X`` → exit 7 (non-TTY, no --sure).
The Python ``queue pause`` / ``queue unpause`` implementations and
their tests are removed in the same PR — the Rust binary now owns
both commands end-to-end. Binary: 8.4 MB → 8.5 MB. 56 Rust tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Change-Id: Idba6fa38caf403fd5f4184cda462b5f7c1eb3ebf
Adds `github_event` (GitHub Actions event payload deserialization) and `queue_metadata` (MQ YAML fenced-block extraction) shared modules to the mergify-ci crate, and ports two commands on top of them: - `ci queue-info` — prints MQ batch metadata as pretty JSON; errors INVALID_STATE (exit 7) outside an MQ context. Appends to `$GITHUB_OUTPUT` with the same `ghadelimiter_<uuid>` heredoc the Python version uses. - `ci git-refs` — detects base/head refs from Buildkite env, GitHub event payload, `refs/notes/mergify/<branch>` git notes, MQ PR body, or falls back to `HEAD^..HEAD`. Supports `text`/`shell`/`json` output formats, writes `base`/`head` to `$GITHUB_OUTPUT`, and calls `buildkite-agent meta-data set` when `BUILDKITE=true`. The notes reader is injected as a trait-object callback so unit tests can exercise the note-driven detection path without touching a real git repository; the production path shells out via `real_notes_reader`. The Python implementations of `ci git-refs` and `ci queue-info` are removed in the same PR — the Rust binary now owns both commands end-to-end. The looks-native heuristic in `main.rs` learns the two new subcommand names so argv errors surface as clap exit 2 instead of silently falling through to the Python shim. Adds `serde_yaml_ng` (YAML parser) and `uuid` (ghadelimiter) deps to the mergify-ci crate. Binary grows ~100KB to 8.6MB. 19 new Rust tests (8 event/metadata, 3 queue-info, 12 git-refs + 2 format round-trips merged in). Full workspace: 79 tests green, compat harness 4/4. Change-Id: I8d3f96e6cb4eb51e6cd195951b3e622cee7efdd4
45c9d93 to
8f81284
Compare
dc54105 to
b010249
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.
Adds
github_event(GitHub Actions event payload deserialization) andqueue_metadata(MQ YAML fenced-block extraction) shared modules to themergify-ci crate, and ports two commands on top of them:
ci queue-info— prints MQ batch metadata as pretty JSON; errorsINVALID_STATE (exit 7) outside an MQ context. Appends to
$GITHUB_OUTPUTwith the sameghadelimiter_<uuid>heredoc thePython version uses.
ci git-refs— detects base/head refs from Buildkite env, GitHubevent payload,
refs/notes/mergify/<branch>git notes, MQ PR body,or falls back to
HEAD^..HEAD. Supportstext/shell/jsonoutput formats, writes
base/headto$GITHUB_OUTPUT, and callsbuildkite-agent meta-data setwhenBUILDKITE=true.The notes reader is injected as a trait-object callback so unit tests
can exercise the note-driven detection path without touching a real
git repository; the production path shells out via
real_notes_reader.The Python implementations of
ci git-refsandci queue-infoareremoved in the same PR — the Rust binary now owns both commands
end-to-end. The looks-native heuristic in
main.rslearns the twonew subcommand names so argv errors surface as clap exit 2 instead
of silently falling through to the Python shim.
Adds
serde_yaml_ng(YAML parser) anduuid(ghadelimiter) deps tothe mergify-ci crate. Binary grows ~100KB to 8.6MB.
19 new Rust tests (8 event/metadata, 3 queue-info, 12 git-refs + 2
format round-trips merged in). Full workspace: 79 tests green,
compat harness 4/4.
Depends-On: #1352