use super::changelog::ChangelogCategory;
use clap::ValueEnum;
use serde::{Deserialize, Serialize};
use strum::AsRefStr;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkItemMeta {
#[serde(default, rename = "schema", skip_serializing)]
_schema: u32,
pub id: String,
pub title: String,
pub status: WorkItemStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub created: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub started: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub completed: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub refs: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub depends_on: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
}
impl WorkItemMeta {
pub fn new(id: impl Into<String>, title: impl Into<String>, status: WorkItemStatus) -> Self {
Self {
_schema: 1,
id: id.into(),
title: title.into(),
status,
created: None,
started: None,
completed: None,
refs: vec![],
depends_on: vec![],
tags: vec![],
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct WorkItemVerification {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_guards: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub waivers: Vec<GuardWaiver>,
}
impl WorkItemVerification {
pub fn is_empty(&self) -> bool {
self.required_guards.is_empty() && self.waivers.is_empty()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuardWaiver {
pub guard: String,
pub reason: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, AsRefStr)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum ChecklistStatus {
#[default]
Pending,
Done,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChecklistItem {
pub text: String,
#[serde(default)]
pub status: ChecklistStatus,
#[serde(default)]
pub category: ChangelogCategory,
}
impl ChecklistItem {
#[cfg(test)]
pub fn new(text: impl Into<String>) -> Self {
Self {
text: text.into(),
status: ChecklistStatus::Pending,
category: ChangelogCategory::default(),
}
}
pub fn with_category(text: impl Into<String>, category: ChangelogCategory) -> Self {
Self {
text: text.into(),
status: ChecklistStatus::Pending,
category,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JournalEntry {
pub date: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub scope: Option<String>,
pub content: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct WorkItemContent {
#[serde(default)]
pub description: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub journal: Vec<JournalEntry>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub acceptance_criteria: Vec<ChecklistItem>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkItemSpec {
pub govctl: WorkItemMeta,
pub content: WorkItemContent,
#[serde(default, skip_serializing_if = "WorkItemVerification::is_empty")]
pub verification: WorkItemVerification,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, AsRefStr, ValueEnum)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum WorkItemStatus {
Queue,
Active,
Done,
Cancelled,
}