diff --git a/hive-forge/src/verbs/pr_reviews.rs b/hive-forge/src/verbs/pr_reviews.rs index 8755f218..f9eff091 100644 --- a/hive-forge/src/verbs/pr_reviews.rs +++ b/hive-forge/src/verbs/pr_reviews.rs @@ -65,24 +65,94 @@ pub fn run(client: &Client, args: Args) -> Result<()> { if args.body.is_some() { bail!("--body requires one of --approve / --request-changes / --comment"); } - // List mode (original behaviour). - let v = client.get_json(&format!("/repos/{repo}/pulls/{}/reviews", args.number))?; - let trimmed: Vec = v - .as_array() - .map(|a| { - a.iter() - .map(|r| { - json!({ - "id": r.get("id"), - "state": r.get("state"), - "user": r.get("user").and_then(|u| u.get("login")), - "body": r.get("body"), - "comments_count": r.get("comments_count"), - }) + // List mode: fetch reviews, then fetch inline comments for each review + // so the full review content is visible without curl fallbacks. + let v = + client.get_json(&format!("/repos/{repo}/pulls/{}/reviews", args.number))?; + let reviews = v.as_array().cloned().unwrap_or_default(); + + if client.json_mode() { + let trimmed: Vec = reviews + .iter() + .map(|r| { + let id = r.get("id").and_then(Value::as_u64).unwrap_or(0); + let inline = if id > 0 { + client + .get_json(&format!( + "/repos/{repo}/pulls/{}/reviews/{id}/comments", + args.number + )) + .ok() + .and_then(|v| v.as_array().cloned()) + .map(|comments| { + comments + .iter() + .map(|c| { + json!({ + "id": c.get("id"), + "path": c.get("path"), + "line": c.get("line"), + "body": c.get("body"), + }) + }) + .collect::>() + }) + .unwrap_or_default() + } else { + vec![] + }; + json!({ + "id": r.get("id"), + "state": r.get("state"), + "user": r.get("user").and_then(|u| u.get("login")), + "body": r.get("body"), + "comments_count": r.get("comments_count"), + "comments": inline, }) - .collect() - }) - .unwrap_or_default(); - print_json(&Value::Array(trimmed)) + }) + .collect(); + print_json(&Value::Array(trimmed)) + } else { + if reviews.is_empty() { + println!("(no reviews)"); + return Ok(()); + } + for r in &reviews { + let id = r.get("id").and_then(Value::as_u64).unwrap_or(0); + let user = r + .get("user") + .and_then(|u| u.get("login")) + .and_then(Value::as_str) + .unwrap_or("?"); + let state = r.get("state").and_then(Value::as_str).unwrap_or("?"); + let body = r.get("body").and_then(Value::as_str).unwrap_or("").trim(); + println!("### review by {user} ({state})"); + if !body.is_empty() { + println!("{body}"); + } + // Fetch and print inline comments for this review. + if id > 0 { + if let Ok(ic) = client.get_json(&format!( + "/repos/{repo}/pulls/{}/reviews/{id}/comments", + args.number + )) { + let inline = ic.as_array().cloned().unwrap_or_default(); + for c in &inline { + let path = c.get("path").and_then(Value::as_str).unwrap_or("?"); + let line = c + .get("line") + .and_then(Value::as_u64) + .map(|n| n.to_string()) + .unwrap_or_else(|| "?".to_string()); + let cbody = + c.get("body").and_then(Value::as_str).unwrap_or("").trim(); + println!(" [{path}:{line}] {cbody}"); + } + } + } + println!(); + } + Ok(()) + } } }