use std::fmt::Display; use async_trait::async_trait; use eyre::Context; use crate::{cli, cuddle_file::CuddleFile, MainAction}; pub struct CuddleReleaser { client: dagger_sdk::Query, env: Option, cuddle_file: CuddleFile, folder: String, } pub struct CuddleReleaserOptions { upstream: String, cluster: String, namespace: String, app: String, } pub enum CuddleEnv { Prod, Dev, } impl Display for CuddleEnv { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { CuddleEnv::Prod => f.write_str("prod"), CuddleEnv::Dev => f.write_str("dev"), } } } impl TryInto for String { type Error = eyre::Error; fn try_into(self) -> Result { let env = match self.as_str() { "prod" => CuddleEnv::Prod, "dev" => CuddleEnv::Dev, _ => eyre::bail!("was not a valid env: {}", self), }; Ok(env) } } impl CuddleReleaser { pub async fn new(client: dagger_sdk::Query) -> eyre::Result { let cuddle_file = CuddleFile::from_cuddle_file().await?; let env = std::env::var("CUDDLE_ENV").ok(); Ok(Self { client, cuddle_file, env, folder: ".cuddle/tmp".into(), }) } pub async fn releaser(&self, env: CuddleEnv) -> eyre::Result<()> { let client = self.client.clone(); if self.cuddle_file.deployment.is_none() { return Ok(()); } let chosen_cluster = match self .cuddle_file .deployment .as_ref() .unwrap() .env .0 .get(&self.env.as_ref().unwrap_or(&env.to_string()).to_string()) { Some(c) => match c.clusters.first().take() { Some(c) => c, None => return Ok(()), }, None => return Ok(()), }; if let Some(clusters) = &self.cuddle_file.vars.clusters { let cluster = match clusters.0.get(chosen_cluster) { Some(c) => c, None => eyre::bail!("no cluster found for: {}", chosen_cluster), }; let options = CuddleReleaserOptions { cluster: chosen_cluster.clone(), namespace: cluster.namespace.clone(), app: self.cuddle_file.vars.service.clone(), upstream: self .cuddle_file .deployment .as_ref() .unwrap() .registry .clone(), }; let cuddle_releaser_image = "docker.io/kasperhermansen/cuddle-releaser:main-1706726858"; let folder = client.host().directory(&self.folder); let ssh_sock = std::env::var("SSH_AUTH_SOCK").context("SSH_AUTH_SOCK not set")?; let cuddle_releaser = client .container() .from(cuddle_releaser_image) .with_env_variable("RUST_LOG", "trace") .with_directory("/mnt/templates", folder) .with_unix_socket( ssh_sock.clone(), client.host().unix_socket(ssh_sock.clone()), ); let time = chrono::Local::now(); cuddle_releaser .with_exec(vec!["echo", &time.to_rfc3339()]) .with_exec(vec![ "cuddle-releaser", "release", &format!("--upstream={}", options.upstream), &format!("--folder={}", "/mnt/templates/k8s"), &format!("--cluster={}", options.cluster), &format!("--namespace={}", options.namespace), &format!("--app={}", options.app), ]) .sync() .await?; } Ok(()) } } #[async_trait] impl MainAction for CuddleReleaser { async fn execute_main(&self, _ctx: &mut cli::Context) -> eyre::Result<()> { self.releaser(CuddleEnv::Prod).await?; Ok(()) } }