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