huskies: merge 940
This commit is contained in:
@@ -33,12 +33,16 @@ pub fn format_stage_notification(
|
||||
to_stage: &str,
|
||||
) -> (String, String) {
|
||||
let number = extract_item_number(item_id).unwrap_or(item_id);
|
||||
let name = story_name.unwrap_or(item_id);
|
||||
let effective_name = story_name.filter(|n| !n.is_empty());
|
||||
let name_plain = effective_name.map(|n| format!("{n} ")).unwrap_or_default();
|
||||
let name_html = effective_name
|
||||
.map(|n| format!("<em>{n}</em> "))
|
||||
.unwrap_or_default();
|
||||
|
||||
let prefix = if to_stage == "Done" { "\u{1f389} " } else { "" };
|
||||
let plain = format!("{prefix}#{number} {name} \u{2014} {from_stage} \u{2192} {to_stage}");
|
||||
let plain = format!("{prefix}#{number} {name_plain}\u{2014} {from_stage} \u{2192} {to_stage}");
|
||||
let html = format!(
|
||||
"{prefix}<strong>#{number}</strong> <em>{name}</em> \u{2014} {from_stage} \u{2192} {to_stage}"
|
||||
"{prefix}<strong>#{number}</strong> {name_html}\u{2014} {from_stage} \u{2192} {to_stage}"
|
||||
);
|
||||
(plain, html)
|
||||
}
|
||||
@@ -52,10 +56,14 @@ pub fn format_error_notification(
|
||||
reason: &str,
|
||||
) -> (String, String) {
|
||||
let number = extract_item_number(item_id).unwrap_or(item_id);
|
||||
let name = story_name.unwrap_or(item_id);
|
||||
let effective_name = story_name.filter(|n| !n.is_empty());
|
||||
let name_plain = effective_name.map(|n| format!("{n} ")).unwrap_or_default();
|
||||
let name_html = effective_name
|
||||
.map(|n| format!("<em>{n}</em> "))
|
||||
.unwrap_or_default();
|
||||
|
||||
let plain = format!("\u{274c} #{number} {name} \u{2014} {reason}");
|
||||
let html = format!("\u{274c} <strong>#{number}</strong> <em>{name}</em> \u{2014} {reason}");
|
||||
let plain = format!("\u{274c} #{number} {name_plain}\u{2014} {reason}");
|
||||
let html = format!("\u{274c} <strong>#{number}</strong> {name_html}\u{2014} {reason}");
|
||||
(plain, html)
|
||||
}
|
||||
|
||||
@@ -68,11 +76,15 @@ pub fn format_blocked_notification(
|
||||
reason: &str,
|
||||
) -> (String, String) {
|
||||
let number = extract_item_number(item_id).unwrap_or(item_id);
|
||||
let name = story_name.unwrap_or(item_id);
|
||||
let effective_name = story_name.filter(|n| !n.is_empty());
|
||||
let name_plain = effective_name.map(|n| format!("{n} ")).unwrap_or_default();
|
||||
let name_html = effective_name
|
||||
.map(|n| format!("<em>{n}</em> "))
|
||||
.unwrap_or_default();
|
||||
|
||||
let plain = format!("\u{1f6ab} #{number} {name} \u{2014} BLOCKED: {reason}");
|
||||
let plain = format!("\u{1f6ab} #{number} {name_plain}\u{2014} BLOCKED: {reason}");
|
||||
let html =
|
||||
format!("\u{1f6ab} <strong>#{number}</strong> <em>{name}</em> \u{2014} BLOCKED: {reason}");
|
||||
format!("\u{1f6ab} <strong>#{number}</strong> {name_html}\u{2014} BLOCKED: {reason}");
|
||||
(plain, html)
|
||||
}
|
||||
|
||||
@@ -85,12 +97,17 @@ pub fn format_rate_limit_notification(
|
||||
agent_name: &str,
|
||||
) -> (String, String) {
|
||||
let number = extract_item_number(item_id).unwrap_or(item_id);
|
||||
let name = story_name.unwrap_or(item_id);
|
||||
let effective_name = story_name.filter(|n| !n.is_empty());
|
||||
let name_plain = effective_name.map(|n| format!("{n} ")).unwrap_or_default();
|
||||
let name_html = effective_name
|
||||
.map(|n| format!("<em>{n}</em> "))
|
||||
.unwrap_or_default();
|
||||
|
||||
let plain =
|
||||
format!("\u{26a0}\u{fe0f} #{number} {name} \u{2014} {agent_name} hit an API rate limit");
|
||||
let plain = format!(
|
||||
"\u{26a0}\u{fe0f} #{number} {name_plain}\u{2014} {agent_name} hit an API rate limit"
|
||||
);
|
||||
let html = format!(
|
||||
"\u{26a0}\u{fe0f} <strong>#{number}</strong> <em>{name}</em> \u{2014} \
|
||||
"\u{26a0}\u{fe0f} <strong>#{number}</strong> {name_html}\u{2014} \
|
||||
{agent_name} hit an API rate limit"
|
||||
);
|
||||
(plain, html)
|
||||
@@ -127,11 +144,15 @@ pub fn format_agent_started_notification(
|
||||
agent_name: &str,
|
||||
) -> (String, String) {
|
||||
let number = extract_item_number(item_id).unwrap_or(item_id);
|
||||
let name = story_name.unwrap_or(item_id);
|
||||
let plain = format!("\u{1F916} #{number} {name} \u{2014} {agent_name} started");
|
||||
let html = format!(
|
||||
"\u{1F916} <strong>#{number}</strong> <em>{name}</em> \u{2014} {agent_name} started"
|
||||
);
|
||||
let effective_name = story_name.filter(|n| !n.is_empty());
|
||||
let name_plain = effective_name.map(|n| format!("{n} ")).unwrap_or_default();
|
||||
let name_html = effective_name
|
||||
.map(|n| format!("<em>{n}</em> "))
|
||||
.unwrap_or_default();
|
||||
|
||||
let plain = format!("\u{1F916} #{number} {name_plain}\u{2014} {agent_name} started");
|
||||
let html =
|
||||
format!("\u{1F916} <strong>#{number}</strong> {name_html}\u{2014} {agent_name} started");
|
||||
(plain, html)
|
||||
}
|
||||
|
||||
@@ -146,16 +167,20 @@ pub fn format_agent_completed_notification(
|
||||
success: bool,
|
||||
) -> (String, String) {
|
||||
let number = extract_item_number(item_id).unwrap_or(item_id);
|
||||
let name = story_name.unwrap_or(item_id);
|
||||
let effective_name = story_name.filter(|n| !n.is_empty());
|
||||
let name_plain = effective_name.map(|n| format!("{n} ")).unwrap_or_default();
|
||||
let name_html = effective_name
|
||||
.map(|n| format!("<em>{n}</em> "))
|
||||
.unwrap_or_default();
|
||||
|
||||
let (emoji, result) = if success {
|
||||
("\u{2705}", "completed") // ✅
|
||||
} else {
|
||||
("\u{274C}", "failed") // ❌
|
||||
};
|
||||
let plain = format!("{emoji} #{number} {name} \u{2014} {agent_name} {result}");
|
||||
let html = format!(
|
||||
"{emoji} <strong>#{number}</strong> <em>{name}</em> \u{2014} {agent_name} {result}"
|
||||
);
|
||||
let plain = format!("{emoji} #{number} {name_plain}\u{2014} {agent_name} {result}");
|
||||
let html =
|
||||
format!("{emoji} <strong>#{number}</strong> {name_html}\u{2014} {agent_name} {result}");
|
||||
(plain, html)
|
||||
}
|
||||
|
||||
@@ -241,9 +266,10 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_notification_without_story_name_falls_back_to_item_id() {
|
||||
let (plain, _html) = format_stage_notification("42_bug_fix_thing", None, "Current", "QA");
|
||||
assert_eq!(plain, "#42 42_bug_fix_thing \u{2014} Current \u{2192} QA");
|
||||
fn format_stage_notification_without_story_name_falls_back_to_number() {
|
||||
let (plain, html) = format_stage_notification("42_bug_fix_thing", None, "Current", "QA");
|
||||
assert_eq!(plain, "#42 \u{2014} Current \u{2192} QA");
|
||||
assert_eq!(html, "<strong>#42</strong> \u{2014} Current \u{2192} QA");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -265,12 +291,10 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_stage_notification_empty_story_name_falls_back_to_id() {
|
||||
// Some("") is a valid Some but empty — treat as missing? Currently we use it as-is.
|
||||
let (plain, _html) = format_stage_notification("42_story_empty", Some(""), "Current", "QA");
|
||||
// The name slot is empty but the structure is still correct.
|
||||
assert!(plain.contains("#42"));
|
||||
assert!(plain.contains("Current \u{2192} QA"));
|
||||
fn format_stage_notification_empty_story_name_falls_back_to_number() {
|
||||
let (plain, html) = format_stage_notification("42_story_empty", Some(""), "Current", "QA");
|
||||
assert_eq!(plain, "#42 \u{2014} Current \u{2192} QA");
|
||||
assert_eq!(html, "<strong>#42</strong> \u{2014} Current \u{2192} QA");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -301,9 +325,10 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_error_notification_without_story_name_falls_back_to_item_id() {
|
||||
let (plain, _html) = format_error_notification("42_bug_fix_thing", None, "tests failed");
|
||||
assert_eq!(plain, "\u{274c} #42 42_bug_fix_thing \u{2014} tests failed");
|
||||
fn format_error_notification_without_story_name_falls_back_to_number() {
|
||||
let (plain, html) = format_error_notification("42_bug_fix_thing", None, "tests failed");
|
||||
assert_eq!(plain, "\u{274c} #42 \u{2014} tests failed");
|
||||
assert_eq!(html, "\u{274c} <strong>#42</strong> \u{2014} tests failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -330,6 +355,13 @@ mod tests {
|
||||
assert!(plain.contains("错误:合并冲突"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_error_notification_empty_story_name_falls_back_to_number() {
|
||||
let (plain, _html) =
|
||||
format_error_notification("42_bug_fix_thing", Some(""), "tests failed");
|
||||
assert_eq!(plain, "\u{274c} #42 \u{2014} tests failed");
|
||||
}
|
||||
|
||||
// ── format_blocked_notification ───────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
@@ -350,14 +382,21 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_blocked_notification_falls_back_to_item_id() {
|
||||
let (plain, _html) = format_blocked_notification("42_story_thing", None, "empty diff");
|
||||
fn format_blocked_notification_falls_back_to_number() {
|
||||
let (plain, html) = format_blocked_notification("42_story_thing", None, "empty diff");
|
||||
assert_eq!(plain, "\u{1f6ab} #42 \u{2014} BLOCKED: empty diff");
|
||||
assert_eq!(
|
||||
plain,
|
||||
"\u{1f6ab} #42 42_story_thing \u{2014} BLOCKED: empty diff"
|
||||
html,
|
||||
"\u{1f6ab} <strong>#42</strong> \u{2014} BLOCKED: empty diff"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_blocked_notification_empty_story_name_falls_back_to_number() {
|
||||
let (plain, _html) = format_blocked_notification("42_story_thing", Some(""), "empty diff");
|
||||
assert_eq!(plain, "\u{1f6ab} #42 \u{2014} BLOCKED: empty diff");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_blocked_notification_unicode_reason() {
|
||||
let (plain, _html) = format_blocked_notification("3_story_x", Some("X"), "理由:空の差分");
|
||||
@@ -381,11 +420,24 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_rate_limit_notification_falls_back_to_item_id() {
|
||||
let (plain, _html) = format_rate_limit_notification("42_story_thing", None, "coder-1");
|
||||
fn format_rate_limit_notification_falls_back_to_number() {
|
||||
let (plain, html) = format_rate_limit_notification("42_story_thing", None, "coder-1");
|
||||
assert_eq!(
|
||||
plain,
|
||||
"\u{26a0}\u{fe0f} #42 42_story_thing \u{2014} coder-1 hit an API rate limit"
|
||||
"\u{26a0}\u{fe0f} #42 \u{2014} coder-1 hit an API rate limit"
|
||||
);
|
||||
assert_eq!(
|
||||
html,
|
||||
"\u{26a0}\u{fe0f} <strong>#42</strong> \u{2014} coder-1 hit an API rate limit"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_rate_limit_notification_empty_story_name_falls_back_to_number() {
|
||||
let (plain, _html) = format_rate_limit_notification("42_story_thing", Some(""), "coder-1");
|
||||
assert_eq!(
|
||||
plain,
|
||||
"\u{26a0}\u{fe0f} #42 \u{2014} coder-1 hit an API rate limit"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -395,4 +447,79 @@ mod tests {
|
||||
assert!(plain.contains("агент-1"));
|
||||
assert!(plain.contains("hit an API rate limit"));
|
||||
}
|
||||
|
||||
// ── format_agent_started_notification ─────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn format_agent_started_notification_with_story_name() {
|
||||
let (plain, html) =
|
||||
format_agent_started_notification("42_story_foo", Some("My Feature"), "coder-1");
|
||||
assert_eq!(plain, "\u{1F916} #42 My Feature \u{2014} coder-1 started");
|
||||
assert_eq!(
|
||||
html,
|
||||
"\u{1F916} <strong>#42</strong> <em>My Feature</em> \u{2014} coder-1 started"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_agent_started_notification_falls_back_to_number() {
|
||||
let (plain, html) = format_agent_started_notification("42_story_foo", None, "coder-1");
|
||||
assert_eq!(plain, "\u{1F916} #42 \u{2014} coder-1 started");
|
||||
assert_eq!(
|
||||
html,
|
||||
"\u{1F916} <strong>#42</strong> \u{2014} coder-1 started"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_agent_started_notification_empty_name_falls_back_to_number() {
|
||||
let (plain, _html) = format_agent_started_notification("42_story_foo", Some(""), "coder-1");
|
||||
assert_eq!(plain, "\u{1F916} #42 \u{2014} coder-1 started");
|
||||
}
|
||||
|
||||
// ── format_agent_completed_notification ───────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn format_agent_completed_notification_success_with_story_name() {
|
||||
let (plain, html) = format_agent_completed_notification(
|
||||
"42_story_foo",
|
||||
Some("My Feature"),
|
||||
"coder-1",
|
||||
true,
|
||||
);
|
||||
assert_eq!(plain, "\u{2705} #42 My Feature \u{2014} coder-1 completed");
|
||||
assert_eq!(
|
||||
html,
|
||||
"\u{2705} <strong>#42</strong> <em>My Feature</em> \u{2014} coder-1 completed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_agent_completed_notification_failure_with_story_name() {
|
||||
let (plain, _html) = format_agent_completed_notification(
|
||||
"42_story_foo",
|
||||
Some("My Feature"),
|
||||
"coder-1",
|
||||
false,
|
||||
);
|
||||
assert_eq!(plain, "\u{274C} #42 My Feature \u{2014} coder-1 failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_agent_completed_notification_falls_back_to_number() {
|
||||
let (plain, html) =
|
||||
format_agent_completed_notification("42_story_foo", None, "coder-1", true);
|
||||
assert_eq!(plain, "\u{2705} #42 \u{2014} coder-1 completed");
|
||||
assert_eq!(
|
||||
html,
|
||||
"\u{2705} <strong>#42</strong> \u{2014} coder-1 completed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_agent_completed_notification_empty_name_falls_back_to_number() {
|
||||
let (plain, _html) =
|
||||
format_agent_completed_notification("42_story_foo", Some(""), "coder-1", false);
|
||||
assert_eq!(plain, "\u{274C} #42 \u{2014} coder-1 failed");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user