Skip to main content

codeberg_cli/actions/issue/
list.rs

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