Files
huskies/server/src/service/gateway/polling.rs
T

92 lines
3.4 KiB
Rust
Raw Normal View History

//! Gateway notification polling — pure event formatting.
//!
//! Formats pipeline events from project containers into gateway notifications
//! with `[project-name]` prefixes. The actual I/O (HTTP polling, spawning
//! tasks, sending messages) lives in `io.rs`.
use crate::service::events::StoredEvent;
use crate::service::notifications::{
format_blocked_notification, format_error_notification, format_stage_notification,
stage_display_name,
};
/// Format a [`StoredEvent`] from a project into a gateway notification.
///
/// Prefixes the message with `[project-name]` so users can distinguish which
/// project emitted the event.
pub fn format_gateway_event(project_name: &str, event: &StoredEvent) -> (String, String) {
let prefix = format!("[{project_name}] ");
match event {
StoredEvent::StageTransition {
story_id,
from_stage,
to_stage,
..
} => {
let from_display = stage_display_name(from_stage);
let to_display = stage_display_name(to_stage);
let (plain, html) = format_stage_notification(story_id, None, from_display, to_display);
(format!("{prefix}{plain}"), format!("{prefix}{html}"))
}
StoredEvent::MergeFailure {
story_id, reason, ..
} => {
let (plain, html) = format_error_notification(story_id, None, reason);
(format!("{prefix}{plain}"), format!("{prefix}{html}"))
}
StoredEvent::StoryBlocked {
story_id, reason, ..
} => {
let (plain, html) = format_blocked_notification(story_id, None, reason);
(format!("{prefix}{plain}"), format!("{prefix}{html}"))
}
}
}
// ── Tests ────────────────────────────────────────────────────────────────────
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stage_transition_prefixes_project_name() {
let event = StoredEvent::StageTransition {
story_id: "42_story_my_feature".to_string(),
from_stage: "2_current".to_string(),
to_stage: "3_qa".to_string(),
timestamp_ms: 1000,
};
let (plain, html) = format_gateway_event("huskies", &event);
assert!(plain.starts_with("[huskies] "));
assert!(html.starts_with("[huskies] "));
assert!(plain.contains("Current"));
assert!(plain.contains("QA"));
}
#[test]
fn merge_failure_prefixes_project_name() {
let event = StoredEvent::MergeFailure {
story_id: "42_story_my_feature".to_string(),
reason: "merge conflict".to_string(),
timestamp_ms: 1000,
};
let (plain, _html) = format_gateway_event("robot-studio", &event);
assert!(plain.starts_with("[robot-studio] "));
assert!(plain.contains("merge conflict"));
}
#[test]
fn story_blocked_prefixes_project_name() {
let event = StoredEvent::StoryBlocked {
story_id: "43_story_bar".to_string(),
reason: "retry limit exceeded".to_string(),
timestamp_ms: 2000,
};
let (plain, _html) = format_gateway_event("huskies", &event);
assert!(plain.starts_with("[huskies] "));
assert!(plain.contains("BLOCKED"));
}
}