impl Roadmap {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new(github_repo: Option<String>) -> Self {
Self {
roadmap_version: ROADMAP_VERSION.to_string(),
github_enabled: true,
github_repo,
roadmap: Vec::new(),
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn find_item(&self, id: &str) -> Option<&RoadmapItem> {
let id_lower = id.to_lowercase();
if let Some(item) = self.roadmap.iter().find(|item| item.id == id) {
return Some(item);
}
if let Some(item) = self
.roadmap
.iter()
.find(|item| item.id.to_lowercase() == id_lower)
{
return Some(item);
}
if let Some(item) = self
.roadmap
.iter()
.find(|item| item.id.to_lowercase().starts_with(&id_lower))
{
return Some(item);
}
self.roadmap
.iter()
.find(|item| item.id.to_lowercase().contains(&id_lower))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn find_item_by_github_issue(&self, issue: u64) -> Option<&RoadmapItem> {
self.roadmap
.iter()
.find(|item| item.github_issue == Some(issue))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn find_item_mut(&mut self, id: &str) -> Option<&mut RoadmapItem> {
self.roadmap.iter_mut().find(|item| item.id == id)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn upsert_item(&mut self, item: RoadmapItem) {
if let Some(existing) = self.find_item_mut(&item.id) {
*existing = item;
} else {
self.roadmap.push(item);
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn remove_item(&mut self, id: &str) -> Option<RoadmapItem> {
if let Some(pos) = self.roadmap.iter().position(|item| item.id == id) {
Some(self.roadmap.remove(pos))
} else {
None
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn yaml_only_items(&self) -> Vec<&RoadmapItem> {
self.roadmap
.iter()
.filter(|item| item.github_issue.is_none())
.collect()
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn epic_items(&self) -> Vec<&RoadmapItem> {
self.roadmap
.iter()
.filter(|item| item.item_type == ItemType::Epic)
.collect()
}
}
impl RoadmapItem {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new(id: String, title: String) -> Self {
let now = chrono::Utc::now().to_rfc3339();
Self {
id,
github_issue: None,
item_type: ItemType::Task,
title,
status: ItemStatus::Planned,
priority: Priority::Medium,
assigned_to: None,
created: now.clone(),
updated: now,
spec: None,
acceptance_criteria: Vec::new(),
phases: Vec::new(),
subtasks: Vec::new(),
estimated_effort: None,
labels: Vec::new(),
notes: None,
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn from_github_issue(issue_number: u64, title: String) -> Self {
let id = format!("GH-{}", issue_number);
let mut item = Self::new(id, title);
item.github_issue = Some(issue_number);
item
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn completion_percentage(&self) -> u8 {
if !self.subtasks.is_empty() {
let total: u16 = self.subtasks.iter().map(|st| st.completion as u16).sum();
(total / self.subtasks.len() as u16) as u8
} else if !self.phases.is_empty() {
let total: u16 = self.phases.iter().map(|p| p.completion as u16).sum();
(total / self.phases.len() as u16) as u8
} else if !self.acceptance_criteria.is_empty() {
0 } else {
match self.status {
ItemStatus::Planned => 0,
ItemStatus::InProgress => 50,
ItemStatus::Review => 90,
ItemStatus::Completed => 100,
ItemStatus::Cancelled => 0,
ItemStatus::Blocked => 0,
}
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_github_synced(&self) -> bool {
self.github_issue.is_some()
}
}