hive-forge: add --since cursor paging to comments and timeline

This commit is contained in:
damocles 2026-08-03 20:39:39 +02:00 committed by mara
commit 4cf647aa70
3 changed files with 159 additions and 70 deletions

View file

@ -69,6 +69,56 @@ pub(crate) fn rfc3339(ts: Option<OffsetDateTime>) -> Option<String> {
ts.and_then(|t| t.format(&Rfc3339).ok())
}
/// Parse a `--since`/`--before` CLI argument as RFC 3339 — the inverse of
/// [`rfc3339`], so a value copied straight from this tool's own output
/// (every row prints its `created_at` in this exact shape) round-trips
/// without reformatting. A bad value gets a message naming what was
/// typed, not a bare parser error.
pub(crate) fn parse_rfc3339(s: &str) -> Result<OffsetDateTime> {
OffsetDateTime::parse(s, &Rfc3339)
.map_err(|e| anyhow::anyhow!("`{s}` isn't a valid RFC 3339 timestamp: {e}"))
}
/// Forgejo's per-page cap, shared by every listing verb that over-fetches
/// by one to detect truncation without an exact total (`timeline`'s
/// `--limit`, `comments`' `--since`). The API silently clamps a requested
/// page size to this value, so it's pinned explicitly rather than left as
/// a hidden default downstream math could drift out of sync with.
pub(crate) const PAGE_SIZE: u64 = 50;
/// The highest `--limit` an over-fetch-by-one truncation check
/// (`fetch_limit = limit + 1`) can still detect: `PAGE_SIZE - 1`. At
/// `limit == PAGE_SIZE` the `+1` request silently clamps to `PAGE_SIZE`
/// server-side and the truncation check goes blind exactly when there's
/// the most data to miss.
pub(crate) const MAX_LIMIT: u64 = PAGE_SIZE - 1;
/// Cap `requested` at [`MAX_LIMIT`], reporting whether it had to. Pure so
/// the boundary math is unit-testable without a network call.
pub(crate) fn clamp_limit(requested: u64) -> (u64, bool) {
let limit = requested.min(MAX_LIMIT);
(limit, limit < requested)
}
#[cfg(test)]
mod page_limit_tests {
use super::{MAX_LIMIT, PAGE_SIZE, clamp_limit};
#[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));
}
}
/// Issue-vs-PR kind, for the `pr <verb>` / `issue <verb>` sub-command
/// validation.
#[derive(Clone, Copy)]