pub fn status_looks_like_descriptive_completion(status: &str) -> bool {
let normalized = status.trim().to_ascii_lowercase();
if normalized.is_empty() {
return false;
}
let has_success_cue = [
"complete",
"completed",
"done",
"finished",
"success",
"succeeded",
"resolved",
"applied",
"patched",
"handled",
"closed",
"acknowledged",
"fixed",
"verified",
"skipped",
"merged",
"implemented",
"addressed",
"nothing to do",
"nothing to trade",
"no changes needed",
"already implemented",
]
.iter()
.any(|cue| normalized.contains(cue));
if !has_success_cue {
return false;
}
let has_failure_cue = [
"error",
"failed",
"failure",
"blocked",
"cannot",
"can't",
"unable",
"retry",
"rate limit",
"timed out",
"incomplete",
"unresolved",
"unsuccessful",
"unaddressed",
"unhandled",
"unverified",
"unapplied",
"unpatched",
"not fixed",
"not_fixed",
"not done",
"not_done",
"overdue",
]
.iter()
.any(|cue| normalized.contains(cue));
!has_failure_cue
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn addressed_is_completion() {
assert!(status_looks_like_descriptive_completion("addressed"));
assert!(status_looks_like_descriptive_completion(
"duplicate_skipped"
));
}
#[test]
fn negations_are_not_completion() {
assert!(!status_looks_like_descriptive_completion("unresolved"));
assert!(!status_looks_like_descriptive_completion("incomplete"));
assert!(!status_looks_like_descriptive_completion("not_fixed"));
assert!(!status_looks_like_descriptive_completion("unaddressed"));
}
#[test]
fn failure_cues_still_win() {
assert!(!status_looks_like_descriptive_completion(
"addressed_but_tests_failed"
));
assert!(!status_looks_like_descriptive_completion(
"resolved_with_error"
));
assert!(!status_looks_like_descriptive_completion(
"done_but_blocked_on_ci"
));
}
#[test]
fn non_completions_stay_false() {
assert!(!status_looks_like_descriptive_completion("in_progress"));
assert!(!status_looks_like_descriptive_completion(
"waiting_on_dependency"
));
assert!(!status_looks_like_descriptive_completion(""));
}
#[test]
fn every_success_cue_is_completion() {
for cue in [
"complete",
"completed",
"done",
"finished",
"success",
"succeeded",
"resolved",
"applied",
"patched",
"handled",
"closed",
"acknowledged",
"fixed",
"verified",
"skipped",
"merged",
"implemented",
"addressed",
"nothing to do",
"nothing to trade",
"no changes needed",
"already implemented",
] {
assert!(status_looks_like_descriptive_completion(cue), "{cue}");
}
}
#[test]
fn underscore_suffixes_are_completion() {
for suffix in [
"addressed",
"skipped",
"done",
"fixed",
"complete",
"completed",
"resolved",
"handled",
"applied",
"patched",
] {
let status = format!("issue_{suffix}");
assert!(
status_looks_like_descriptive_completion(&status),
"{status}"
);
}
}
#[test]
fn every_failure_cue_wins_over_success() {
for cue in [
"error",
"failed",
"failure",
"blocked",
"cannot",
"can't",
"unable",
"retry",
"rate limit",
"timed out",
"incomplete",
"unresolved",
"unsuccessful",
"unaddressed",
"unhandled",
"unverified",
"unapplied",
"unpatched",
"not fixed",
"not_fixed",
"not done",
"not_done",
"overdue",
] {
let status = format!("done {cue}");
assert!(
!status_looks_like_descriptive_completion(&status),
"{status}"
);
}
}
#[test]
fn input_is_trimmed_and_case_insensitive() {
assert!(status_looks_like_descriptive_completion(" DONE \n"));
assert!(!status_looks_like_descriptive_completion(
" Done But FAILED "
));
assert!(!status_looks_like_descriptive_completion(" "));
}
}