//! `view [repo]` — dump title + body + all comments as //! markdown. use anyhow::Result; use clap::Args as ClapArgs; use serde_json::Value; use crate::client::Client; #[derive(ClapArgs)] pub struct Args { /// Issue or PR number. number: u64, } /// # Errors /// /// Propagates any transport error from the Forgejo REST call /// (network unreachable, 4xx/5xx response, token missing/invalid) /// and any I/O error from writing the response to stdout. pub fn run(client: &Client, args: Args) -> Result<()> { let repo = client.repo(); let issue = client.get_json(&format!("/repos/{repo}/issues/{}", args.number))?; let title = issue.get("title").and_then(Value::as_str).unwrap_or(""); let body = issue.get("body").and_then(Value::as_str).unwrap_or(""); let state = issue.get("state").and_then(Value::as_str).unwrap_or("?"); let user = issue .get("user") .and_then(|u| u.get("login")) .and_then(Value::as_str) .unwrap_or("?"); let kind = if issue.get("pull_request").is_some_and(|p| !p.is_null()) { "PR" } else { "issue" }; println!("# {kind} #{} [{state}] by {user}", args.number); println!("{title}"); if !body.is_empty() { println!(); println!("{body}"); } let comments = client.get_json(&format!( "/repos/{repo}/issues/{}/comments?limit=50", args.number ))?; let arr = comments.as_array().cloned().unwrap_or_default(); if !arr.is_empty() { println!(); println!("---"); println!("## Comments ({})", arr.len()); println!(); for c in &arr { let cu = c .get("user") .and_then(|u| u.get("login")) .and_then(Value::as_str) .unwrap_or("?"); let cb = c.get("body").and_then(Value::as_str).unwrap_or(""); println!("**{cu}**: {cb}"); println!(); } } Ok(()) }