Skip to content

Commit 069bdd8

Browse files
committed
Add API compatibility and insecure flag support
- Add camelCase serialization for API responses - Add --insecure flag for aliases with self-signed certs - Add language parameter to create worker command
1 parent f0c16d0 commit 069bdd8

8 files changed

Lines changed: 99 additions & 23 deletions

File tree

src/backend/api.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ pub struct ApiBackend {
88
}
99

1010
impl ApiBackend {
11-
pub fn new(base_url: String, token: Option<String>) -> Self {
11+
pub fn new(base_url: String, token: Option<String>, insecure: bool) -> Self {
12+
let client = Client::builder()
13+
.danger_accept_invalid_certs(insecure)
14+
.build()
15+
.expect("Failed to build HTTP client");
16+
1217
Self {
13-
client: Client::new(),
18+
client,
1419
base_url,
1520
token,
1621
}

src/backend/db.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ impl Backend for DbBackend {
8989
.fetch_one(&self.pool)
9090
.await?;
9191

92+
// Note: language is used by API to set initial deployment, DB backend ignores it for now
93+
9294
Ok(Worker {
9395
id: row.get::<uuid::Uuid, _>("id").to_string(),
9496
name: row.get("name"),

src/backend/mock.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ impl Backend for MockBackend {
8282
)));
8383
}
8484

85+
// Note: language is used by API to set initial deployment, mock ignores it
8586
let worker = Worker {
8687
id: uuid::Uuid::new_v4().to_string(),
8788
name: input.name.clone(),

src/backend/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,28 @@ pub enum BackendError {
2727
}
2828

2929
#[derive(Debug, Clone, Serialize, Deserialize)]
30+
#[serde(rename_all = "camelCase")]
3031
pub struct Worker {
3132
pub id: String,
3233
pub name: String,
34+
#[serde(alias = "desc")]
3335
pub description: Option<String>,
3436
pub current_version: Option<i32>,
3537
pub created_at: DateTime<Utc>,
3638
pub updated_at: DateTime<Utc>,
3739
}
3840

3941
#[derive(Debug, Clone, Serialize, Deserialize)]
42+
#[serde(rename_all = "camelCase")]
4043
pub struct CreateWorkerInput {
4144
pub name: String,
45+
#[serde(skip_serializing_if = "Option::is_none")]
4246
pub description: Option<String>,
47+
pub language: String,
4348
}
4449

4550
#[derive(Debug, Clone, Serialize, Deserialize)]
51+
#[serde(rename_all = "camelCase")]
4652
pub struct Deployment {
4753
pub worker_id: String,
4854
pub version: i32,
@@ -53,9 +59,11 @@ pub struct Deployment {
5359
}
5460

5561
#[derive(Debug, Clone, Serialize, Deserialize)]
62+
#[serde(rename_all = "camelCase")]
5663
pub struct DeployInput {
5764
pub code: Vec<u8>,
5865
pub code_type: String,
66+
#[serde(skip_serializing_if = "Option::is_none")]
5967
pub message: Option<String>,
6068
}
6169

src/commands/alias.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ pub enum AliasCommand {
1717
#[arg(long, requires = "api")]
1818
token: Option<String>,
1919

20+
/// Accept invalid TLS certificates (for dev environments)
21+
#[arg(long, requires = "api")]
22+
insecure: bool,
23+
2024
/// Database URL (for DB backend)
2125
#[arg(long, conflicts_with = "api")]
2226
db: Option<String>,
@@ -51,9 +55,10 @@ impl AliasCommand {
5155
name,
5256
api,
5357
token,
58+
insecure,
5459
db,
5560
force,
56-
} => cmd_set(name, api, token, db, force),
61+
} => cmd_set(name, api, token, insecure, db, force),
5762
Self::List => cmd_list(),
5863
Self::Remove { name } => cmd_remove(name),
5964
Self::SetDefault { name } => cmd_set_default(name),
@@ -65,13 +70,14 @@ fn cmd_set(
6570
name: String,
6671
api: Option<String>,
6772
token: Option<String>,
73+
insecure: bool,
6874
db: Option<String>,
6975
force: bool,
7076
) -> Result<(), ConfigError> {
7177
let mut config = Config::load()?;
7278

7379
let alias_config = match (api, db) {
74-
(Some(url), None) => AliasConfig::api(url, token),
80+
(Some(url), None) => AliasConfig::api(url, token, insecure),
7581
(None, Some(database_url)) => AliasConfig::db(database_url),
7682
_ => {
7783
eprintln!(
@@ -126,7 +132,7 @@ fn cmd_list() -> Result<(), ConfigError> {
126132
};
127133

128134
let (type_str, detail) = match alias {
129-
AliasConfig::Api { url, token } => {
135+
AliasConfig::Api { url, token, .. } => {
130136
let auth = if token.is_some() { " (auth)" } else { "" };
131137
("api".cyan(), format!("{}{}", url, auth.dimmed()))
132138
}

src/commands/workers.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ pub enum WorkersCommand {
2323
/// Worker description
2424
#[arg(short, long)]
2525
description: Option<String>,
26+
27+
/// Language (javascript or typescript)
28+
#[arg(short, long, default_value = "typescript")]
29+
language: String,
2630
},
2731

2832
/// Delete a worker
@@ -51,7 +55,11 @@ impl WorkersCommand {
5155
match self {
5256
Self::List => cmd_list(backend).await,
5357
Self::Get { name } => cmd_get(backend, &name).await,
54-
Self::Create { name, description } => cmd_create(backend, name, description).await,
58+
Self::Create {
59+
name,
60+
description,
61+
language,
62+
} => cmd_create(backend, name, description, language).await,
5563
Self::Delete { name } => cmd_delete(backend, &name).await,
5664
Self::Deploy {
5765
name,
@@ -102,8 +110,13 @@ async fn cmd_create<B: Backend>(
102110
backend: &B,
103111
name: String,
104112
description: Option<String>,
113+
language: String,
105114
) -> Result<(), BackendError> {
106-
let input = CreateWorkerInput { name, description };
115+
let input = CreateWorkerInput {
116+
name,
117+
description,
118+
language,
119+
};
107120
let worker = backend.create_worker(input).await?;
108121

109122
println!(
@@ -271,6 +284,7 @@ mod tests {
271284
let result = WorkersCommand::Create {
272285
name: "new-worker".to_string(),
273286
description: Some("A new worker".to_string()),
287+
language: "typescript".to_string(),
274288
}
275289
.run(&backend)
276290
.await;
@@ -290,6 +304,7 @@ mod tests {
290304
let result = WorkersCommand::Create {
291305
name: "simple-worker".to_string(),
292306
description: None,
307+
language: "javascript".to_string(),
293308
}
294309
.run(&backend)
295310
.await;

src/config.rs

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,20 @@ pub enum AliasConfig {
3232
url: String,
3333
#[serde(skip_serializing_if = "Option::is_none")]
3434
token: Option<String>,
35+
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
36+
insecure: bool,
3537
},
3638
Db {
3739
database_url: String,
3840
},
3941
}
4042

4143
impl AliasConfig {
42-
pub fn api(url: impl Into<String>, token: Option<String>) -> Self {
44+
pub fn api(url: impl Into<String>, token: Option<String>, insecure: bool) -> Self {
4345
Self::Api {
4446
url: url.into(),
4547
token,
48+
insecure,
4649
}
4750
}
4851

@@ -71,7 +74,10 @@ pub struct Config {
7174
impl Default for Config {
7275
fn default() -> Self {
7376
let mut aliases = HashMap::new();
74-
aliases.insert("cloud".to_string(), AliasConfig::api(DEFAULT_API_URL, None));
77+
aliases.insert(
78+
"cloud".to_string(),
79+
AliasConfig::api(DEFAULT_API_URL, None, false),
80+
);
7581

7682
Self {
7783
version: 1,
@@ -163,30 +169,51 @@ mod tests {
163169

164170
#[test]
165171
fn test_alias_config_api() {
166-
let alias = AliasConfig::api("https://example.com/api", Some("token123".to_string()));
172+
let alias = AliasConfig::api(
173+
"https://example.com/api",
174+
Some("token123".to_string()),
175+
false,
176+
);
167177

168178
assert_eq!(alias.type_name(), "api");
169179

170-
if let AliasConfig::Api { url, token } = alias {
180+
if let AliasConfig::Api {
181+
url,
182+
token,
183+
insecure,
184+
} = alias
185+
{
171186
assert_eq!(url, "https://example.com/api");
172187
assert_eq!(token, Some("token123".to_string()));
188+
assert!(!insecure);
173189
} else {
174190
panic!("Expected Api variant");
175191
}
176192
}
177193

178194
#[test]
179195
fn test_alias_config_api_no_token() {
180-
let alias = AliasConfig::api("https://example.com/api", None);
196+
let alias = AliasConfig::api("https://example.com/api", None, false);
181197

182-
if let AliasConfig::Api { url, token } = alias {
198+
if let AliasConfig::Api { url, token, .. } = alias {
183199
assert_eq!(url, "https://example.com/api");
184200
assert!(token.is_none());
185201
} else {
186202
panic!("Expected Api variant");
187203
}
188204
}
189205

206+
#[test]
207+
fn test_alias_config_api_insecure() {
208+
let alias = AliasConfig::api("https://dev.localhost/api", None, true);
209+
210+
if let AliasConfig::Api { insecure, .. } = alias {
211+
assert!(insecure);
212+
} else {
213+
panic!("Expected Api variant");
214+
}
215+
}
216+
190217
#[test]
191218
fn test_alias_config_db() {
192219
let alias = AliasConfig::db("postgres://user:pass@localhost/db");
@@ -211,7 +238,7 @@ mod tests {
211238
let cloud = config.aliases.get("cloud").unwrap();
212239
assert_eq!(cloud.type_name(), "api");
213240

214-
if let AliasConfig::Api { url, token } = cloud {
241+
if let AliasConfig::Api { url, token, .. } = cloud {
215242
assert_eq!(url, DEFAULT_API_URL);
216243
assert!(token.is_none());
217244
}
@@ -231,7 +258,7 @@ mod tests {
231258

232259
let result = config.set_alias(
233260
"prod",
234-
AliasConfig::api("https://prod.example.com", None),
261+
AliasConfig::api("https://prod.example.com", None, false),
235262
false,
236263
);
237264

@@ -243,7 +270,11 @@ mod tests {
243270
fn test_set_alias_exists_no_force() {
244271
let mut config = Config::default();
245272

246-
let result = config.set_alias("cloud", AliasConfig::api("https://other.com", None), false);
273+
let result = config.set_alias(
274+
"cloud",
275+
AliasConfig::api("https://other.com", None, false),
276+
false,
277+
);
247278

248279
assert!(matches!(result, Err(ConfigError::AliasExists(_))));
249280
}
@@ -253,7 +284,7 @@ mod tests {
253284
let mut config = Config::default();
254285
let new_url = "https://new.example.com";
255286

256-
let result = config.set_alias("cloud", AliasConfig::api(new_url, None), true);
287+
let result = config.set_alias("cloud", AliasConfig::api(new_url, None, false), true);
257288

258289
assert!(result.is_ok());
259290

@@ -301,7 +332,7 @@ mod tests {
301332
config
302333
.set_alias(
303334
"prod",
304-
AliasConfig::api("https://prod.example.com", None),
335+
AliasConfig::api("https://prod.example.com", None, false),
305336
false,
306337
)
307338
.unwrap();
@@ -323,14 +354,18 @@ mod tests {
323354

324355
#[test]
325356
fn test_json_serialization_api() {
326-
let alias = AliasConfig::api("https://example.com/api", Some("token123".to_string()));
357+
let alias = AliasConfig::api(
358+
"https://example.com/api",
359+
Some("token123".to_string()),
360+
false,
361+
);
327362

328363
let json = serde_json::to_string(&alias).unwrap();
329364
let parsed: AliasConfig = serde_json::from_str(&json).unwrap();
330365

331366
assert_eq!(parsed.type_name(), "api");
332367

333-
if let AliasConfig::Api { url, token } = parsed {
368+
if let AliasConfig::Api { url, token, .. } = parsed {
334369
assert_eq!(url, "https://example.com/api");
335370
assert_eq!(token, Some("token123".to_string()));
336371
}
@@ -368,7 +403,7 @@ mod tests {
368403

369404
#[test]
370405
fn test_json_api_without_token_skips_field() {
371-
let alias = AliasConfig::api("https://example.com", None);
406+
let alias = AliasConfig::api("https://example.com", None, false);
372407

373408
let json = serde_json::to_string(&alias).unwrap();
374409

src/main.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,12 @@ async fn run_workers_command(alias: Option<String>, command: WorkersCommand) ->
112112
command.run(&backend).await.map_err(format_backend_error)
113113
}
114114

115-
AliasConfig::Api { url, token } => {
116-
let backend = ApiBackend::new(url, token);
115+
AliasConfig::Api {
116+
url,
117+
token,
118+
insecure,
119+
} => {
120+
let backend = ApiBackend::new(url, token, insecure);
117121
command.run(&backend).await.map_err(format_backend_error)
118122
}
119123
}

0 commit comments

Comments
 (0)