//! `pr-commits [repo]` — list a PR's commits as JSON //! (sha, message, author date, author login), paginated. //! //! The forge stores a PR's commits against its branch ref, so this //! returns them even for a PR whose shas were rewritten by a rebase //! merge. The commit message and author date survive a rebase //! unchanged, so a caller can match these rows against the linear //! `main` history to recover the merged-final commits when the PR's //! recorded shas no longer resolve. use anyhow::Result; use clap::Args as ClapArgs; use serde_json::json; use crate::client::Client; use crate::verbs::print_json; /// Page cap for the commit list. Forgejo serves up to 50 commits per /// page; 40 pages (2000 commits) is far beyond any real PR. const MAX_PAGES: u32 = 40; #[derive(ClapArgs)] pub struct Args { /// PR number. number: u64, } pub fn run(client: &Client, args: Args) -> Result<()> { let repo = client.repo(); let commits = client.get_json_all( &format!("/repos/{repo}/pulls/{}/commits", args.number), MAX_PAGES, )?; let trimmed: Vec<_> = commits .iter() .map(|c| { let commit = c.get("commit"); json!({ "sha": c.get("sha"), "message": commit.and_then(|x| x.get("message")), "author_date": commit .and_then(|x| x.get("author")) .and_then(|a| a.get("date")), "author": c.get("author").and_then(|u| u.get("login")), }) }) .collect(); print_json(&json!(trimmed)) }