#![cfg_attr(coverage_nightly, coverage(off))]
use anyhow::{Context, Result};
use chrono::{DateTime, Utc};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
pub mod commands;
pub mod generator;
pub mod parser;
pub mod quality;
pub mod tracker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TaskStatus {
Planned,
InProgress,
Completed,
Blocked,
Deferred,
}
impl TaskStatus {
#[must_use]
pub fn to_emoji(&self) -> &'static str {
match self {
Self::Planned => "\u{1f4cb}",
Self::InProgress => "\u{1f6a7}",
Self::Completed => "\u{2705}",
Self::Blocked => "\u{1f6ab}",
Self::Deferred => "\u{23f8}\u{fe0f}",
}
}
#[must_use]
pub fn from_emoji(emoji: &str) -> Option<Self> {
match emoji {
"\u{1f4cb}" => Some(Self::Planned),
"\u{1f6a7}" => Some(Self::InProgress),
"\u{2705}" => Some(Self::Completed),
"\u{1f6ab}" => Some(Self::Blocked),
"\u{23f8}\u{fe0f}" => Some(Self::Deferred),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Complexity {
Low,
Medium,
High,
}
impl std::str::FromStr for Complexity {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"low" => Ok(Self::Low),
"medium" => Ok(Self::Medium),
"high" => Ok(Self::High),
_ => Err(()),
}
}
}
impl Complexity {
#[must_use]
pub fn to_string(&self) -> &str {
match self {
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Priority {
P0, P1, P2, }
impl std::str::FromStr for Priority {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_uppercase().as_str() {
"P0" => Ok(Self::P0),
"P1" => Ok(Self::P1),
"P2" => Ok(Self::P2),
_ => Err(()),
}
}
}
impl Priority {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Task {
pub id: String, pub description: String,
pub status: TaskStatus,
pub complexity: Complexity,
pub priority: Priority,
pub assignee: Option<String>,
pub started_at: Option<DateTime<Utc>>,
pub completed_at: Option<DateTime<Utc>>,
}
impl Task {
#[must_use]
pub fn seed(&self) -> u64 {
if let Some(captures) = Regex::new(r"PMAT-(\d+)")
.expect("internal error")
.captures(&self.id)
{
if let Some(num) = captures.get(1) {
return num.as_str().parse().unwrap_or(42);
}
}
42 }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Sprint {
pub version: String,
pub title: String,
pub start_date: DateTime<Utc>,
pub end_date: DateTime<Utc>,
pub priority: Priority,
pub tasks: Vec<Task>,
pub definition_of_done: Vec<String>,
pub quality_gates: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Roadmap {
pub current_sprint: Option<String>,
pub sprints: HashMap<String, Sprint>,
pub backlog: Vec<Task>,
pub completed_sprints: Vec<String>,
}
include!("roadmap_methods.rs");
include!("roadmap_config.rs");
include!("roadmap_tests.rs");