syncable_cli/handlers/
deploy.rs1use crate::agent::tools::ExecutionContext;
7use crate::agent::tools::platform::{DeployServiceArgs, DeployServiceTool, SecretKeyInput};
8use rig::tool::Tool;
9use std::path::PathBuf;
10
11pub async fn handle_deploy_preview(
13 project_path: PathBuf,
14 service_path: PathBuf,
15 service_name: Option<String>,
16 provider: Option<String>,
17 region: Option<String>,
18 machine_type: Option<String>,
19 port: Option<u16>,
20 is_public: bool,
21) -> crate::Result<String> {
22 let rel_path = if service_path == PathBuf::from(".") {
23 None
24 } else {
25 Some(service_path.display().to_string())
26 };
27
28 let args = DeployServiceArgs {
29 path: rel_path,
30 service_name,
31 provider,
32 machine_type,
33 region,
34 port,
35 is_public,
36 cpu: None,
37 memory: None,
38 min_instances: None,
39 max_instances: None,
40 preview_only: true,
41 secret_keys: None,
42 };
43
44 let tool = DeployServiceTool::with_context(project_path, ExecutionContext::HeadlessServer);
45 let result = tool.call(args).await.map_err(|e| {
46 crate::error::IaCGeneratorError::Analysis(crate::error::AnalysisError::InvalidStructure(
47 format!("Deploy preview failed: {}", e),
48 ))
49 })?;
50
51 Ok(result)
52}
53
54pub async fn handle_deploy_run(
56 project_path: PathBuf,
57 service_path: PathBuf,
58 service_name: Option<String>,
59 provider: Option<String>,
60 region: Option<String>,
61 machine_type: Option<String>,
62 port: Option<u16>,
63 is_public: bool,
64 cpu: Option<String>,
65 memory: Option<String>,
66 min_instances: Option<i32>,
67 max_instances: Option<i32>,
68 env_vars: Vec<String>,
69 secrets: Vec<String>,
70 env_file: Option<PathBuf>,
71) -> crate::Result<String> {
72 let rel_path = if service_path == PathBuf::from(".") {
73 None
74 } else {
75 Some(service_path.display().to_string())
76 };
77
78 let mut secret_keys: Vec<SecretKeyInput> = Vec::new();
80
81 for env_str in &env_vars {
83 if let Some((key, value)) = env_str.split_once('=') {
84 secret_keys.push(SecretKeyInput {
85 key: key.to_string(),
86 value: Some(value.to_string()),
87 is_secret: false,
88 });
89 } else {
90 eprintln!(
91 "Warning: ignoring malformed --env '{}' (expected KEY=VALUE)",
92 env_str
93 );
94 }
95 }
96
97 for key in &secrets {
99 secret_keys.push(SecretKeyInput {
100 key: key.to_string(),
101 value: None,
102 is_secret: true,
103 });
104 }
105
106 if let Some(ref env_file_path) = env_file {
108 if env_file_path.exists() {
109 if let Ok(content) = std::fs::read_to_string(env_file_path) {
110 for line in content.lines() {
111 let line = line.trim();
112 if line.is_empty() || line.starts_with('#') {
113 continue;
114 }
115 if let Some((key, value)) = line.split_once('=') {
116 let key = key.trim().to_string();
117 let value = value
118 .trim()
119 .trim_matches('"')
120 .trim_matches('\'')
121 .to_string();
122 let looks_secret = key.contains("SECRET")
124 || key.contains("KEY")
125 || key.contains("TOKEN")
126 || key.contains("PASSWORD")
127 || key.contains("PRIVATE");
128 if looks_secret {
129 secret_keys.push(SecretKeyInput {
131 key,
132 value: None,
133 is_secret: true,
134 });
135 } else {
136 secret_keys.push(SecretKeyInput {
137 key,
138 value: Some(value),
139 is_secret: false,
140 });
141 }
142 }
143 }
144 } else {
145 eprintln!(
146 "Warning: could not read env file: {}",
147 env_file_path.display()
148 );
149 }
150 } else {
151 eprintln!("Warning: env file not found: {}", env_file_path.display());
152 }
153 }
154
155 let args = DeployServiceArgs {
156 path: rel_path,
157 service_name,
158 provider,
159 machine_type,
160 region,
161 port,
162 is_public,
163 cpu,
164 memory,
165 min_instances,
166 max_instances,
167 preview_only: false,
168 secret_keys: if secret_keys.is_empty() {
169 None
170 } else {
171 Some(secret_keys)
172 },
173 };
174
175 let tool = DeployServiceTool::with_context(project_path, ExecutionContext::InteractiveCli);
177 let result = tool.call(args).await.map_err(|e| {
178 crate::error::IaCGeneratorError::Analysis(crate::error::AnalysisError::InvalidStructure(
179 format!("Deploy failed: {}", e),
180 ))
181 })?;
182
183 Ok(result)
184}