omni_dev/cli/
resources.rs1use anyhow::{anyhow, Result};
5use clap::{Parser, Subcommand};
6
7use crate::resources;
8
9#[derive(Parser)]
11pub struct ResourcesCommand {
12 #[command(subcommand)]
14 pub command: ResourcesSubcommands,
15}
16
17#[derive(Subcommand)]
19pub enum ResourcesSubcommands {
20 Show(ShowCommand),
22 List(ListCommand),
24}
25
26#[derive(Parser)]
28pub struct ShowCommand {
29 pub id: String,
32}
33
34#[derive(Parser)]
36pub struct ListCommand {}
37
38impl ResourcesCommand {
39 pub fn execute(self) -> Result<()> {
41 match self.command {
42 ResourcesSubcommands::Show(c) => c.execute(),
43 ResourcesSubcommands::List(c) => c.execute(),
44 }
45 }
46}
47
48impl ShowCommand {
49 pub fn execute(self) -> Result<()> {
51 let canonical = normalize_id(&self.id);
52 match resources::get(canonical) {
53 Some(r) => {
54 print!("{}", r.content);
58 Ok(())
59 }
60 None => Err(anyhow!(
61 "unknown resource `{id}`; known: {known}",
62 id = self.id,
63 known = resources::known_ids_csv(),
64 )),
65 }
66 }
67}
68
69impl ListCommand {
70 pub fn execute(self) -> Result<()> {
72 for id in resources::ids() {
73 println!("{id}");
74 }
75 Ok(())
76 }
77}
78
79fn normalize_id(input: &str) -> &str {
82 input.strip_prefix("omni-dev://").unwrap_or(input)
83}
84
85#[cfg(test)]
86#[allow(clippy::unwrap_used, clippy::expect_used)]
87mod tests {
88 use super::*;
89 use crate::cli::{Cli, Commands};
90
91 #[test]
92 fn normalize_id_strips_scheme() {
93 assert_eq!(normalize_id("omni-dev://specs/jfm"), "specs/jfm");
94 }
95
96 #[test]
97 fn normalize_id_passes_through_plain() {
98 assert_eq!(normalize_id("specs/jfm"), "specs/jfm");
99 }
100
101 #[test]
102 fn normalize_id_strips_only_one_scheme() {
103 assert_eq!(
105 normalize_id("omni-dev://omni-dev://specs/jfm"),
106 "omni-dev://specs/jfm"
107 );
108 }
109
110 #[test]
111 fn normalize_id_does_not_strip_other_schemes() {
112 assert_eq!(normalize_id("jira://issue/X-1"), "jira://issue/X-1");
113 assert_eq!(
114 normalize_id("git://repo/commits/HEAD"),
115 "git://repo/commits/HEAD"
116 );
117 }
118
119 #[test]
120 fn show_unknown_id_errors_with_known_list() {
121 let cmd = ShowCommand {
122 id: "specs/does-not-exist".into(),
123 };
124 let err = cmd.execute().expect_err("unknown id must error");
125 let chain = format!("{err:#}");
126 assert!(
127 chain.contains("unknown resource"),
128 "missing prefix: {chain}"
129 );
130 assert!(chain.contains("specs/jfm"), "known list missing: {chain}");
131 }
132
133 #[test]
134 fn clap_parses_show_command() {
135 let cli = Cli::try_parse_from(["omni-dev", "resources", "show", "specs/jfm"]).unwrap();
136 match cli.command {
137 Commands::Resources(ResourcesCommand {
138 command: ResourcesSubcommands::Show(c),
139 }) => assert_eq!(c.id, "specs/jfm"),
140 _ => panic!("expected resources show"),
141 }
142 }
143
144 #[test]
145 fn clap_parses_list_command() {
146 let cli = Cli::try_parse_from(["omni-dev", "resources", "list"]).unwrap();
147 assert!(matches!(
148 cli.command,
149 Commands::Resources(ResourcesCommand {
150 command: ResourcesSubcommands::List(_)
151 })
152 ));
153 }
154
155 #[test]
156 fn clap_parses_show_with_omni_dev_uri() {
157 let cli =
158 Cli::try_parse_from(["omni-dev", "resources", "show", "omni-dev://specs/jfm"]).unwrap();
159 match cli.command {
160 Commands::Resources(ResourcesCommand {
161 command: ResourcesSubcommands::Show(c),
162 }) => assert_eq!(c.id, "omni-dev://specs/jfm"),
163 _ => panic!("expected resources show"),
164 }
165 }
166}