codeberg_cli/actions/pull_request/
view.rs1use super::display_pull_request;
2use crate::actions::{GeneralArgs, text_manipulation::select_prompt_for};
3use crate::render::comment::render_comment;
4use crate::render::datetime::render_datetime_and_info;
5use crate::render::json::JsonToStdout;
6use crate::render::option::option_display;
7use crate::render::spinner::spin_until_ready;
8use crate::render::ui::fuzzy_select_with_key;
9use crate::types::api::state_type::ViewStateType;
10use crate::types::context::BergContext;
11use crate::types::git::OwnerRepo;
12use crate::types::output::OutputMode;
13use anyhow::Context;
14use clap::Parser;
15use forgejo_api::structs::{
16 IssueGetCommentsQuery, PullRequest, RepoListPullRequestsQuery, RepoListPullRequestsQueryState,
17};
18use itertools::Itertools;
19
20#[derive(Parser, Debug)]
21#[command(about = "View details of a selected pull request")]
22pub struct ViewPullRequestsArgs {
23 #[arg(
25 short,
26 long,
27 value_enum,
28 default_value_t = ViewStateType::All,
29 )]
30 pub state: ViewStateType,
31
32 #[arg(short, long)]
34 pub comments: bool,
35}
36
37impl ViewPullRequestsArgs {
38 pub async fn run(self, general_args: GeneralArgs) -> anyhow::Result<()> {
39 let ctx = BergContext::new(self, general_args).await?;
40
41 let OwnerRepo { repo, owner } = ctx.owner_repo()?;
42 let state = match ctx.args.state {
43 ViewStateType::Closed => RepoListPullRequestsQueryState::Closed,
44 ViewStateType::Open => RepoListPullRequestsQueryState::Open,
45 ViewStateType::All => RepoListPullRequestsQueryState::All,
46 };
47 let (_, pull_requests_list) = spin_until_ready(ctx.client.repo_list_pull_requests(
48 owner.as_str(),
49 repo.as_str(),
50 RepoListPullRequestsQuery {
51 state: Some(state),
52 ..Default::default()
53 },
54 ))
55 .await?;
56
57 let pull_request = fuzzy_select_with_key(
58 &pull_requests_list,
59 select_prompt_for("pull request"),
60 display_pull_request,
61 )?;
62
63 match general_args.output_mode {
64 OutputMode::Pretty => {
65 if ctx.args.comments {
66 spin_until_ready(present_pull_request_comments(&ctx, pull_request)).await?;
67 } else {
68 present_pull_request_overview(&ctx, pull_request);
69 }
70 }
71 OutputMode::Json => pull_request.print_json()?,
72 }
73
74 Ok(())
75 }
76}
77
78fn present_pull_request_overview(
79 ctx: &BergContext<ViewPullRequestsArgs>,
80 pull_request: &PullRequest,
81) {
82 let rendered_datetime = pull_request
83 .created_at
84 .as_ref()
85 .map(render_datetime_and_info)
86 .unwrap_or_else(|| String::from("?"));
87
88 let mut table = ctx.make_table();
89
90 table
91 .set_header(vec![format!(
92 "Pull Request #{}",
93 option_display(&pull_request.id)
94 )])
95 .add_row(vec![
96 String::from("Title"),
97 option_display(&pull_request.title),
98 ])
99 .add_row(vec![String::from("Created"), rendered_datetime])
100 .add_row(vec![
101 String::from("Labels"),
102 pull_request
103 .labels
104 .iter()
105 .flatten()
106 .map(|label| option_display(&label.name))
107 .join(", "),
108 ])
109 .add_row(vec![
110 String::from("Description"),
111 option_display(&pull_request.body),
112 ]);
113
114 println!("{table}", table = table.show());
115}
116
117async fn present_pull_request_comments(
118 ctx: &BergContext<ViewPullRequestsArgs>,
119 pull_request: &PullRequest,
120) -> anyhow::Result<()> {
121 let OwnerRepo { repo, owner } = ctx.owner_repo()?;
122 let nr = pull_request.id.context("Selected pull request has no ID")?;
123 let (_, comments) = ctx
124 .client
125 .issue_get_comments(
126 owner.as_str(),
127 repo.as_str(),
128 nr as u64,
129 IssueGetCommentsQuery::default(),
130 )
131 .await?;
132 let header = format!(
133 "Pull Request #{} {}",
134 option_display(&pull_request.id),
135 if comments.is_empty() {
136 "(no comments)"
137 } else {
138 "comments"
139 }
140 );
141
142 let mut table = ctx.make_table();
143
144 table
145 .set_header(vec![header])
146 .add_rows(comments.into_iter().filter_map(|comment| {
147 let username = comment.user.as_ref()?.login.as_ref()?.as_str();
148 let creation_time = comment.created_at.as_ref()?;
149 let comment = comment.body.as_ref()?;
150 let comment = render_comment(&ctx.config, username, creation_time, comment);
151 Some(vec![comment])
152 }));
153
154 println!("{table}", table = table.show());
155
156 Ok(())
157}