use anyhow::Result;
use rigg_core::config::EnvironmentConfig;
use rigg_core::resources::ResourceKind;
use rigg_core::service::ServiceDomain;
use crate::cli::EnvCommands;
use crate::commands::load_config;
pub async fn run(cmd: EnvCommands) -> Result<()> {
match cmd {
EnvCommands::List => list().await,
EnvCommands::Show { name } => show(name).await,
EnvCommands::SetDefault { name } => set_default(&name).await,
EnvCommands::Add { name } => add(&name).await,
EnvCommands::Remove { name } => remove(&name).await,
}
}
async fn list() -> Result<()> {
let (_project_root, config) = load_config()?;
let default_name = config.default_env_name().unwrap_or("");
for name in config.environment_names() {
let env_config = &config.environments[name];
let search_count = env_config.search.len();
let foundry_count = env_config.foundry.len();
let is_default = name == default_name;
let mut parts = Vec::new();
if search_count > 0 {
parts.push(format!("search: {}", search_count));
}
if foundry_count > 0 {
parts.push(format!("foundry: {}", foundry_count));
}
let suffix = if is_default { " (default)" } else { "" };
println!(" {} {}{}", name, parts.join(", "), suffix);
}
Ok(())
}
async fn show(name: Option<String>) -> Result<()> {
let (_project_root, config) = load_config()?;
let env_name = match name {
Some(ref n) => n.as_str(),
None => config.default_env_name().ok_or_else(|| {
anyhow::anyhow!("No default environment set. Specify one with: rigg env show <name>")
})?,
};
let env_config = config.environments.get(env_name).ok_or_else(|| {
anyhow::anyhow!(
"Environment '{}' not found. Available: {}",
env_name,
config.environment_names().join(", ")
)
})?;
let is_default = config.default_env_name() == Some(env_name);
let default_tag = if is_default { " (default)" } else { "" };
println!("Environment: {}{}", env_name, default_tag);
if let Some(ref desc) = env_config.description {
println!("Description: {}", desc);
}
if !env_config.search.is_empty() {
println!();
println!(" Search services:");
for svc in &env_config.search {
let mut detail = String::new();
if let Some(ref label) = svc.label {
detail.push_str(&format!(" [{}]", label));
}
if let Some(ref sub) = svc.subscription {
detail.push_str(&format!(" (subscription: {})", sub));
}
println!(" {}{}", svc.name, detail);
}
}
if !env_config.foundry.is_empty() {
println!();
println!(" Foundry services:");
for svc in &env_config.foundry {
let mut detail = String::new();
if let Some(ref label) = svc.label {
detail.push_str(&format!(" [{}]", label));
}
println!(" {} / {}{}", svc.name, svc.project, detail);
}
}
Ok(())
}
async fn set_default(name: &str) -> Result<()> {
let (project_root, mut config) = load_config()?;
if !config.environments.contains_key(name) {
anyhow::bail!(
"Environment '{}' not found. Available: {}",
name,
config.environment_names().join(", ")
);
}
for env in config.environments.values_mut() {
env.default = false;
}
config.environments.get_mut(name).unwrap().default = true;
config.save(&project_root)?;
println!("Default environment set to '{}'", name);
Ok(())
}
async fn add(name: &str) -> Result<()> {
let (project_root, mut config) = load_config()?;
if config.environments.contains_key(name) {
anyhow::bail!(
"Environment '{}' already exists. Use 'rigg init' to update it.",
name
);
}
println!("Adding environment '{}'", name);
println!();
let ctx = super::init::try_authenticate().await?;
let mut env_config = EnvironmentConfig {
default: false,
description: None,
search: vec![],
foundry: vec![],
};
if crate::commands::confirm::prompt_yes_default("Manage Azure AI Search resources?")? {
let search_services =
super::init::discover_new_search_services(&ctx, &env_config.search).await?;
env_config.search = search_services;
}
if crate::commands::confirm::prompt_yes_default("Manage Microsoft Foundry agents?")? {
let accounts = ctx
.arm
.list_ai_services_accounts(&ctx.subscription_id)
.await?;
let foundry_services =
super::init::discover_new_foundry_services(&ctx, &env_config.foundry, &accounts)
.await?;
env_config.foundry = foundry_services;
}
if env_config.search.is_empty() && env_config.foundry.is_empty() {
anyhow::bail!("No services configured. Environment not added.");
}
config.environments.insert(name.to_string(), env_config);
let has_default = config.environments.values().any(|e| e.default);
if !has_default && config.environments.len() == 1 {
config.environments.get_mut(name).unwrap().default = true;
}
let env = config
.resolve_env(Some(name))
.map_err(|e| anyhow::anyhow!("{}", e))?;
let files_root = config.files_root(&project_root);
for search_svc in &env.search {
let search_base = env.search_service_dir(&files_root, search_svc);
for kind in ResourceKind::search_kinds() {
if kind.domain() == ServiceDomain::Search {
let dir = search_base.join(kind.directory_name());
std::fs::create_dir_all(&dir)?;
}
}
}
for foundry_svc in &env.foundry {
let foundry_base = env.foundry_service_dir(&files_root, foundry_svc);
std::fs::create_dir_all(foundry_base.join("agents"))?;
}
let state_dir = project_root.join(".rigg").join(name);
std::fs::create_dir_all(&state_dir)?;
config.save(&project_root)?;
println!();
println!("Environment '{}' added.", name);
let search_count = env.search.len();
let foundry_count = env.foundry.len();
if search_count > 0 {
println!(" Search services: {}", search_count);
}
if foundry_count > 0 {
println!(" Foundry services: {}", foundry_count);
}
println!();
println!("Pull resources with: rigg pull --all --env {}", name);
Ok(())
}
async fn remove(name: &str) -> Result<()> {
let (project_root, mut config) = load_config()?;
if !config.environments.contains_key(name) {
anyhow::bail!(
"Environment '{}' not found. Available: {}",
name,
config.environment_names().join(", ")
);
}
if config.environments.len() == 1 {
anyhow::bail!("Cannot remove the only environment. At least one environment must exist.");
}
let was_default = config.environments[name].default;
if !crate::commands::confirm::prompt_yes_no(&format!(
"Remove environment '{}'? This will delete its state files.",
name
))? {
println!("Cancelled.");
return Ok(());
}
config.environments.remove(name);
if was_default {
if let Some(first_name) = config.environments.keys().next().cloned() {
config.environments.get_mut(&first_name).unwrap().default = true;
println!("Default environment changed to '{}'", first_name);
}
}
let state_dir = project_root.join(".rigg").join(name);
if state_dir.exists() {
std::fs::remove_dir_all(&state_dir)?;
}
config.save(&project_root)?;
println!("Environment '{}' removed.", name);
Ok(())
}