hive-forge: add --all to list for full-pagination repo-wide sweeps
This commit is contained in:
parent
21e5233c1f
commit
0aef643797
2 changed files with 31 additions and 4 deletions
|
|
@ -37,6 +37,7 @@ hive-forge pr-reviews 42 --comment -m "msg" # submit COMMENT review
|
||||||
hive-forge diff 42 # unified diff (lockfile hunks collapsed by default)
|
hive-forge diff 42 # unified diff (lockfile hunks collapsed by default)
|
||||||
hive-forge diff 42 --full # include unfiltered lockfile hunks
|
hive-forge diff 42 --full # include unfiltered lockfile hunks
|
||||||
hive-forge list # open issues/PRs
|
hive-forge list # open issues/PRs
|
||||||
|
hive-forge list --kind pr --state all --all # every PR across all pages (repo-wide sweep; --all follows pagination)
|
||||||
hive-forge milestone # list milestones
|
hive-forge milestone # list milestones
|
||||||
hive-forge branches deployed/ # filter branches by pattern
|
hive-forge branches deployed/ # filter branches by pattern
|
||||||
hive-forge tree-sha main # git tree SHA for a ref
|
hive-forge tree-sha main # git tree SHA for a ref
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
//! `list [--kind issue|pr|both] [--state open|closed|all] [--assignee
|
//! `list [--kind issue|pr|both] [--state open|closed|all] [--assignee
|
||||||
//! <user>] [--author <user>] [--label <name>] [--limit N]` — list
|
//! <user>] [--author <user>] [--label <name>] [--limit N] [--all]` —
|
||||||
//! issues / PRs with filters. Pretty `#NNN [author] title` output by
|
//! list issues / PRs with filters. Pretty `#NNN [author] title` output by
|
||||||
//! default; `--json` for piping.
|
//! default; `--json` for piping. `--all` drains every page (for repo-wide
|
||||||
|
//! analysis) instead of a single `--limit` page.
|
||||||
//!
|
//!
|
||||||
//! Mirrors Forgejo's `GET /repos/{owner}/{repo}/issues` query-string
|
//! Mirrors Forgejo's `GET /repos/{owner}/{repo}/issues` query-string
|
||||||
//! filters one-for-one so the mental model carries over. Closes the
|
//! filters one-for-one so the mental model carries over. Closes the
|
||||||
|
|
@ -86,15 +87,26 @@ pub struct Args {
|
||||||
/// Max items to return (default: 30; forge's per-page cap applies).
|
/// Max items to return (default: 30; forge's per-page cap applies).
|
||||||
#[arg(long, default_value_t = 30)]
|
#[arg(long, default_value_t = 30)]
|
||||||
limit: u64,
|
limit: u64,
|
||||||
|
/// Drain ALL matching items across every page, not just the first
|
||||||
|
/// `--limit` (which the forge caps at its per-page max, ~50). Follows
|
||||||
|
/// pagination up to a safety cap. Use for repo-wide analysis — e.g.
|
||||||
|
/// `--kind pr --state all --all` to sweep every PR. Overrides
|
||||||
|
/// `--limit` (each page is fetched at the per-page max).
|
||||||
|
#[arg(long)]
|
||||||
|
all: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(client: &Client, args: Args) -> Result<()> {
|
pub fn run(client: &Client, args: Args) -> Result<()> {
|
||||||
let repo = client.repo();
|
let repo = client.repo();
|
||||||
|
// With `--all` each page is fetched at the forge's per-page max so we
|
||||||
|
// make the fewest round-trips; `get_json_all` then follows the
|
||||||
|
// `Link: rel="next"` chain. Otherwise honour `--limit` as a single page.
|
||||||
|
let per_page = if args.all { 50 } else { args.limit };
|
||||||
let mut path = format!(
|
let mut path = format!(
|
||||||
"/repos/{repo}/issues?type={}&state={}&limit={}",
|
"/repos/{repo}/issues?type={}&state={}&limit={}",
|
||||||
args.kind.api_value(),
|
args.kind.api_value(),
|
||||||
args.state.api_value(),
|
args.state.api_value(),
|
||||||
args.limit
|
per_page
|
||||||
);
|
);
|
||||||
if let Some(u) = args.assignee.as_deref()
|
if let Some(u) = args.assignee.as_deref()
|
||||||
&& !u.is_empty()
|
&& !u.is_empty()
|
||||||
|
|
@ -118,6 +130,20 @@ pub fn run(client: &Client, args: Args) -> Result<()> {
|
||||||
let encoded: Vec<String> = args.labels.iter().map(|l| super::pct_encode(l)).collect();
|
let encoded: Vec<String> = args.labels.iter().map(|l| super::pct_encode(l)).collect();
|
||||||
write!(path, "&labels={}", encoded.join(",")).unwrap();
|
write!(path, "&labels={}", encoded.join(",")).unwrap();
|
||||||
}
|
}
|
||||||
|
if args.all {
|
||||||
|
// Safety cap: 200 pages * 50/page = 10k items, well past any
|
||||||
|
// realistic repo while still bounding a runaway loop.
|
||||||
|
const MAX_PAGES: u32 = 200;
|
||||||
|
let items = client.get_json_all(&path, MAX_PAGES)?;
|
||||||
|
if client.json_mode() {
|
||||||
|
return print_json(&Value::Array(items));
|
||||||
|
}
|
||||||
|
for item in &items {
|
||||||
|
print_row(item);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let resp = client.get_json(&path)?;
|
let resp = client.get_json(&path)?;
|
||||||
if client.json_mode() {
|
if client.json_mode() {
|
||||||
return print_json(&resp);
|
return print_json(&resp);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue