codeberg_cli/actions/issue/
list.rs

1use forgejo_api::structs::{Issue, IssueListIssuesQuery, IssueListIssuesQueryState};
2
3use crate::actions::GlobalArgs;
4use crate::render::json::JsonToStdout;
5use crate::render::option::{option_debug_display, option_display};
6use crate::render::spinner::spin_until_ready;
7use crate::types::api::state_type::ViewStateType;
8use crate::types::context::BergContext;
9use crate::types::git::OwnerRepo;
10use crate::types::output::OutputMode;
11
12use clap::Parser;
13
14/// List all issues in the current repository
15#[derive(Parser, Debug)]
16pub struct ListIssueArgs {
17    /// Filter by state
18    #[arg(short, long, value_enum, default_value_t = ViewStateType::Open)]
19    pub state: ViewStateType,
20}
21
22impl ListIssueArgs {
23    pub async fn run(self, global_args: GlobalArgs) -> anyhow::Result<()> {
24        let ctx = BergContext::new(self, global_args).await?;
25        let OwnerRepo { repo, owner } = ctx.owner_repo()?;
26        let state = match ctx.args.state {
27            ViewStateType::Closed => IssueListIssuesQueryState::Closed,
28            ViewStateType::Open => IssueListIssuesQueryState::Open,
29            ViewStateType::All => IssueListIssuesQueryState::All,
30        };
31        let (_, mut issues_list) = spin_until_ready(
32            ctx.client
33                .issue_list_issues(
34                    owner.as_str(),
35                    repo.as_str(),
36                    IssueListIssuesQuery {
37                        state: Some(state),
38                        ..Default::default()
39                    },
40                )
41                .send(),
42        )
43        .await?;
44
45        issues_list.retain(|issue| issue.pull_request.is_none());
46
47        match ctx.global_args.output_mode {
48            OutputMode::Pretty => {
49                present_issues_list(&ctx, issues_list);
50            }
51            OutputMode::Json => issues_list.print_json()?,
52        }
53
54        Ok(())
55    }
56}
57
58fn present_issues_list(ctx: &BergContext<ListIssueArgs>, issues: Vec<Issue>) {
59    let issues_empty = issues.is_empty();
60
61    let mut table = ctx.make_table().add_table((!issues_empty).then(|| {
62        let mut inner_table = ctx.make_table();
63        inner_table
64            .set_header(vec!["Number", "Status", "Name", "Labels"])
65            .add_rows(issues.into_iter().map(|issue| {
66                let Issue {
67                    title,
68                    number,
69                    labels,
70                    state,
71                    ..
72                } = issue;
73                let labels = labels.map(|labels| {
74                    labels
75                        .into_iter()
76                        .map(|label| option_display(&label.name))
77                        .collect::<Vec<_>>()
78                        .join(",")
79                });
80                vec![
81                    option_display(&number),
82                    option_debug_display(&state),
83                    option_display(&title),
84                    option_display(&labels),
85                ]
86            }));
87        inner_table
88    }));
89
90    table.set_header(vec![format!(
91        "Issues{}",
92        if issues_empty {
93            " (empty)"
94        } else {
95            Default::default()
96        }
97    )]);
98
99    println!("{table}", table = table.show());
100}