hive-forge: add --since cursor paging to comments and timeline
This commit is contained in:
parent
f6629f0c23
commit
4cf647aa70
3 changed files with 159 additions and 70 deletions
|
|
@ -18,10 +18,14 @@
|
|||
//! against — so this over-fetches by one (`limit + 1`) and reports
|
||||
//! "there's more" without saying how much.
|
||||
//!
|
||||
//! `--limit` is capped at [`MAX_LIMIT`] (`PAGE_SIZE - 1`): the
|
||||
//! `--limit` is capped at [`crate::verbs::MAX_LIMIT`]: the
|
||||
//! over-fetch-by-one trick needs `limit + 1` to fit inside Forgejo's
|
||||
//! hard 50-per-page cap, or the response silently clamps to 50 and the
|
||||
//! hard per-page cap, or the response silently clamps and the
|
||||
//! truncation check can never fire even when there genuinely is more.
|
||||
//!
|
||||
//! `--since <RFC3339>` filters to events at or after that timestamp —
|
||||
//! a cursor: feed the last-seen row's own `created_at` back in next
|
||||
//! time instead of re-running with a higher `--limit`.
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Args as ClapArgs;
|
||||
|
|
@ -29,17 +33,7 @@ use forgejo_api::structs::IssueGetCommentsAndTimelineQuery;
|
|||
use serde_json::{Value, json};
|
||||
|
||||
use crate::client::{Client, index};
|
||||
use crate::verbs::print_json;
|
||||
|
||||
/// Forgejo's per-page cap on the timeline endpoint — same hard ceiling
|
||||
/// `comments.rs`'s `PAGE_SIZE` documents for `/comments`.
|
||||
const PAGE_SIZE: u64 = 50;
|
||||
|
||||
/// Largest `--limit` the over-fetch-by-one trick can still detect
|
||||
/// truncation at: `limit + 1` must stay within [`PAGE_SIZE`], or the
|
||||
/// response silently clamps to `PAGE_SIZE` and `more` reads `false` even
|
||||
/// when there's genuinely more.
|
||||
const MAX_LIMIT: u64 = PAGE_SIZE - 1;
|
||||
use crate::verbs::{MAX_LIMIT, clamp_limit, parse_rfc3339, print_json};
|
||||
|
||||
#[derive(ClapArgs)]
|
||||
pub struct Args {
|
||||
|
|
@ -49,14 +43,11 @@ pub struct Args {
|
|||
/// comment for why). Default kept small on purpose.
|
||||
#[arg(long, default_value_t = 10)]
|
||||
limit: u64,
|
||||
}
|
||||
|
||||
/// Effective `--limit` plus whether the request was clamped to
|
||||
/// [`MAX_LIMIT`]. Pure so the boundary math is unit-testable without a
|
||||
/// network call.
|
||||
fn clamp_limit(requested: u64) -> (u64, bool) {
|
||||
let limit = requested.min(MAX_LIMIT);
|
||||
(limit, limit < requested)
|
||||
/// Only show events at or after this RFC3339 timestamp (same format
|
||||
/// this verb's own output prints) — pass back the last-seen row's
|
||||
/// `created_at` to fetch only what's new.
|
||||
#[arg(long)]
|
||||
since: Option<String>,
|
||||
}
|
||||
|
||||
pub fn run(client: &Client, args: Args) -> Result<()> {
|
||||
|
|
@ -65,17 +56,17 @@ pub fn run(client: &Client, args: Args) -> Result<()> {
|
|||
// stay within Forgejo's per-page cap or the truncation check goes
|
||||
// silently blind right at the boundary — see MAX_LIMIT's doc comment.
|
||||
let (limit, clamped) = clamp_limit(args.limit);
|
||||
let since = args.since.as_deref().map(parse_rfc3339).transpose()?;
|
||||
let query = IssueGetCommentsAndTimelineQuery {
|
||||
since,
|
||||
before: None,
|
||||
};
|
||||
// Over-fetch by one to detect truncation without an exact total —
|
||||
// see the module doc comment for why there's no count query here.
|
||||
let fetch_limit = limit.saturating_add(1);
|
||||
let (_, events) = client
|
||||
.api()
|
||||
.issue_get_comments_and_timeline(
|
||||
owner,
|
||||
name,
|
||||
index(args.number)?,
|
||||
IssueGetCommentsAndTimelineQuery::default(),
|
||||
)
|
||||
.issue_get_comments_and_timeline(owner, name, index(args.number)?, query)
|
||||
.page_size(u32::try_from(fetch_limit).unwrap_or(u32::MAX))
|
||||
.send()?;
|
||||
let limit = usize::try_from(limit).unwrap_or(usize::MAX);
|
||||
|
|
@ -288,20 +279,6 @@ mod tests {
|
|||
//! duplicating the logic" — addressed.
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn clamp_limit_passes_small_requests_through() {
|
||||
assert_eq!(clamp_limit(10), (10, false));
|
||||
assert_eq!(clamp_limit(MAX_LIMIT), (MAX_LIMIT, false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clamp_limit_caps_requests_above_the_boundary() {
|
||||
// Regression: `limit + 1` must never exceed Forgejo's PAGE_SIZE,
|
||||
// or the over-fetch-by-one truncation check goes silently blind.
|
||||
assert_eq!(clamp_limit(PAGE_SIZE), (MAX_LIMIT, true));
|
||||
assert_eq!(clamp_limit(1000), (MAX_LIMIT, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_renders_body_inline() {
|
||||
let ev = serde_json::json!({
|
||||
|
|
|
|||
Loading…
Reference in a new issue