mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-01 02:04:24 +00:00
116 lines
3.5 KiB
Rust
116 lines
3.5 KiB
Rust
use std::fmt;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub(crate) enum ResolveRunError {
|
|
InvalidSelector,
|
|
AmbiguousPrefix {
|
|
selector: String,
|
|
matches: Vec<String>,
|
|
},
|
|
NotFound {
|
|
selector: String,
|
|
},
|
|
}
|
|
|
|
impl fmt::Display for ResolveRunError {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::InvalidSelector => write!(f, "Run selector must not be empty."),
|
|
Self::AmbiguousPrefix { selector, matches } => write!(
|
|
f,
|
|
"Ambiguous prefix '{selector}': {} runs match: {}",
|
|
matches.len(),
|
|
matches.join(", ")
|
|
),
|
|
Self::NotFound { selector } => write!(
|
|
f,
|
|
"No run found matching '{selector}' (tried run ID prefix and workflow name)"
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn resolve_run_by_selector<
|
|
'a,
|
|
T,
|
|
FRunId,
|
|
FWorkflowSlug,
|
|
FWorkflowName,
|
|
FCreatedAt,
|
|
FCreatedAtLabel,
|
|
FRepoOriginUrl,
|
|
K,
|
|
>(
|
|
runs: &'a [T],
|
|
selector: &str,
|
|
run_id: FRunId,
|
|
workflow_slug: FWorkflowSlug,
|
|
workflow_name: FWorkflowName,
|
|
created_at: FCreatedAt,
|
|
created_at_label: FCreatedAtLabel,
|
|
repo_origin_url: FRepoOriginUrl,
|
|
) -> Result<&'a T, ResolveRunError>
|
|
where
|
|
FRunId: Fn(&T) -> String,
|
|
FWorkflowSlug: Fn(&T) -> Option<String>,
|
|
FWorkflowName: Fn(&T) -> Option<String>,
|
|
FCreatedAt: Fn(&T) -> K,
|
|
FCreatedAtLabel: Fn(&T) -> String,
|
|
FRepoOriginUrl: Fn(&T) -> Option<String>,
|
|
K: Ord,
|
|
{
|
|
let selector = selector.trim();
|
|
if selector.is_empty() {
|
|
return Err(ResolveRunError::InvalidSelector);
|
|
}
|
|
|
|
let id_matches: Vec<_> = runs
|
|
.iter()
|
|
.filter(|run| run_id(run).starts_with(selector))
|
|
.collect();
|
|
match id_matches.len() {
|
|
1 => return Ok(id_matches[0]),
|
|
count if count > 1 => {
|
|
return Err(ResolveRunError::AmbiguousPrefix {
|
|
selector: selector.to_string(),
|
|
matches: id_matches
|
|
.iter()
|
|
.map(|run| {
|
|
let workflow = workflow_name(run)
|
|
.or_else(|| workflow_slug(run))
|
|
.unwrap_or_else(|| "-".to_string());
|
|
let origin = repo_origin_url(run).unwrap_or_else(|| "-".to_string());
|
|
format!(
|
|
"{} created_at={} workflow={} origin={}",
|
|
run_id(run),
|
|
created_at_label(run),
|
|
workflow,
|
|
origin
|
|
)
|
|
})
|
|
.collect(),
|
|
});
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
let selector_lower = selector.to_lowercase();
|
|
let selector_collapsed = collapse_separators(&selector_lower);
|
|
runs.iter()
|
|
.filter(|run| {
|
|
workflow_slug(run).is_some_and(|slug| slug.to_lowercase() == selector_lower)
|
|
|| workflow_name(run).is_some_and(|name| {
|
|
let name_lower = name.to_lowercase();
|
|
name_lower.contains(&selector_lower)
|
|
|| collapse_separators(&name_lower).contains(&selector_collapsed)
|
|
})
|
|
})
|
|
.max_by_key(|run| created_at(run))
|
|
.ok_or_else(|| ResolveRunError::NotFound {
|
|
selector: selector.to_string(),
|
|
})
|
|
}
|
|
|
|
fn collapse_separators(value: &str) -> String {
|
|
value.chars().filter(|c| *c != '-' && *c != '_').collect()
|
|
}
|