feat(events): add a shared activity-log client crate - #1758
Conversation
|
This pull request is part of a Mergify stack:
|
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
Adds a new mergify-events crate to centralize the Mergify activity-log (/logs) contract (explicit time windows, typed span validation, cursor pagination, stable newest-first ordering, and raw-field passthrough), plus a small mergify-core HTTP helper to fetch cursor-paginated pages safely.
Changes:
- Introduces
crates/mergify-eventswithWindow,Event, andfetch(Query)APIs, backed by wiremock-based tests. - Adds
Client::get_page+Page<T>and RFC5988Linkcursor extraction tomergify-core::http. - Wires the new crate into the workspace (new crate manifest + lockfile entry).
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/mergify-events/src/window.rs | Adds explicit time window type with retention/span constraints + unit tests. |
| crates/mergify-events/src/lib.rs | New crate root docs + exports for the activity-log client surface. |
| crates/mergify-events/src/event.rs | Adds Event wrapper that preserves raw payload while exposing a decoded envelope. |
| crates/mergify-events/src/client.rs | Implements /logs fetching with explicit bounds, cursor pagination, ordering guarantee + wiremock tests. |
| crates/mergify-events/Cargo.toml | Declares the new crate and its workspace dependencies. |
| crates/mergify-core/src/lib.rs | Re-exports new http::Page type from mergify-core. |
| crates/mergify-core/src/http.rs | Adds Page<T>, Client::get_page, and cursor parsing from Link header + tests. |
| Cargo.lock | Adds lock entry for the new mergify-events crate. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The activity log (GET /v1/repos/.../logs) carries every event type the engine records — the action.queue.* family, the workflow actions, ci_insights.*, command.* — behind a contract with sharp edges that cost #1747 ~700 lines to pin for a single lookup: a silent `received_from = received_to - 1 day` default that makes a pull request dequeued last week read exactly like one never queued, a raw 422 on ranges over 93 days while retention is 90, opaque-cursor pagination, and unstated ordering. Own that contract once, in a new `mergify-events` crate, so nothing above it thinks about the traps: - **The window is always explicit.** `Window` carries both bounds and every request sends them; the silent 1-day default is unreachable. - **The 93-day cap is a typed error.** `Window` refuses to construct a range the API would 422 on, and "everything retained" is spelled `Window::retained` — the widest useful window has a name. - **Pagination is followed to completion** via the RFC 5988 `Link` cursors (new `Client::get_page` in mergify-core, which extracts only the cursor from the rel="next" target so a server cannot rewrite the caller's query), with a same-cursor loop guard. - **Ordering is guaranteed newest-first** by the client after collecting — a promise of the crate, not an observation about today's server. - **Unknown fields pass through verbatim.** An `Event` keeps the raw API object untouched next to a decoded envelope of the fields every event shares, so a newer engine cannot break an older CLI and `--json` republishes Mergify's contract, not this crate's. Nothing consumes the crate yet: the next two changes port `queue show`'s last-leave fallback onto it (so the contract has one home) and add `mergify events`. Part of MRGFY-8363. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Change-Id: I1f15266ac6680c63d95dddeec34978ad4edf0a50
6220917 to
f6b6132
Compare
Revision history
|
Merge Queue Status
Waiting for
All merge conditions
Required conditions to stay in the queue
|
The activity log (GET /v1/repos/.../logs) carries every event type the
engine records — the action.queue.* family, the workflow actions,
ci_insights., command. — behind a contract with sharp edges that cost
#1747 ~700 lines to pin for a single lookup: a silent
received_from = received_to - 1 daydefault that makes a pullrequest dequeued last week read exactly like one never queued, a raw
422 on ranges over 93 days while retention is 90, opaque-cursor
pagination, and unstated ordering.
Own that contract once, in a new
mergify-eventscrate, so nothingabove it thinks about the traps:
Windowcarries both bounds andevery request sends them; the silent 1-day default is unreachable.
Windowrefuses to construct arange the API would 422 on, and "everything retained" is spelled
Window::retained— the widest useful window has a name.Linkcursors (new
Client::get_pagein mergify-core, which extracts onlythe cursor from the rel="next" target so a server cannot rewrite the
caller's query), with a same-cursor loop guard.
collecting — a promise of the crate, not an observation about
today's server.
Eventkeeps the rawAPI object untouched next to a decoded envelope of the fields every
event shares, so a newer engine cannot break an older CLI and
--jsonrepublishes Mergify's contract, not this crate's.Nothing consumes the crate yet: the next two changes port
queue show's last-leave fallback onto it (so the contract has one home) andadd
mergify events.Part of MRGFY-8363.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com