1pub(crate) mod attachment;
4pub(crate) mod board;
5pub(crate) mod changelog;
6pub(crate) mod comment;
7pub(crate) mod create;
8pub(crate) mod delete;
9pub(crate) mod dev;
10pub(crate) mod edit;
11pub(crate) mod field;
12pub(crate) mod link;
13pub(crate) mod project;
14pub(crate) mod read;
15pub(crate) mod search;
16pub(crate) mod sprint;
17pub(crate) mod transition;
18pub(crate) mod user;
19pub(crate) mod version;
20pub(crate) mod watcher;
21pub(crate) mod worklog;
22pub(crate) mod write;
23
24use anyhow::Result;
25use clap::{Parser, Subcommand};
26
27#[derive(Parser)]
29pub struct JiraCommand {
30 #[command(subcommand)]
32 pub command: JiraSubcommands,
33}
34
35#[derive(Subcommand)]
37pub enum JiraSubcommands {
38 Read(read::ReadCommand),
40 Write(write::WriteCommand),
42 Edit(edit::EditCommand),
44 Search(search::SearchCommand),
46 Create(create::CreateCommand),
48 Transition(transition::TransitionCommand),
50 Comment(comment::CommentCommand),
52 Delete(delete::DeleteCommand),
54 Dev(dev::DevCommand),
56 Project(project::ProjectCommand),
58 Field(field::FieldCommand),
60 Board(board::BoardCommand),
62 Sprint(sprint::SprintCommand),
64 Link(link::LinkCommand),
66 Changelog(changelog::ChangelogCommand),
68 Attachment(attachment::AttachmentCommand),
70 Watcher(watcher::WatcherCommand),
72 Worklog(worklog::WorklogCommand),
74 User(user::UserCommand),
76 Version(version::VersionCommand),
78}
79
80impl JiraCommand {
81 pub async fn execute(self) -> Result<()> {
83 match self.command {
84 JiraSubcommands::Read(cmd) => cmd.execute().await,
85 JiraSubcommands::Write(cmd) => cmd.execute().await,
86 JiraSubcommands::Edit(cmd) => cmd.execute().await,
87 JiraSubcommands::Search(cmd) => cmd.execute().await,
88 JiraSubcommands::Create(cmd) => cmd.execute().await,
89 JiraSubcommands::Transition(cmd) => cmd.execute().await,
90 JiraSubcommands::Comment(cmd) => cmd.execute().await,
91 JiraSubcommands::Delete(cmd) => cmd.execute().await,
92 JiraSubcommands::Dev(cmd) => cmd.execute().await,
93 JiraSubcommands::Project(cmd) => cmd.execute().await,
94 JiraSubcommands::Field(cmd) => cmd.execute().await,
95 JiraSubcommands::Board(cmd) => cmd.execute().await,
96 JiraSubcommands::Sprint(cmd) => cmd.execute().await,
97 JiraSubcommands::Link(cmd) => cmd.execute().await,
98 JiraSubcommands::Changelog(cmd) => cmd.execute().await,
99 JiraSubcommands::Attachment(cmd) => cmd.execute().await,
100 JiraSubcommands::Watcher(cmd) => cmd.execute().await,
101 JiraSubcommands::Worklog(cmd) => cmd.execute().await,
102 JiraSubcommands::User(cmd) => cmd.execute().await,
103 JiraSubcommands::Version(cmd) => cmd.execute().await,
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::cli::atlassian::format::{ContentFormat, OutputFormat};
112
113 #[test]
114 fn jira_subcommands_read_variant() {
115 let cmd = JiraCommand {
116 command: JiraSubcommands::Read(read::ReadCommand {
117 key: "PROJ-1".to_string(),
118 out_file: None,
119 output: None,
120 format: ContentFormat::Jfm,
121 fields: vec![],
122 all_fields: false,
123 }),
124 };
125 assert!(matches!(cmd.command, JiraSubcommands::Read(_)));
126 }
127
128 #[test]
129 fn jira_subcommands_write_variant() {
130 let cmd = JiraCommand {
131 command: JiraSubcommands::Write(write::WriteCommand {
132 key: "PROJ-1".to_string(),
133 file: None,
134 format: ContentFormat::Jfm,
135 no_content: false,
136 assignee: None,
137 reporter: None,
138 set_fields: vec![],
139 force: false,
140 dry_run: false,
141 }),
142 };
143 assert!(matches!(cmd.command, JiraSubcommands::Write(_)));
144 }
145
146 #[test]
147 fn jira_subcommands_edit_variant() {
148 let cmd = JiraCommand {
149 command: JiraSubcommands::Edit(edit::EditCommand {
150 key: "PROJ-1".to_string(),
151 }),
152 };
153 assert!(matches!(cmd.command, JiraSubcommands::Edit(_)));
154 }
155
156 #[test]
157 fn jira_subcommands_create_variant() {
158 let cmd = JiraCommand {
159 command: JiraSubcommands::Create(create::CreateCommand {
160 file: None,
161 format: ContentFormat::Jfm,
162 instance: None,
163 project: Some("PROJ".to_string()),
164 r#type: None,
165 summary: Some("Test".to_string()),
166 set_fields: vec![],
167 dry_run: false,
168 }),
169 };
170 assert!(matches!(cmd.command, JiraSubcommands::Create(_)));
171 }
172
173 #[test]
174 fn jira_subcommands_search_variant() {
175 let cmd = JiraCommand {
176 command: JiraSubcommands::Search(search::SearchCommand {
177 jql: Some("project = PROJ".to_string()),
178 project: None,
179 assignee: None,
180 status: None,
181 limit: 50,
182 output: OutputFormat::Table,
183 }),
184 };
185 assert!(matches!(cmd.command, JiraSubcommands::Search(_)));
186 }
187
188 #[test]
189 fn jira_subcommands_transition_variant() {
190 let cmd = JiraCommand {
191 command: JiraSubcommands::Transition(transition::TransitionCommand {
192 command: transition::TransitionSubcommands::Execute(transition::ExecuteCommand {
193 key: "PROJ-1".to_string(),
194 transition: "Done".to_string(),
195 set_fields: vec![],
196 resolution: None,
197 comment: None,
198 }),
199 }),
200 };
201 assert!(matches!(cmd.command, JiraSubcommands::Transition(_)));
202 }
203
204 #[test]
205 fn jira_subcommands_comment_variant() {
206 let cmd = JiraCommand {
207 command: JiraSubcommands::Comment(comment::CommentCommand {
208 command: comment::CommentSubcommands::List(comment::ListCommand {
209 key: "PROJ-1".to_string(),
210 output: OutputFormat::Table,
211 limit: 0,
212 }),
213 }),
214 };
215 assert!(matches!(cmd.command, JiraSubcommands::Comment(_)));
216 }
217
218 #[test]
219 fn jira_subcommands_delete_variant() {
220 let cmd = JiraCommand {
221 command: JiraSubcommands::Delete(delete::DeleteCommand {
222 key: "PROJ-1".to_string(),
223 force: true,
224 dry_run: false,
225 }),
226 };
227 assert!(matches!(cmd.command, JiraSubcommands::Delete(_)));
228 }
229
230 #[test]
231 fn jira_subcommands_dev_variant() {
232 let cmd = JiraCommand {
233 command: JiraSubcommands::Dev(dev::DevCommand {
234 key: "PROJ-1".to_string(),
235 r#type: None,
236 app: None,
237 summary: false,
238 output: OutputFormat::Table,
239 }),
240 };
241 assert!(matches!(cmd.command, JiraSubcommands::Dev(_)));
242 }
243
244 #[test]
245 fn jira_subcommands_project_variant() {
246 let cmd = JiraCommand {
247 command: JiraSubcommands::Project(project::ProjectCommand {
248 command: project::ProjectSubcommands::List(project::ListCommand {
249 limit: 50,
250 output: OutputFormat::Table,
251 }),
252 }),
253 };
254 assert!(matches!(cmd.command, JiraSubcommands::Project(_)));
255 }
256
257 #[test]
258 fn jira_subcommands_field_variant() {
259 let cmd = JiraCommand {
260 command: JiraSubcommands::Field(field::FieldCommand {
261 command: field::FieldSubcommands::List(field::ListCommand {
262 search: None,
263 output: OutputFormat::Table,
264 }),
265 }),
266 };
267 assert!(matches!(cmd.command, JiraSubcommands::Field(_)));
268 }
269
270 #[test]
271 fn jira_subcommands_board_variant() {
272 let cmd = JiraCommand {
273 command: JiraSubcommands::Board(board::BoardCommand {
274 command: board::BoardSubcommands::List(board::ListCommand {
275 project: None,
276 r#type: None,
277 limit: 50,
278 output: OutputFormat::Table,
279 }),
280 }),
281 };
282 assert!(matches!(cmd.command, JiraSubcommands::Board(_)));
283 }
284
285 #[test]
286 fn jira_subcommands_sprint_variant() {
287 let cmd = JiraCommand {
288 command: JiraSubcommands::Sprint(sprint::SprintCommand {
289 command: sprint::SprintSubcommands::List(sprint::ListCommand {
290 board_id: 1,
291 state: None,
292 limit: 50,
293 output: OutputFormat::Table,
294 }),
295 }),
296 };
297 assert!(matches!(cmd.command, JiraSubcommands::Sprint(_)));
298 }
299
300 #[test]
301 fn jira_subcommands_link_variant() {
302 let cmd = JiraCommand {
303 command: JiraSubcommands::Link(link::LinkCommand {
304 command: link::LinkSubcommands::Types(link::TypesCommand {
305 output: OutputFormat::Table,
306 }),
307 }),
308 };
309 assert!(matches!(cmd.command, JiraSubcommands::Link(_)));
310 }
311
312 #[test]
313 fn jira_subcommands_changelog_variant() {
314 let cmd = JiraCommand {
315 command: JiraSubcommands::Changelog(changelog::ChangelogCommand {
316 keys: "PROJ-1".to_string(),
317 limit: 50,
318 output: OutputFormat::Table,
319 }),
320 };
321 assert!(matches!(cmd.command, JiraSubcommands::Changelog(_)));
322 }
323
324 #[test]
325 fn jira_subcommands_attachment_variant() {
326 let cmd = JiraCommand {
327 command: JiraSubcommands::Attachment(attachment::AttachmentCommand {
328 command: attachment::AttachmentSubcommands::Download(attachment::DownloadCommand {
329 key: "PROJ-1".to_string(),
330 output_dir: ".".to_string(),
331 filter: None,
332 }),
333 }),
334 };
335 assert!(matches!(cmd.command, JiraSubcommands::Attachment(_)));
336 }
337
338 #[test]
339 fn jira_subcommands_watcher_variant() {
340 let cmd = JiraCommand {
341 command: JiraSubcommands::Watcher(watcher::WatcherCommand {
342 command: watcher::WatcherSubcommands::List(watcher::ListCommand {
343 key: "PROJ-1".to_string(),
344 output: OutputFormat::Table,
345 }),
346 }),
347 };
348 assert!(matches!(cmd.command, JiraSubcommands::Watcher(_)));
349 }
350
351 #[test]
352 fn jira_subcommands_worklog_variant() {
353 let cmd = JiraCommand {
354 command: JiraSubcommands::Worklog(worklog::WorklogCommand {
355 command: worklog::WorklogSubcommands::List(worklog::ListCommand {
356 key: "PROJ-1".to_string(),
357 limit: 50,
358 output: OutputFormat::Table,
359 }),
360 }),
361 };
362 assert!(matches!(cmd.command, JiraSubcommands::Worklog(_)));
363 }
364
365 #[test]
366 fn jira_subcommands_user_variant() {
367 let cmd = JiraCommand {
368 command: JiraSubcommands::User(user::UserCommand {
369 command: user::UserSubcommands::Search(user::UserSearchCommand {
370 query: "alice".to_string(),
371 limit: 25,
372 output: OutputFormat::Table,
373 }),
374 }),
375 };
376 assert!(matches!(cmd.command, JiraSubcommands::User(_)));
377 }
378
379 #[test]
380 fn jira_subcommands_version_variant() {
381 let cmd = JiraCommand {
382 command: JiraSubcommands::Version(version::VersionCommand {
383 command: version::VersionSubcommands::List(version::ListCommand {
384 project: "PROJ".to_string(),
385 released: false,
386 unreleased: false,
387 archived: false,
388 unarchived: false,
389 output: OutputFormat::Table,
390 }),
391 }),
392 };
393 assert!(matches!(cmd.command, JiraSubcommands::Version(_)));
394 }
395
396 #[tokio::test]
400 async fn jira_command_execute_version_arm() {
401 use crate::atlassian::auth::test_util::EnvGuard;
402
403 let server = wiremock::MockServer::start().await;
404 wiremock::Mock::given(wiremock::matchers::method("GET"))
405 .and(wiremock::matchers::path(
406 "/rest/api/3/project/PROJ/versions",
407 ))
408 .respond_with(
409 wiremock::ResponseTemplate::new(200).set_body_json(serde_json::json!([
410 {"id": "1", "name": "1.0", "released": false, "archived": false}
411 ])),
412 )
413 .mount(&server)
414 .await;
415
416 let guard = EnvGuard::take();
417 let _home = guard.set_credentials(&server.uri());
418
419 let cmd = JiraCommand {
420 command: JiraSubcommands::Version(version::VersionCommand {
421 command: version::VersionSubcommands::List(version::ListCommand {
422 project: "PROJ".to_string(),
423 released: false,
424 unreleased: false,
425 archived: false,
426 unarchived: false,
427 output: OutputFormat::Yaml,
428 }),
429 }),
430 };
431 assert!(cmd.execute().await.is_ok());
432 }
433}