codeberg_cli/actions/pull_request/
view.rs1use super::display_pull_request;
2use crate::actions::{GlobalArgs, 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, global_args: GlobalArgs) -> anyhow::Result<()> {
39 let ctx = BergContext::new(self, global_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(
48 ctx.client
49 .repo_list_pull_requests(
50 owner.as_str(),
51 repo.as_str(),
52 RepoListPullRequestsQuery {
53 state: Some(state),
54 ..Default::default()
55 },
56 )
57 .send(),
58 )
59 .await?;
60
61 let pull_request = fuzzy_select_with_key(
62 &pull_requests_list,
63 select_prompt_for("pull request"),
64 display_pull_request,
65 )?;
66
67 match ctx.global_args.output_mode {
68 OutputMode::Pretty => {
69 if ctx.args.comments {
70 spin_until_ready(present_pull_request_comments(&ctx, pull_request)).await?;
71 } else {
72 present_pull_request_overview(&ctx, pull_request);
73 }
74 }
75 OutputMode::Json => pull_request.print_json()?,
76 }
77
78 Ok(())
79 }
80}
81
82fn present_pull_request_overview(
83 ctx: &BergContext<ViewPullRequestsArgs>,
84 pull_request: &PullRequest,
85) {
86 let rendered_datetime = pull_request
87 .created_at
88 .as_ref()
89 .map(render_datetime_and_info)
90 .unwrap_or_else(|| String::from("?"));
91
92 let mut table = ctx.make_table();
93
94 table
95 .set_header(vec![format!(
96 "Pull Request #{}",
97 option_display(&pull_request.id)
98 )])
99 .add_row(vec![
100 String::from("Title"),
101 option_display(&pull_request.title),
102 ])
103 .add_row(vec![String::from("Created"), rendered_datetime])
104 .add_row(vec![
105 String::from("Labels"),
106 pull_request
107 .labels
108 .iter()
109 .flatten()
110 .map(|label| option_display(&label.name))
111 .join(", "),
112 ])
113 .add_row(vec![
114 String::from("Description"),
115 option_display(&pull_request.body),
116 ]);
117
118 println!("{table}", table = table.show());
119}
120
121async fn present_pull_request_comments(
122 ctx: &BergContext<ViewPullRequestsArgs>,
123 pull_request: &PullRequest,
124) -> anyhow::Result<()> {
125 let OwnerRepo { repo, owner } = ctx.owner_repo()?;
126 let nr = pull_request.id.context("Selected pull request has no ID")?;
127 let (_, comments) = ctx
128 .client
129 .issue_get_comments(
130 owner.as_str(),
131 repo.as_str(),
132 nr,
133 IssueGetCommentsQuery::default(),
134 )
135 .await?;
136 let header = format!(
137 "Pull Request #{} {}",
138 option_display(&pull_request.id),
139 if comments.is_empty() {
140 "(no comments)"
141 } else {
142 "comments"
143 }
144 );
145
146 let mut table = ctx.make_table();
147
148 table
149 .set_header(vec![header])
150 .add_rows(comments.into_iter().filter_map(|comment| {
151 let username = comment.user.as_ref()?.login.as_ref()?.as_str();
152 let creation_time = comment.created_at.as_ref()?;
153 let comment = comment.body.as_ref()?;
154 let comment = render_comment(&ctx.config, username, creation_time, comment);
155 Some(vec![comment])
156 }));
157
158 println!("{table}", table = table.show());
159
160 Ok(())
161}