huskies: merge 1035

This commit is contained in:
dave
2026-05-14 13:17:38 +00:00
parent c353c0a6be
commit f1c96595de
6 changed files with 141 additions and 8 deletions
+105 -5
View File
@@ -20,25 +20,33 @@ pub fn format_gateway_event(project_name: &str, event: &StoredEvent) -> (String,
match event {
StoredEvent::StageTransition {
story_id,
story_name,
from_stage,
to_stage,
..
} => {
let from_typed = Stage::from_dir(from_stage).unwrap_or(Stage::Upcoming);
let to_typed = Stage::from_dir(to_stage).unwrap_or(Stage::Upcoming);
let (plain, html) = format_stage_notification(story_id, "", &from_typed, &to_typed);
let (plain, html) =
format_stage_notification(story_id, story_name, &from_typed, &to_typed);
(format!("{prefix}{plain}"), format!("{prefix}{html}"))
}
StoredEvent::MergeFailure {
story_id, reason, ..
story_id,
story_name,
reason,
..
} => {
let (plain, html) = format_error_notification(story_id, "", reason);
let (plain, html) = format_error_notification(story_id, story_name, reason);
(format!("{prefix}{plain}"), format!("{prefix}{html}"))
}
StoredEvent::StoryBlocked {
story_id, reason, ..
story_id,
story_name,
reason,
..
} => {
let (plain, html) = format_blocked_notification(story_id, "", reason);
let (plain, html) = format_blocked_notification(story_id, story_name, reason);
(format!("{prefix}{plain}"), format!("{prefix}{html}"))
}
}
@@ -54,6 +62,7 @@ mod tests {
fn stage_transition_prefixes_project_name() {
let event = StoredEvent::StageTransition {
story_id: "42_story_my_feature".to_string(),
story_name: String::new(),
from_stage: "coding".to_string(),
to_stage: "qa".to_string(),
timestamp_ms: 1000,
@@ -69,6 +78,7 @@ mod tests {
fn merge_failure_prefixes_project_name() {
let event = StoredEvent::MergeFailure {
story_id: "42_story_my_feature".to_string(),
story_name: String::new(),
reason: "merge conflict".to_string(),
timestamp_ms: 1000,
};
@@ -81,6 +91,7 @@ mod tests {
fn story_blocked_prefixes_project_name() {
let event = StoredEvent::StoryBlocked {
story_id: "43_story_bar".to_string(),
story_name: String::new(),
reason: "retry limit exceeded".to_string(),
timestamp_ms: 2000,
};
@@ -88,4 +99,93 @@ mod tests {
assert!(plain.starts_with("[huskies] "));
assert!(plain.contains("BLOCKED"));
}
#[test]
fn stage_transition_with_story_name_includes_title() {
let event = StoredEvent::StageTransition {
story_id: "10_story_feat".to_string(),
story_name: "My New Feature".to_string(),
from_stage: "backlog".to_string(),
to_stage: "coding".to_string(),
timestamp_ms: 100,
};
let (plain, html) = format_gateway_event("huskies", &event);
assert!(plain.starts_with("[huskies] "));
assert!(
plain.contains("My New Feature"),
"plain must include story title; got: {plain}"
);
assert!(
html.contains("My New Feature"),
"html must include story title; got: {html}"
);
assert!(plain.contains("#10"));
assert!(plain.contains("Backlog"));
assert!(plain.contains("Current"));
}
#[test]
fn merge_failure_with_story_name_includes_title() {
let event = StoredEvent::MergeFailure {
story_id: "7_story_bar".to_string(),
story_name: "Bar Feature".to_string(),
reason: "conflict in lib.rs".to_string(),
timestamp_ms: 200,
};
let (plain, html) = format_gateway_event("robot-studio", &event);
assert!(plain.starts_with("[robot-studio] "));
assert!(
plain.contains("Bar Feature"),
"plain must include story title; got: {plain}"
);
assert!(
html.contains("Bar Feature"),
"html must include story title; got: {html}"
);
assert!(plain.contains("#7"));
assert!(plain.contains("conflict in lib.rs"));
}
#[test]
fn story_blocked_with_story_name_includes_title() {
let event = StoredEvent::StoryBlocked {
story_id: "3_story_baz".to_string(),
story_name: "Baz Story".to_string(),
reason: "retry limit exceeded".to_string(),
timestamp_ms: 300,
};
let (plain, html) = format_gateway_event("huskies", &event);
assert!(plain.starts_with("[huskies] "));
assert!(
plain.contains("Baz Story"),
"plain must include story title; got: {plain}"
);
assert!(
html.contains("Baz Story"),
"html must include story title; got: {html}"
);
assert!(plain.contains("#3"));
assert!(plain.contains("BLOCKED"));
}
#[test]
fn unnamed_story_falls_back_gracefully() {
let event = StoredEvent::StageTransition {
story_id: "5_story_unnamed".to_string(),
story_name: String::new(),
from_stage: "backlog".to_string(),
to_stage: "qa".to_string(),
timestamp_ms: 50,
};
let (plain, _html) = format_gateway_event("proj", &event);
assert!(plain.starts_with("[proj] "));
assert!(plain.contains("#5"));
assert!(plain.contains("Backlog"));
assert!(plain.contains("QA"));
// Must NOT contain stray empty-name artefacts between # and —
assert!(
!plain.contains(" "),
"should not have double spaces from empty name; got: {plain}"
);
}
}