use crate::strategies::{get_all_services, ServiceConfig, XbpConfig};
pub fn resolve_deploy_env(config: &XbpConfig, explicit: Option<&str>) -> String {
if let Some(env) = explicit.map(str::trim).filter(|s| !s.is_empty()) {
return env.to_string();
}
config
.deploy
.as_ref()
.and_then(|d| d.default_env.as_deref())
.map(str::trim)
.filter(|s| !s.is_empty())
.unwrap_or("production")
.to_string()
}
pub fn resolve_deploy_targets(
config: &XbpConfig,
target: &str,
env: &str,
) -> Result<Vec<ServiceConfig>, String> {
let target = target.trim();
if target.is_empty() {
return Err("deploy target is required (service name, group, or `all`)".to_string());
}
let all = get_all_services(config);
if target.eq_ignore_ascii_case("all") {
let selected: Vec<ServiceConfig> = all
.into_iter()
.filter(|s| service_has_env(s, env))
.collect();
if selected.is_empty() {
return Err(format!(
"no services declare `deploy.envs.{env}`; add per-service deploy config first"
));
}
return Ok(selected);
}
if let Some(group) = config
.deploy
.as_ref()
.and_then(|d| d.groups.get(target))
{
let order = if group.order.is_empty() {
group.services.clone()
} else {
group.order.clone()
};
let mut out = Vec::new();
for name in order {
let Some(service) = all.iter().find(|s| s.name == name).cloned() else {
return Err(format!(
"deploy group `{target}` references unknown service `{name}`"
));
};
if !service_has_env(&service, env) {
return Err(format!(
"service `{name}` in group `{target}` has no `deploy.envs.{env}`"
));
}
out.push(service);
}
if out.is_empty() {
return Err(format!("deploy group `{target}` has no services"));
}
return Ok(out);
}
if let Some(service) = all.iter().find(|s| s.name == target).cloned() {
if !service_has_env(&service, env) {
return Err(format!(
"service `{target}` has no `deploy.envs.{env}` (and is not a deploy.groups name)"
));
}
return Ok(vec![service]);
}
let available_services: Vec<&str> = all
.iter()
.filter(|s| service_has_env(s, env))
.map(|s| s.name.as_str())
.collect();
let available_groups: Vec<String> = config
.deploy
.as_ref()
.map(|d| d.groups.keys().cloned().collect())
.unwrap_or_default();
Err(format!(
"unknown deploy target `{target}`. \
Try a service name, `all`, or a group. \
Services with env `{env}`: [{}]. Groups: [{}].",
available_services.join(", "),
available_groups.join(", ")
))
}
fn service_has_env(service: &ServiceConfig, env: &str) -> bool {
service
.deploy
.as_ref()
.map(|d| d.envs.contains_key(env))
.unwrap_or(false)
}