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 }),
196 }),
197 };
198 assert!(matches!(cmd.command, JiraSubcommands::Transition(_)));
199 }
200
201 #[test]
202 fn jira_subcommands_comment_variant() {
203 let cmd = JiraCommand {
204 command: JiraSubcommands::Comment(comment::CommentCommand {
205 command: comment::CommentSubcommands::List(comment::ListCommand {
206 key: "PROJ-1".to_string(),
207 output: OutputFormat::Table,
208 limit: 0,
209 }),
210 }),
211 };
212 assert!(matches!(cmd.command, JiraSubcommands::Comment(_)));
213 }
214
215 #[test]
216 fn jira_subcommands_delete_variant() {
217 let cmd = JiraCommand {
218 command: JiraSubcommands::Delete(delete::DeleteCommand {
219 key: "PROJ-1".to_string(),
220 force: true,
221 dry_run: false,
222 }),
223 };
224 assert!(matches!(cmd.command, JiraSubcommands::Delete(_)));
225 }
226
227 #[test]
228 fn jira_subcommands_dev_variant() {
229 let cmd = JiraCommand {
230 command: JiraSubcommands::Dev(dev::DevCommand {
231 key: "PROJ-1".to_string(),
232 r#type: None,
233 app: None,
234 summary: false,
235 output: OutputFormat::Table,
236 }),
237 };
238 assert!(matches!(cmd.command, JiraSubcommands::Dev(_)));
239 }
240
241 #[test]
242 fn jira_subcommands_project_variant() {
243 let cmd = JiraCommand {
244 command: JiraSubcommands::Project(project::ProjectCommand {
245 command: project::ProjectSubcommands::List(project::ListCommand {
246 limit: 50,
247 output: OutputFormat::Table,
248 }),
249 }),
250 };
251 assert!(matches!(cmd.command, JiraSubcommands::Project(_)));
252 }
253
254 #[test]
255 fn jira_subcommands_field_variant() {
256 let cmd = JiraCommand {
257 command: JiraSubcommands::Field(field::FieldCommand {
258 command: field::FieldSubcommands::List(field::ListCommand {
259 search: None,
260 output: OutputFormat::Table,
261 }),
262 }),
263 };
264 assert!(matches!(cmd.command, JiraSubcommands::Field(_)));
265 }
266
267 #[test]
268 fn jira_subcommands_board_variant() {
269 let cmd = JiraCommand {
270 command: JiraSubcommands::Board(board::BoardCommand {
271 command: board::BoardSubcommands::List(board::ListCommand {
272 project: None,
273 r#type: None,
274 limit: 50,
275 output: OutputFormat::Table,
276 }),
277 }),
278 };
279 assert!(matches!(cmd.command, JiraSubcommands::Board(_)));
280 }
281
282 #[test]
283 fn jira_subcommands_sprint_variant() {
284 let cmd = JiraCommand {
285 command: JiraSubcommands::Sprint(sprint::SprintCommand {
286 command: sprint::SprintSubcommands::List(sprint::ListCommand {
287 board_id: 1,
288 state: None,
289 limit: 50,
290 output: OutputFormat::Table,
291 }),
292 }),
293 };
294 assert!(matches!(cmd.command, JiraSubcommands::Sprint(_)));
295 }
296
297 #[test]
298 fn jira_subcommands_link_variant() {
299 let cmd = JiraCommand {
300 command: JiraSubcommands::Link(link::LinkCommand {
301 command: link::LinkSubcommands::Types(link::TypesCommand {
302 output: OutputFormat::Table,
303 }),
304 }),
305 };
306 assert!(matches!(cmd.command, JiraSubcommands::Link(_)));
307 }
308
309 #[test]
310 fn jira_subcommands_changelog_variant() {
311 let cmd = JiraCommand {
312 command: JiraSubcommands::Changelog(changelog::ChangelogCommand {
313 keys: "PROJ-1".to_string(),
314 limit: 50,
315 output: OutputFormat::Table,
316 }),
317 };
318 assert!(matches!(cmd.command, JiraSubcommands::Changelog(_)));
319 }
320
321 #[test]
322 fn jira_subcommands_attachment_variant() {
323 let cmd = JiraCommand {
324 command: JiraSubcommands::Attachment(attachment::AttachmentCommand {
325 command: attachment::AttachmentSubcommands::Download(attachment::DownloadCommand {
326 key: "PROJ-1".to_string(),
327 output_dir: ".".to_string(),
328 filter: None,
329 }),
330 }),
331 };
332 assert!(matches!(cmd.command, JiraSubcommands::Attachment(_)));
333 }
334
335 #[test]
336 fn jira_subcommands_watcher_variant() {
337 let cmd = JiraCommand {
338 command: JiraSubcommands::Watcher(watcher::WatcherCommand {
339 command: watcher::WatcherSubcommands::List(watcher::ListCommand {
340 key: "PROJ-1".to_string(),
341 output: OutputFormat::Table,
342 }),
343 }),
344 };
345 assert!(matches!(cmd.command, JiraSubcommands::Watcher(_)));
346 }
347
348 #[test]
349 fn jira_subcommands_worklog_variant() {
350 let cmd = JiraCommand {
351 command: JiraSubcommands::Worklog(worklog::WorklogCommand {
352 command: worklog::WorklogSubcommands::List(worklog::ListCommand {
353 key: "PROJ-1".to_string(),
354 limit: 50,
355 output: OutputFormat::Table,
356 }),
357 }),
358 };
359 assert!(matches!(cmd.command, JiraSubcommands::Worklog(_)));
360 }
361
362 #[test]
363 fn jira_subcommands_user_variant() {
364 let cmd = JiraCommand {
365 command: JiraSubcommands::User(user::UserCommand {
366 command: user::UserSubcommands::Search(user::UserSearchCommand {
367 query: "alice".to_string(),
368 limit: 25,
369 output: OutputFormat::Table,
370 }),
371 }),
372 };
373 assert!(matches!(cmd.command, JiraSubcommands::User(_)));
374 }
375
376 #[test]
377 fn jira_subcommands_version_variant() {
378 let cmd = JiraCommand {
379 command: JiraSubcommands::Version(version::VersionCommand {
380 command: version::VersionSubcommands::List(version::ListCommand {
381 project: "PROJ".to_string(),
382 released: false,
383 unreleased: false,
384 archived: false,
385 unarchived: false,
386 output: OutputFormat::Table,
387 }),
388 }),
389 };
390 assert!(matches!(cmd.command, JiraSubcommands::Version(_)));
391 }
392
393 #[tokio::test]
397 async fn jira_command_execute_version_arm() {
398 use crate::atlassian::auth::test_util::EnvGuard;
399
400 let server = wiremock::MockServer::start().await;
401 wiremock::Mock::given(wiremock::matchers::method("GET"))
402 .and(wiremock::matchers::path(
403 "/rest/api/3/project/PROJ/versions",
404 ))
405 .respond_with(
406 wiremock::ResponseTemplate::new(200).set_body_json(serde_json::json!([
407 {"id": "1", "name": "1.0", "released": false, "archived": false}
408 ])),
409 )
410 .mount(&server)
411 .await;
412
413 let guard = EnvGuard::take();
414 let _home = guard.set_credentials(&server.uri());
415
416 let cmd = JiraCommand {
417 command: JiraSubcommands::Version(version::VersionCommand {
418 command: version::VersionSubcommands::List(version::ListCommand {
419 project: "PROJ".to_string(),
420 released: false,
421 unreleased: false,
422 archived: false,
423 unarchived: false,
424 output: OutputFormat::Yaml,
425 }),
426 }),
427 };
428 assert!(cmd.execute().await.is_ok());
429 }
430}