stormchaser_cli/commands/
cron.rs1use crate::utils::{handle_response, parse_key_val_list, require_token};
2use anyhow::Result;
3use clap::Subcommand;
4use serde_json::json;
5
6#[derive(Subcommand)]
7pub enum CronCommands {
8 List,
10 Create {
12 name: String,
13 #[arg(long)]
14 cron: String,
15 #[arg(long)]
16 workflow: String,
17 #[arg(long)]
18 repo: String,
19 #[arg(long)]
20 path: String,
21 #[arg(long, default_value = "main")]
22 git_ref: String,
23 #[arg(long)]
24 description: Option<String>,
25 #[arg(short, long)]
27 input: Vec<String>,
28 },
29 Delete {
31 id: stormchaser_model::CronWorkflowId,
32 },
33}
34
35pub async fn handle(
36 url: &str,
37 token: Option<&str>,
38 http_client: &reqwest_middleware::ClientWithMiddleware,
39 command: CronCommands,
40) -> Result<()> {
41 match command {
42 CronCommands::List => {
43 let token = require_token(token)?;
44 let res = http_client
45 .get(format!("{}/api/v1/cron-workflows", url))
46 .header(reqwest::header::AUTHORIZATION, format!("Bearer {}", token))
47 .send()
48 .await?;
49 handle_response(res).await?;
50 }
51 CronCommands::Create {
52 name,
53 cron,
54 workflow,
55 repo,
56 path,
57 git_ref,
58 description,
59 input,
60 } => {
61 let inputs = parse_key_val_list(input);
62 let token = require_token(token)?;
63 let res = http_client
64 .post(format!("{}/api/v1/cron-workflows", url))
65 .header(reqwest::header::AUTHORIZATION, format!("Bearer {}", token))
66 .json(&json!({
67 "name": name,
68 "cronspec": cron,
69 "workflow_name": workflow,
70 "repo_url": repo,
71 "workflow_path": path,
72 "git_ref": git_ref,
73 "inputs": inputs,
74 "description": description,
75 }))
76 .send()
77 .await?;
78 handle_response(res).await?;
79 }
80 CronCommands::Delete { id } => {
81 let token = require_token(token)?;
82 let res = http_client
83 .delete(format!("{}/api/v1/cron-workflows/{}", url, id))
84 .header(reqwest::header::AUTHORIZATION, format!("Bearer {}", token))
85 .send()
86 .await?;
87 handle_response(res).await?;
88 }
89 }
90 Ok(())
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use reqwest_middleware::ClientBuilder;
97 use wiremock::matchers::{header, method, path};
98 use wiremock::{Mock, MockServer, ResponseTemplate};
99
100 #[tokio::test]
101 async fn test_cron_list() {
102 let server = MockServer::start().await;
103 Mock::given(method("GET"))
104 .and(path("/api/v1/cron-workflows"))
105 .and(header(reqwest::header::AUTHORIZATION, "Bearer test-token"))
106 .respond_with(ResponseTemplate::new(200).set_body_json(json!([])))
107 .mount(&server)
108 .await;
109
110 let client = ClientBuilder::new(reqwest::Client::new()).build();
111 let cmd = CronCommands::List;
112
113 let result = handle(&server.uri(), Some("test-token"), &client, cmd).await;
114 assert!(result.is_ok());
115 }
116
117 #[tokio::test]
118 async fn test_cron_create() {
119 let server = MockServer::start().await;
120 Mock::given(method("POST"))
121 .and(path("/api/v1/cron-workflows"))
122 .and(header(reqwest::header::AUTHORIZATION, "Bearer test-token"))
123 .respond_with(ResponseTemplate::new(200).set_body_json(json!({"status": "created"})))
124 .mount(&server)
125 .await;
126
127 let client = ClientBuilder::new(reqwest::Client::new()).build();
128 let cmd = CronCommands::Create {
129 name: "test-cron".to_string(),
130 cron: "* * * * *".to_string(),
131 workflow: "my-wf".to_string(),
132 repo: "https://github.com/a/b".to_string(),
133 path: "wf.storm".to_string(),
134 git_ref: "main".to_string(),
135 description: Some("desc".to_string()),
136 input: vec!["key=value".to_string()],
137 };
138
139 let result = handle(&server.uri(), Some("test-token"), &client, cmd).await;
140 assert!(result.is_ok());
141 }
142
143 #[tokio::test]
144 async fn test_cron_delete() {
145 let server = MockServer::start().await;
146 let id = stormchaser_model::CronWorkflowId::new_v4();
147 Mock::given(method("DELETE"))
148 .and(path(format!("/api/v1/cron-workflows/{}", id)))
149 .and(header(reqwest::header::AUTHORIZATION, "Bearer test-token"))
150 .respond_with(ResponseTemplate::new(200).set_body_json(json!({"status": "deleted"})))
151 .mount(&server)
152 .await;
153
154 let client = ClientBuilder::new(reqwest::Client::new()).build();
155 let cmd = CronCommands::Delete { id };
156
157 let result = handle(&server.uri(), Some("test-token"), &client, cmd).await;
158 assert!(result.is_ok());
159 }
160}