huskies: merge 942
This commit is contained in:
@@ -222,6 +222,55 @@ pub(crate) fn next_item_number(_root: &std::path::Path) -> Result<u32, String> {
|
||||
Ok(crate::db::next_item_number())
|
||||
}
|
||||
|
||||
/// Single internal entry point for creating a new pipeline work item in the backlog.
|
||||
///
|
||||
/// This is the canonical creation path. All `create_*_file` functions for pipeline
|
||||
/// item types (story, bug, spike, refactor) route through here. On validation failure
|
||||
/// this function returns `Err` and writes nothing.
|
||||
///
|
||||
/// Validates:
|
||||
/// - `name` is not empty or whitespace-only
|
||||
/// - `name` contains at least one alphanumeric character
|
||||
/// - `acceptance_criteria` has at least one entry
|
||||
/// - `item_type` is a known pipeline item type
|
||||
///
|
||||
/// `build_content` receives the assigned item number and returns the full markdown
|
||||
/// content to persist (including front matter and all type-specific sections).
|
||||
pub(crate) fn create_item_in_backlog(
|
||||
root: &Path,
|
||||
item_type: &str,
|
||||
name: &str,
|
||||
acceptance_criteria: &[String],
|
||||
depends_on: Option<&[u32]>,
|
||||
build_content: impl FnOnce(u32) -> String,
|
||||
) -> Result<String, String> {
|
||||
if name.trim().is_empty() {
|
||||
return Err("Title must not be empty or whitespace-only.".to_string());
|
||||
}
|
||||
if slugify_name(name).is_empty() {
|
||||
return Err("Title must contain at least one alphanumeric character.".to_string());
|
||||
}
|
||||
if acceptance_criteria.is_empty() {
|
||||
return Err("At least one acceptance criterion is required.".to_string());
|
||||
}
|
||||
const VALID_TYPES: &[&str] = &["story", "bug", "spike", "refactor"];
|
||||
if !VALID_TYPES.contains(&item_type) {
|
||||
return Err(format!(
|
||||
"Invalid item type '{item_type}': must be one of story, bug, spike, refactor."
|
||||
));
|
||||
}
|
||||
|
||||
let item_number = next_item_number(root)?;
|
||||
let item_id = format!("{item_number}");
|
||||
let content = build_content(item_number);
|
||||
|
||||
write_story_content(root, &item_id, "1_backlog", &content, Some(name));
|
||||
crate::crdt_state::set_depends_on(&item_id, depends_on.unwrap_or(&[]));
|
||||
crate::crdt_state::set_item_type(&item_id, Some(item_type));
|
||||
|
||||
Ok(item_id)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user