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                    limit: 0,
192                }),
193            }),
194        };
195        assert!(matches!(cmd.command, JiraSubcommands::Comment(_)));
196    }
197
198    #[test]
199    fn jira_subcommands_delete_variant() {
200        let cmd = JiraCommand {
201            command: JiraSubcommands::Delete(delete::DeleteCommand {
202                key: "PROJ-1".to_string(),
203                force: true,
204            }),
205        };
206        assert!(matches!(cmd.command, JiraSubcommands::Delete(_)));
207    }
208
209    #[test]
210    fn jira_subcommands_dev_variant() {
211        let cmd = JiraCommand {
212            command: JiraSubcommands::Dev(dev::DevCommand {
213                key: "PROJ-1".to_string(),
214                r#type: None,
215                app: None,
216                summary: false,
217                output: OutputFormat::Table,
218            }),
219        };
220        assert!(matches!(cmd.command, JiraSubcommands::Dev(_)));
221    }
222
223    #[test]
224    fn jira_subcommands_project_variant() {
225        let cmd = JiraCommand {
226            command: JiraSubcommands::Project(project::ProjectCommand {
227                command: project::ProjectSubcommands::List(project::ListCommand {
228                    limit: 50,
229                    output: OutputFormat::Table,
230                }),
231            }),
232        };
233        assert!(matches!(cmd.command, JiraSubcommands::Project(_)));
234    }
235
236    #[test]
237    fn jira_subcommands_field_variant() {
238        let cmd = JiraCommand {
239            command: JiraSubcommands::Field(field::FieldCommand {
240                command: field::FieldSubcommands::List(field::ListCommand {
241                    search: None,
242                    output: OutputFormat::Table,
243                }),
244            }),
245        };
246        assert!(matches!(cmd.command, JiraSubcommands::Field(_)));
247    }
248
249    #[test]
250    fn jira_subcommands_board_variant() {
251        let cmd = JiraCommand {
252            command: JiraSubcommands::Board(board::BoardCommand {
253                command: board::BoardSubcommands::List(board::ListCommand {
254                    project: None,
255                    r#type: None,
256                    limit: 50,
257                    output: OutputFormat::Table,
258                }),
259            }),
260        };
261        assert!(matches!(cmd.command, JiraSubcommands::Board(_)));
262    }
263
264    #[test]
265    fn jira_subcommands_sprint_variant() {
266        let cmd = JiraCommand {
267            command: JiraSubcommands::Sprint(sprint::SprintCommand {
268                command: sprint::SprintSubcommands::List(sprint::ListCommand {
269                    board_id: 1,
270                    state: None,
271                    limit: 50,
272                    output: OutputFormat::Table,
273                }),
274            }),
275        };
276        assert!(matches!(cmd.command, JiraSubcommands::Sprint(_)));
277    }
278
279    #[test]
280    fn jira_subcommands_link_variant() {
281        let cmd = JiraCommand {
282            command: JiraSubcommands::Link(link::LinkCommand {
283                command: link::LinkSubcommands::Types(link::TypesCommand {
284                    output: OutputFormat::Table,
285                }),
286            }),
287        };
288        assert!(matches!(cmd.command, JiraSubcommands::Link(_)));
289    }
290
291    #[test]
292    fn jira_subcommands_changelog_variant() {
293        let cmd = JiraCommand {
294            command: JiraSubcommands::Changelog(changelog::ChangelogCommand {
295                keys: "PROJ-1".to_string(),
296                limit: 50,
297                output: OutputFormat::Table,
298            }),
299        };
300        assert!(matches!(cmd.command, JiraSubcommands::Changelog(_)));
301    }
302
303    #[test]
304    fn jira_subcommands_attachment_variant() {
305        let cmd = JiraCommand {
306            command: JiraSubcommands::Attachment(attachment::AttachmentCommand {
307                command: attachment::AttachmentSubcommands::Download(attachment::DownloadCommand {
308                    key: "PROJ-1".to_string(),
309                    output_dir: ".".to_string(),
310                    filter: None,
311                }),
312            }),
313        };
314        assert!(matches!(cmd.command, JiraSubcommands::Attachment(_)));
315    }
316
317    #[test]
318    fn jira_subcommands_watcher_variant() {
319        let cmd = JiraCommand {
320            command: JiraSubcommands::Watcher(watcher::WatcherCommand {
321                command: watcher::WatcherSubcommands::List(watcher::ListCommand {
322                    key: "PROJ-1".to_string(),
323                    output: OutputFormat::Table,
324                }),
325            }),
326        };
327        assert!(matches!(cmd.command, JiraSubcommands::Watcher(_)));
328    }
329
330    #[test]
331    fn jira_subcommands_worklog_variant() {
332        let cmd = JiraCommand {
333            command: JiraSubcommands::Worklog(worklog::WorklogCommand {
334                command: worklog::WorklogSubcommands::List(worklog::ListCommand {
335                    key: "PROJ-1".to_string(),
336                    limit: 50,
337                    output: OutputFormat::Table,
338                }),
339            }),
340        };
341        assert!(matches!(cmd.command, JiraSubcommands::Worklog(_)));
342    }
343}