use std::{cmp::Ordering, collections::HashSet, fmt::Display}; use serde::{Deserialize, Serialize}; use sled::IVec; use crate::jira::Issue; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct MergeRequestRef { pub url: String, pub state: String, } #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct Task { pub jira_key: String, pub description: String, pub merge_requests: Vec, pub jira_priority: i64, pub local_priority: i64, pub status: String, pub tags: HashSet, } const STATUS_PRIORITY: [&str; 4] = ["Blocked", "InProgress", "DevReady", "Backlog"]; impl PartialOrd for Task { /// We sort tasks first by their status. If those are equal, we sort by their priority, favoring the `local_priority`. fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Task { fn cmp(&self, other: &Self) -> std::cmp::Ordering { if self.eq(other) { return Ordering::Equal; } { let a = STATUS_PRIORITY.iter().position(|s| **s == self.status); let b = STATUS_PRIORITY.iter().position(|s| **s == other.status); let o = a.cmp(&b); if o != Ordering::Equal { return o; } } { let o = self.local_priority.cmp(&other.local_priority); if o != Ordering::Equal { return o; } } self.jira_priority.cmp(&other.jira_priority) } } impl Display for Task { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { description, jira_key, merge_requests, jira_priority, local_priority, status, tags, } = self; let tags_text = tags .iter() .map(String::as_str) .collect::>() .join(", "); let mr_text = if merge_requests.len() > 0 { format!(" {} MRs", merge_requests.len()) } else { "".into() }; f.write_fmt(format_args!( "{jira_key} {status:>10} {jira_priority} {description} [{tags_text}]{mr_text}", )) } } impl TryFrom for Task { type Error = anyhow::Error; fn try_from(value: IVec) -> std::prelude::v1::Result { serde_json::from_slice(&value).map_err(|e| e.into()) } } impl TryInto for &Task { type Error = anyhow::Error; fn try_into(self) -> std::prelude::v1::Result { Ok(IVec::from(serde_json::to_vec(self)?)) } } impl TryFrom<&Issue> for Task { type Error = anyhow::Error; fn try_from(value: &Issue) -> std::prelude::v1::Result { let mut tags = HashSet::from_iter(value.fields.labels.iter().map(|s| s.to_owned())); if let Some(cs) = &value.fields.components { for c in cs.iter().map(|c| c.name.to_owned()) { tags.insert(c); } } Ok(Self { jira_key: value.key.to_owned(), description: value.fields.summary.to_owned(), merge_requests: vec![], jira_priority: value.fields.priority.id.parse()?, local_priority: value.fields.priority.id.parse()?, status: value.fields.status.name.to_owned(), tags, }) } }