use crate::platform::api::PlatformApiClient;
use crate::platform::api::types::{
CloudProvider, CreateRegistryRequest, RegistrySummary, RegistryTaskState,
};
use crate::wizard::render::{display_step_header, wizard_render_config};
use colored::Colorize;
use inquire::{InquireError, Text};
use std::io::Write;
use std::time::Duration;
use tokio::time::sleep;
#[derive(Debug)]
pub enum RegistryProvisioningResult {
Success(RegistrySummary),
Cancelled,
Error(String),
}
pub async fn provision_registry(
client: &PlatformApiClient,
project_id: &str,
cluster_id: &str,
cluster_name: &str,
provider: CloudProvider,
region: &str,
gcp_project_id: Option<&str>,
) -> RegistryProvisioningResult {
display_step_header(
4,
"Provision Registry",
"Create a new container registry for storing images.",
);
let registry_name = match Text::new("Registry name:")
.with_default("main")
.with_help_message("Lowercase alphanumeric with hyphens (e.g., main, staging)")
.with_render_config(wizard_render_config())
.prompt()
{
Ok(name) => sanitize_registry_name(&name),
Err(InquireError::OperationCanceled) | Err(InquireError::OperationInterrupted) => {
return RegistryProvisioningResult::Cancelled;
}
Err(_) => return RegistryProvisioningResult::Cancelled,
};
println!(
"\n{} Provisioning registry: {}",
"⏳".yellow(),
registry_name.cyan()
);
let request = CreateRegistryRequest {
project_id: project_id.to_string(),
cluster_id: cluster_id.to_string(),
cluster_name: cluster_name.to_string(),
registry_name: registry_name.clone(),
cloud_provider: provider.as_str().to_string(),
region: region.to_string(),
gcp_project_id: gcp_project_id.map(|s| s.to_string()),
};
let response = match client.create_registry(project_id, &request).await {
Ok(r) => r,
Err(e) => {
return RegistryProvisioningResult::Error(format!(
"Failed to start registry provisioning: {}",
e
));
}
};
let task_id = response.task_id;
println!(" Task started: {}", task_id.dimmed());
let mut last_progress = 0;
loop {
sleep(Duration::from_secs(3)).await;
let status = match client.get_registry_task_status(&task_id).await {
Ok(s) => s,
Err(e) => {
return RegistryProvisioningResult::Error(format!(
"Failed to get task status: {}",
e
));
}
};
let progress = status.progress.unwrap_or(0);
if progress > last_progress {
let bar = progress_bar(progress);
let message = status.overall_message.as_deref().unwrap_or("Processing...");
print!(
"\r {} {} {}",
bar,
format!("{}%", progress).cyan(),
message.dimmed()
);
std::io::stdout().flush().ok();
last_progress = progress;
}
match status.status {
RegistryTaskState::Completed => {
println!("\n{} Registry provisioned successfully!", "✓".green());
let registry = RegistrySummary {
id: task_id.clone(), name: status.output.registry_name.unwrap_or(registry_name),
region: region.to_string(),
is_ready: true,
};
if let Some(url) = status.output.registry_url {
println!(" URL: {}", url.cyan());
}
return RegistryProvisioningResult::Success(registry);
}
RegistryTaskState::Failed => {
println!();
let error_msg = status
.error
.map(|e| e.message)
.unwrap_or_else(|| "Unknown error".to_string());
return RegistryProvisioningResult::Error(error_msg);
}
RegistryTaskState::Cancelled => {
println!();
return RegistryProvisioningResult::Cancelled;
}
RegistryTaskState::Processing | RegistryTaskState::Unknown => {
}
}
}
}
fn progress_bar(percent: u8) -> String {
let filled = (percent as usize * 20) / 100;
let empty = 20 - filled;
format!("[{}{}]", "█".repeat(filled), "░".repeat(empty))
}
fn sanitize_registry_name(name: &str) -> String {
name.to_lowercase()
.chars()
.map(|c| {
if c.is_alphanumeric() || c == '-' {
c
} else {
'-'
}
})
.collect::<String>()
.trim_matches('-')
.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sanitize_registry_name() {
assert_eq!(sanitize_registry_name("My Registry"), "my-registry");
assert_eq!(sanitize_registry_name("test_name"), "test-name");
assert_eq!(sanitize_registry_name("--test--"), "test");
assert_eq!(sanitize_registry_name("MAIN"), "main");
assert_eq!(sanitize_registry_name("prod-123"), "prod-123");
}
#[test]
fn test_progress_bar() {
assert_eq!(progress_bar(0), "[░░░░░░░░░░░░░░░░░░░░]");
assert_eq!(progress_bar(50), "[██████████░░░░░░░░░░]");
assert_eq!(progress_bar(100), "[████████████████████]");
}
}