Skip to main content

omni_dev/cli/atlassian/jira/
mod.rs

1//! JIRA CLI subcommands.
2
3pub(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 watcher;
19pub(crate) mod worklog;
20pub(crate) mod write;
21
22use anyhow::Result;
23use clap::{Parser, Subcommand};
24
25/// JIRA issue management, search, agile boards, and more.
26#[derive(Parser)]
27pub struct JiraCommand {
28    /// The JIRA subcommand to execute.
29    #[command(subcommand)]
30    pub command: JiraSubcommands,
31}
32
33/// JIRA subcommands.
34#[derive(Subcommand)]
35pub enum JiraSubcommands {
36    /// Fetches a JIRA issue and outputs it as JFM markdown or ADF JSON.
37    Read(read::ReadCommand),
38    /// Pushes content to a JIRA issue.
39    Write(write::WriteCommand),
40    /// Interactive fetch-edit-push cycle for a JIRA issue.
41    Edit(edit::EditCommand),
42    /// Searches JIRA issues using JQL.
43    Search(search::SearchCommand),
44    /// Creates a new JIRA issue.
45    Create(create::CreateCommand),
46    /// Lists or executes workflow transitions on a JIRA issue.
47    Transition(transition::TransitionCommand),
48    /// Manages comments on a JIRA issue.
49    Comment(comment::CommentCommand),
50    /// Deletes a JIRA issue.
51    Delete(delete::DeleteCommand),
52    /// Shows development status (linked PRs, branches, repositories) for a JIRA issue.
53    Dev(dev::DevCommand),
54    /// Lists JIRA projects.
55    Project(project::ProjectCommand),
56    /// Manages JIRA field definitions and options.
57    Field(field::FieldCommand),
58    /// Manages JIRA agile boards.
59    Board(board::BoardCommand),
60    /// Manages JIRA agile sprints.
61    Sprint(sprint::SprintCommand),
62    /// Manages JIRA issue links.
63    Link(link::LinkCommand),
64    /// Shows change history for JIRA issues.
65    Changelog(changelog::ChangelogCommand),
66    /// Downloads JIRA issue attachments.
67    Attachment(attachment::AttachmentCommand),
68    /// Manages watchers on a JIRA issue.
69    Watcher(watcher::WatcherCommand),
70    /// Manages worklogs (time tracking) on a JIRA issue.
71    Worklog(worklog::WorklogCommand),
72}
73
74impl JiraCommand {
75    /// Executes the JIRA command.
76    pub async fn execute(self) -> Result<()> {
77        match self.command {
78            JiraSubcommands::Read(cmd) => cmd.execute().await,
79            JiraSubcommands::Write(cmd) => cmd.execute().await,
80            JiraSubcommands::Edit(cmd) => cmd.execute().await,
81            JiraSubcommands::Search(cmd) => cmd.execute().await,
82            JiraSubcommands::Create(cmd) => cmd.execute().await,
83            JiraSubcommands::Transition(cmd) => cmd.execute().await,
84            JiraSubcommands::Comment(cmd) => cmd.execute().await,
85            JiraSubcommands::Delete(cmd) => cmd.execute().await,
86            JiraSubcommands::Dev(cmd) => cmd.execute().await,
87            JiraSubcommands::Project(cmd) => cmd.execute().await,
88            JiraSubcommands::Field(cmd) => cmd.execute().await,
89            JiraSubcommands::Board(cmd) => cmd.execute().await,
90            JiraSubcommands::Sprint(cmd) => cmd.execute().await,
91            JiraSubcommands::Link(cmd) => cmd.execute().await,
92            JiraSubcommands::Changelog(cmd) => cmd.execute().await,
93            JiraSubcommands::Attachment(cmd) => cmd.execute().await,
94            JiraSubcommands::Watcher(cmd) => cmd.execute().await,
95            JiraSubcommands::Worklog(cmd) => cmd.execute().await,
96        }
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::cli::atlassian::format::{ContentFormat, OutputFormat};
104
105    #[test]
106    fn jira_subcommands_read_variant() {
107        let cmd = JiraCommand {
108            command: JiraSubcommands::Read(read::ReadCommand {
109                key: "PROJ-1".to_string(),
110                output: None,
111                format: ContentFormat::Jfm,
112            }),
113        };
114        assert!(matches!(cmd.command, JiraSubcommands::Read(_)));
115    }
116
117    #[test]
118    fn jira_subcommands_write_variant() {
119        let cmd = JiraCommand {
120            command: JiraSubcommands::Write(write::WriteCommand {
121                key: "PROJ-1".to_string(),
122                file: None,
123                format: ContentFormat::Jfm,
124                force: false,
125                dry_run: false,
126            }),
127        };
128        assert!(matches!(cmd.command, JiraSubcommands::Write(_)));
129    }
130
131    #[test]
132    fn jira_subcommands_edit_variant() {
133        let cmd = JiraCommand {
134            command: JiraSubcommands::Edit(edit::EditCommand {
135                key: "PROJ-1".to_string(),
136            }),
137        };
138        assert!(matches!(cmd.command, JiraSubcommands::Edit(_)));
139    }
140
141    #[test]
142    fn jira_subcommands_create_variant() {
143        let cmd = JiraCommand {
144            command: JiraSubcommands::Create(create::CreateCommand {
145                file: None,
146                format: ContentFormat::Jfm,
147                project: Some("PROJ".to_string()),
148                r#type: None,
149                summary: Some("Test".to_string()),
150                dry_run: false,
151            }),
152        };
153        assert!(matches!(cmd.command, JiraSubcommands::Create(_)));
154    }
155
156    #[test]
157    fn jira_subcommands_search_variant() {
158        let cmd = JiraCommand {
159            command: JiraSubcommands::Search(search::SearchCommand {
160                jql: Some("project = PROJ".to_string()),
161                project: None,
162                assignee: None,
163                status: None,
164                limit: 50,
165                output: OutputFormat::Table,
166            }),
167        };
168        assert!(matches!(cmd.command, JiraSubcommands::Search(_)));
169    }
170
171    #[test]
172    fn jira_subcommands_transition_variant() {
173        let cmd = JiraCommand {
174            command: JiraSubcommands::Transition(transition::TransitionCommand {
175                key: "PROJ-1".to_string(),
176                transition: Some("Done".to_string()),
177                list: false,
178                output: OutputFormat::Table,
179            }),
180        };
181        assert!(matches!(cmd.command, JiraSubcommands::Transition(_)));
182    }
183
184    #[test]
185    fn jira_subcommands_comment_variant() {
186        let cmd = JiraCommand {
187            command: JiraSubcommands::Comment(comment::CommentCommand {
188                command: comment::CommentSubcommands::List(comment::ListCommand {
189                    key: "PROJ-1".to_string(),
190                    output: OutputFormat::Table,
191                }),
192            }),
193        };
194        assert!(matches!(cmd.command, JiraSubcommands::Comment(_)));
195    }
196
197    #[test]
198    fn jira_subcommands_delete_variant() {
199        let cmd = JiraCommand {
200            command: JiraSubcommands::Delete(delete::DeleteCommand {
201                key: "PROJ-1".to_string(),
202                force: true,
203            }),
204        };
205        assert!(matches!(cmd.command, JiraSubcommands::Delete(_)));
206    }
207
208    #[test]
209    fn jira_subcommands_dev_variant() {
210        let cmd = JiraCommand {
211            command: JiraSubcommands::Dev(dev::DevCommand {
212                key: "PROJ-1".to_string(),
213                r#type: None,
214                app: None,
215                summary: false,
216                output: OutputFormat::Table,
217            }),
218        };
219        assert!(matches!(cmd.command, JiraSubcommands::Dev(_)));
220    }
221
222    #[test]
223    fn jira_subcommands_project_variant() {
224        let cmd = JiraCommand {
225            command: JiraSubcommands::Project(project::ProjectCommand {
226                command: project::ProjectSubcommands::List(project::ListCommand {
227                    limit: 50,
228                    output: OutputFormat::Table,
229                }),
230            }),
231        };
232        assert!(matches!(cmd.command, JiraSubcommands::Project(_)));
233    }
234
235    #[test]
236    fn jira_subcommands_field_variant() {
237        let cmd = JiraCommand {
238            command: JiraSubcommands::Field(field::FieldCommand {
239                command: field::FieldSubcommands::List(field::ListCommand {
240                    search: None,
241                    output: OutputFormat::Table,
242                }),
243            }),
244        };
245        assert!(matches!(cmd.command, JiraSubcommands::Field(_)));
246    }
247
248    #[test]
249    fn jira_subcommands_board_variant() {
250        let cmd = JiraCommand {
251            command: JiraSubcommands::Board(board::BoardCommand {
252                command: board::BoardSubcommands::List(board::ListCommand {
253                    project: None,
254                    r#type: None,
255                    limit: 50,
256                    output: OutputFormat::Table,
257                }),
258            }),
259        };
260        assert!(matches!(cmd.command, JiraSubcommands::Board(_)));
261    }
262
263    #[test]
264    fn jira_subcommands_sprint_variant() {
265        let cmd = JiraCommand {
266            command: JiraSubcommands::Sprint(sprint::SprintCommand {
267                command: sprint::SprintSubcommands::List(sprint::ListCommand {
268                    board_id: 1,
269                    state: None,
270                    limit: 50,
271                    output: OutputFormat::Table,
272                }),
273            }),
274        };
275        assert!(matches!(cmd.command, JiraSubcommands::Sprint(_)));
276    }
277
278    #[test]
279    fn jira_subcommands_link_variant() {
280        let cmd = JiraCommand {
281            command: JiraSubcommands::Link(link::LinkCommand {
282                command: link::LinkSubcommands::Types(link::TypesCommand {
283                    output: OutputFormat::Table,
284                }),
285            }),
286        };
287        assert!(matches!(cmd.command, JiraSubcommands::Link(_)));
288    }
289
290    #[test]
291    fn jira_subcommands_changelog_variant() {
292        let cmd = JiraCommand {
293            command: JiraSubcommands::Changelog(changelog::ChangelogCommand {
294                keys: "PROJ-1".to_string(),
295                limit: 50,
296                output: OutputFormat::Table,
297            }),
298        };
299        assert!(matches!(cmd.command, JiraSubcommands::Changelog(_)));
300    }
301
302    #[test]
303    fn jira_subcommands_attachment_variant() {
304        let cmd = JiraCommand {
305            command: JiraSubcommands::Attachment(attachment::AttachmentCommand {
306                command: attachment::AttachmentSubcommands::Download(attachment::DownloadCommand {
307                    key: "PROJ-1".to_string(),
308                    output_dir: ".".to_string(),
309                    filter: None,
310                }),
311            }),
312        };
313        assert!(matches!(cmd.command, JiraSubcommands::Attachment(_)));
314    }
315
316    #[test]
317    fn jira_subcommands_watcher_variant() {
318        let cmd = JiraCommand {
319            command: JiraSubcommands::Watcher(watcher::WatcherCommand {
320                command: watcher::WatcherSubcommands::List(watcher::ListCommand {
321                    key: "PROJ-1".to_string(),
322                    output: OutputFormat::Table,
323                }),
324            }),
325        };
326        assert!(matches!(cmd.command, JiraSubcommands::Watcher(_)));
327    }
328
329    #[test]
330    fn jira_subcommands_worklog_variant() {
331        let cmd = JiraCommand {
332            command: JiraSubcommands::Worklog(worklog::WorklogCommand {
333                command: worklog::WorklogSubcommands::List(worklog::ListCommand {
334                    key: "PROJ-1".to_string(),
335                    limit: 50,
336                    output: OutputFormat::Table,
337                }),
338            }),
339        };
340        assert!(matches!(cmd.command, JiraSubcommands::Worklog(_)));
341    }
342}