use clap::ValueEnum;
use serde::Serialize;
use crate::domain::{DependencyType, Issue, IssueStatus, IssueType};
#[derive(Debug, Clone, Serialize)]
pub struct BatchResult {
pub succeeded: Vec<Issue>,
pub failed: Vec<BatchError>,
}
impl BatchResult {
pub fn new() -> Self {
Self {
succeeded: Vec::new(),
failed: Vec::new(),
}
}
pub fn is_complete_success(&self) -> bool {
self.failed.is_empty()
}
pub fn is_complete_failure(&self) -> bool {
self.succeeded.is_empty() && !self.failed.is_empty()
}
pub fn has_failures(&self) -> bool {
!self.failed.is_empty()
}
pub fn total(&self) -> usize {
self.succeeded.len() + self.failed.len()
}
}
impl Default for BatchResult {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize)]
pub struct BatchError {
pub issue_id: String,
pub error: String,
}
#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
pub enum IssueTypeArg {
Bug,
Feature,
Task,
Epic,
Chore,
}
impl std::fmt::Display for IssueTypeArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bug => write!(f, "bug"),
Self::Feature => write!(f, "feature"),
Self::Task => write!(f, "task"),
Self::Epic => write!(f, "epic"),
Self::Chore => write!(f, "chore"),
}
}
}
#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
pub enum IssueStatusArg {
Open,
#[value(name = "in_progress", alias = "in-progress")]
InProgress,
Blocked,
Closed,
}
impl std::fmt::Display for IssueStatusArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Open => write!(f, "open"),
Self::InProgress => write!(f, "in_progress"),
Self::Blocked => write!(f, "blocked"),
Self::Closed => write!(f, "closed"),
}
}
}
#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
pub enum DependencyTypeArg {
Blocks,
Related,
#[value(name = "parent-child")]
ParentChild,
#[value(name = "discovered-from")]
DiscoveredFrom,
}
impl std::fmt::Display for DependencyTypeArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Blocks => write!(f, "blocks"),
Self::Related => write!(f, "related"),
Self::ParentChild => write!(f, "parent-child"),
Self::DiscoveredFrom => write!(f, "discovered-from"),
}
}
}
#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SortOrderArg {
#[default]
Priority,
Newest,
Oldest,
Updated,
}
impl std::fmt::Display for SortOrderArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Priority => write!(f, "priority"),
Self::Newest => write!(f, "newest"),
Self::Oldest => write!(f, "oldest"),
Self::Updated => write!(f, "updated"),
}
}
}
#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SortPolicyArg {
#[default]
Hybrid,
Priority,
Oldest,
}
impl std::fmt::Display for SortPolicyArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Hybrid => write!(f, "hybrid"),
Self::Priority => write!(f, "priority"),
Self::Oldest => write!(f, "oldest"),
}
}
}
impl From<IssueTypeArg> for IssueType {
fn from(arg: IssueTypeArg) -> Self {
match arg {
IssueTypeArg::Bug => IssueType::Bug,
IssueTypeArg::Feature => IssueType::Feature,
IssueTypeArg::Task => IssueType::Task,
IssueTypeArg::Epic => IssueType::Epic,
IssueTypeArg::Chore => IssueType::Chore,
}
}
}
impl From<IssueType> for IssueTypeArg {
fn from(t: IssueType) -> Self {
match t {
IssueType::Bug => IssueTypeArg::Bug,
IssueType::Feature => IssueTypeArg::Feature,
IssueType::Task => IssueTypeArg::Task,
IssueType::Epic => IssueTypeArg::Epic,
IssueType::Chore => IssueTypeArg::Chore,
}
}
}
impl From<IssueStatusArg> for IssueStatus {
fn from(arg: IssueStatusArg) -> Self {
match arg {
IssueStatusArg::Open => IssueStatus::Open,
IssueStatusArg::InProgress => IssueStatus::InProgress,
IssueStatusArg::Blocked => IssueStatus::Blocked,
IssueStatusArg::Closed => IssueStatus::Closed,
}
}
}
impl From<IssueStatus> for IssueStatusArg {
fn from(s: IssueStatus) -> Self {
match s {
IssueStatus::Open => IssueStatusArg::Open,
IssueStatus::InProgress => IssueStatusArg::InProgress,
IssueStatus::Blocked => IssueStatusArg::Blocked,
IssueStatus::Closed => IssueStatusArg::Closed,
}
}
}
impl From<DependencyTypeArg> for DependencyType {
fn from(arg: DependencyTypeArg) -> Self {
match arg {
DependencyTypeArg::Blocks => DependencyType::Blocks,
DependencyTypeArg::Related => DependencyType::Related,
DependencyTypeArg::ParentChild => DependencyType::ParentChild,
DependencyTypeArg::DiscoveredFrom => DependencyType::DiscoveredFrom,
}
}
}
impl From<DependencyType> for DependencyTypeArg {
fn from(d: DependencyType) -> Self {
match d {
DependencyType::Blocks => DependencyTypeArg::Blocks,
DependencyType::Related => DependencyTypeArg::Related,
DependencyType::ParentChild => DependencyTypeArg::ParentChild,
DependencyType::DiscoveredFrom => DependencyTypeArg::DiscoveredFrom,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_issue_type_conversion() {
assert_eq!(IssueType::from(IssueTypeArg::Bug), IssueType::Bug);
assert_eq!(IssueType::from(IssueTypeArg::Feature), IssueType::Feature);
assert_eq!(IssueType::from(IssueTypeArg::Task), IssueType::Task);
assert_eq!(IssueType::from(IssueTypeArg::Epic), IssueType::Epic);
assert_eq!(IssueType::from(IssueTypeArg::Chore), IssueType::Chore);
assert_eq!(IssueTypeArg::from(IssueType::Bug), IssueTypeArg::Bug);
assert_eq!(
IssueTypeArg::from(IssueType::Feature),
IssueTypeArg::Feature
);
}
#[test]
fn test_issue_status_conversion() {
assert_eq!(IssueStatus::from(IssueStatusArg::Open), IssueStatus::Open);
assert_eq!(
IssueStatus::from(IssueStatusArg::InProgress),
IssueStatus::InProgress
);
assert_eq!(
IssueStatus::from(IssueStatusArg::Blocked),
IssueStatus::Blocked
);
assert_eq!(
IssueStatus::from(IssueStatusArg::Closed),
IssueStatus::Closed
);
assert_eq!(
IssueStatusArg::from(IssueStatus::Open),
IssueStatusArg::Open
);
}
#[test]
fn test_dependency_type_conversion() {
assert_eq!(
DependencyType::from(DependencyTypeArg::Blocks),
DependencyType::Blocks
);
assert_eq!(
DependencyType::from(DependencyTypeArg::Related),
DependencyType::Related
);
assert_eq!(
DependencyType::from(DependencyTypeArg::ParentChild),
DependencyType::ParentChild
);
assert_eq!(
DependencyType::from(DependencyTypeArg::DiscoveredFrom),
DependencyType::DiscoveredFrom
);
}
#[test]
fn test_display_implementations() {
assert_eq!(format!("{}", IssueTypeArg::Bug), "bug");
assert_eq!(format!("{}", IssueStatusArg::InProgress), "in_progress");
assert_eq!(
format!("{}", DependencyTypeArg::ParentChild),
"parent-child"
);
assert_eq!(format!("{}", SortOrderArg::Priority), "priority");
assert_eq!(format!("{}", SortPolicyArg::Hybrid), "hybrid");
}
}