use forgejo_api::structs::{
PullRequest, RepoListPullRequestsQuery, RepoListPullRequestsQueryState,
};
use itertools::Itertools;
use miette::IntoDiagnostic;
use crate::actions::GlobalArgs;
use crate::render::json::JsonToStdout;
use crate::render::option::{option_debug_display, option_display};
use crate::render::spinner::spin_until_ready;
use crate::types::api::pr_query_sort::{self, PullRequestsQuerySort};
use crate::types::context::BergContext;
use crate::types::api::state_type::ViewStateType;
use crate::types::git::OwnerRepo;
use crate::types::output::OutputMode;
use clap::Parser;
#[derive(Parser, Debug, Clone)]
pub struct ListPullRequestArgs {
#[arg(long, default_value_t = pr_query_sort::PullRequestsQuerySort::Recentupdate)]
pub sort: PullRequestsQuerySort,
#[arg(short, long, default_value_t = ViewStateType::All)]
pub state: ViewStateType,
}
impl ListPullRequestArgs {
pub async fn run(self, global_args: GlobalArgs) -> miette::Result<()> {
let state = match self.state {
ViewStateType::All => RepoListPullRequestsQueryState::All,
ViewStateType::Closed => RepoListPullRequestsQueryState::Closed,
ViewStateType::Open => RepoListPullRequestsQueryState::Open,
};
let query = RepoListPullRequestsQuery {
state: Some(state),
sort: Some(self.sort.into()),
..Default::default()
};
let ctx = BergContext::new(self, global_args).await?;
let OwnerRepo { repo, owner } = ctx.owner_repo()?;
let (_, pull_requests_list) = spin_until_ready(
ctx.client
.repo_list_pull_requests(owner.as_str(), repo.as_str(), query)
.send(),
)
.await
.into_diagnostic()?;
match ctx.global_args.output_mode {
OutputMode::Pretty => {
present_pull_requests_list(&ctx, pull_requests_list);
}
OutputMode::Json => pull_requests_list.print_json()?,
}
Ok(())
}
}
fn present_pull_requests_list(
ctx: &BergContext<ListPullRequestArgs>,
pull_requests: Vec<PullRequest>,
) {
let pull_requests_empty = pull_requests.is_empty();
let table = ctx
.make_table()
.set_header(vec!["Number", "Status", "Name", "Labels"])
.add_rows(pull_requests.iter().map(|issue| {
let PullRequest {
title,
number,
labels,
state,
..
} = issue;
let labels = option_display(&labels.as_ref().map(|labels| {
if labels.is_empty() {
String::from("x")
} else {
labels
.iter()
.filter_map(|label| label.name.as_ref())
.join(",")
}
}));
vec![
option_display(number),
option_debug_display(state),
option_display(title),
labels,
]
}));
let header = format!(
"Pull Requests {}",
if pull_requests_empty {
" (empty)"
} else {
Default::default()
}
);
let underscore = "=".repeat(header.len());
let out = [header, underscore, table.show()].join("\n");
println!("{out}");
}