use aptu_core::DiscoveredRepo;
use aptu_core::ai::types::TriageResponse;
use aptu_core::github::auth::TokenSource;
use aptu_core::github::graphql::IssueNode;
use aptu_core::history::{Contribution, HistoryData};
use aptu_core::repos::CuratedRepo;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct AuthStatusResult {
pub authenticated: bool,
pub method: Option<TokenSource>,
pub username: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct ReposResult {
pub repos: Vec<CuratedRepo>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct IssuesResult {
pub issues_by_repo: Vec<(String, Vec<IssueNode>)>,
pub total_count: usize,
pub repo_filter: Option<String>,
pub no_repos_matched: bool,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct TriageResult {
pub issue_title: String,
pub issue_number: u64,
pub triage: TriageResponse,
pub ai_stats: aptu_core::history::AiStats,
pub comment_url: Option<String>,
pub dry_run: bool,
pub user_declined: bool,
pub applied_labels: Vec<String>,
pub applied_milestone: Option<String>,
pub apply_warnings: Vec<String>,
pub is_maintainer: bool,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
pub enum SingleTriageOutcome {
#[allow(dead_code)]
Success(Box<TriageResult>),
#[allow(dead_code)]
Skipped(String),
#[allow(dead_code)]
Failed(String),
}
impl SingleTriageOutcome {
pub fn as_triage_result(&self) -> Option<&TriageResult> {
match self {
SingleTriageOutcome::Success(result) => Some(result),
_ => None,
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct BulkTriageResult {
pub succeeded: usize,
pub failed: usize,
pub skipped: usize,
pub outcomes: Vec<(String, SingleTriageOutcome)>,
}
impl BulkTriageResult {
pub fn has_dry_run(&self) -> bool {
self.outcomes.iter().any(|(_, outcome)| {
outcome
.as_triage_result()
.is_some_and(|result| result.dry_run)
})
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct HistoryResult {
pub contributions: Vec<Contribution>,
pub history_data: HistoryData,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct CreateResult {
pub issue_url: String,
pub issue_number: u64,
pub title: String,
pub body: String,
pub suggested_labels: Vec<String>,
pub dry_run: bool,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct PrReviewResult {
pub pr_title: String,
pub pr_number: u64,
pub pr_url: String,
pub review: aptu_core::ai::types::PrReviewResponse,
pub verdict: String,
pub ai_stats: aptu_core::history::AiStats,
pub dry_run: bool,
pub labels: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub security_findings: Option<Vec<aptu_core::Finding>>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
pub enum SinglePrReviewOutcome {
#[allow(dead_code)]
Success(Box<PrReviewResult>),
#[allow(dead_code)]
Skipped(String),
#[allow(dead_code)]
Failed(String),
}
impl SinglePrReviewOutcome {
pub fn as_pr_review_result(&self) -> Option<&PrReviewResult> {
match self {
SinglePrReviewOutcome::Success(result) => Some(result),
_ => None,
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct BulkPrReviewResult {
pub succeeded: usize,
pub failed: usize,
pub skipped: usize,
pub outcomes: Vec<(String, SinglePrReviewOutcome)>,
}
impl BulkPrReviewResult {
pub fn has_dry_run(&self) -> bool {
self.outcomes
.iter()
.any(|(_, outcome)| outcome.as_pr_review_result().is_some_and(|r| r.dry_run))
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct PrLabelResult {
pub pr_number: u64,
pub pr_title: String,
pub pr_url: String,
pub labels: Vec<String>,
pub dry_run: bool,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct DiscoverResult {
pub repos: Vec<DiscoveredRepo>,
}