1use clap::{arg, Args, Parser, Subcommand};
2use dotenv::dotenv;
3use rujira::{agile, api, Rujira};
4use serde_json::json;
5use tracing_subscriber::{fmt, EnvFilter};
6
7#[derive(Parser, Debug)]
8#[command(name = "itcast")]
9pub struct Cli {
10 #[command(subcommand)]
11 command: Commands,
12}
13
14#[derive(Debug, Subcommand)]
15enum Commands {
16 Project(ProjectArgs),
17 Issue(IssueArgs),
18 Board(BoardArgs),
19 Sprint(SprintArgs),
20 Myself,
21}
22
23#[derive(Debug, Args)]
24struct ProjectArgs {
25 #[command(subcommand)]
26 command: ProjectCommands,
27}
28#[derive(Debug, Args)]
29struct IssueArgs {
30 #[command(subcommand)]
31 command: IssueCommands,
32}
33#[derive(Debug, Args)]
34struct BoardArgs {
35 #[command(subcommand)]
36 command: BoardCommands,
37}
38#[derive(Debug, Args)]
39struct SprintArgs {
40 #[command(subcommand)]
41 command: SprintCommands,
42}
43#[derive(Debug, Subcommand)]
44enum ProjectCommands {
45 Create {
46 key: String,
47 #[arg(short, long)]
48 name: String,
49 #[arg(short, long, default_value_t = String::from("software"))]
50 r#type: String,
51 #[arg(short, long)]
52 lead: String,
53 },
54 Delete {
55 key: String,
56 },
57 Update {
58 key: String,
59 #[arg(short, long)]
60 expand: Option<String>,
61 #[arg(short, long)]
62 update: String,
63 },
64 List {
65 #[arg(short, long)]
66 include_archive: Option<bool>,
67 #[arg(short, long)]
68 browse_archive: Option<bool>,
69 #[arg(short, long)]
70 expand: Option<String>,
71 #[arg(short, long)]
72 recent: Option<u8>,
73 },
74}
75#[derive(Debug, Subcommand)]
76enum IssueCommands {
77 Create {
78 project: String,
79 #[arg(short, long)]
80 summary: String,
81 #[arg(short, long)]
82 description: String,
83 #[arg(short, long, default_value_t = String::from("Task"))]
84 r#type: String,
85 },
86 Edit {
87 key: String,
88 #[arg(short, long)]
89 sprint: String,
90 },
91 Get {
92 key: String,
93 },
94 Delete {
95 key: String,
96 },
97}
98#[derive(Debug, Subcommand)]
99enum BoardCommands {
100 Get { key: String },
101 List {},
102}
103#[derive(Debug, Subcommand)]
104enum SprintCommands {
105 List { board: String },
106 Get { key: String },
107 Issue { key: String, task: String },
108}
109
110#[tokio::main]
111async fn main() {
112 dotenv().ok();
113 fmt()
114 .with_env_filter(EnvFilter::from_default_env())
115 .compact()
116 .init();
117 let bot = Rujira::new().from_env_handler();
118 let args = Cli::parse();
119 match args.command {
120 Commands::Myself => {
121 let me = match crate::api::myself::get(bot).apply().await {
122 Ok(rs) => rs,
123 Err(e) => {
124 eprintln!("{e}");
125 panic!();
126 }
127 };
128 println!("{me:#?}");
129 }
130 Commands::Issue(s) => match s.command {
131 IssueCommands::Create {
132 project,
133 summary,
134 description,
135 r#type,
136 } => {
137 let fields = json!({
138 "project": { "key": &project },
139 "summary": &summary,
140 "description": &description,
141 "issuetype": { "name": &r#type },
142 });
143 let issue = crate::api::issue::create(bot.clone(), fields, false)
144 .apply()
145 .await
146 .unwrap();
147 println!("{issue:#?}");
148 }
149 IssueCommands::Edit { key, sprint } => {
150 let payload = json!({
151 "sprint": { "name": sprint }
152 });
153 let issue = crate::api::issue::edit(bot.clone(), &key, None, Some(payload), None)
154 .apply()
155 .await
156 .unwrap();
157 println!("{issue:#?}");
158 }
159 IssueCommands::Get { key } => {
160 let issue = crate::api::issue::get(bot.clone(), &key, None, None, None, None)
161 .apply()
162 .await
163 .unwrap();
164 println!("{issue:#?}");
165 }
166 _ => todo!(),
167 },
168 Commands::Project(s) => match s.command {
169 ProjectCommands::Update {
170 key,
171 update,
172 expand,
173 } => {
174 let update = serde_json::from_str(&update).unwrap();
179 let project = api::project::update(bot.clone(), &key, update, expand.as_deref())
180 .apply()
181 .await
182 .unwrap();
183 println!("{project:#?}");
184 }
185 ProjectCommands::List {
186 include_archive,
187 browse_archive,
188 expand,
189 recent,
190 } => {
191 let projects = api::project::list(
192 bot.clone(),
193 include_archive,
194 browse_archive,
195 expand.as_deref(),
197 recent,
198 )
199 .apply()
200 .await
201 .unwrap();
202 println!("{projects:#?}");
203 }
204 ProjectCommands::Create {
205 key,
206 name,
207 r#type,
208 lead,
209 } => {
210 api::project::create(bot.clone(), &key, &name, &r#type, &lead)
211 .apply()
212 .await
213 .unwrap();
214 }
215 ProjectCommands::Delete { key } => {
216 api::project::delete(bot.clone(), &key)
217 .apply()
218 .await
219 .unwrap();
220 }
221 },
222 Commands::Board(s) => match s.command {
223 BoardCommands::List {} => {
224 let boards = agile::board::list(bot.clone(), None, None, None, None, None)
225 .apply()
226 .await
227 .unwrap();
228 println!("{boards:#?}");
229 }
230 BoardCommands::Get { key } => {
231 let board = agile::board::get(bot.clone(), &key).apply().await.unwrap();
232 println!("{board:#?}");
233 }
234 },
235 Commands::Sprint(s) => match s.command {
236 SprintCommands::List { board } => {
237 let sprints = agile::sprint::list(bot.clone(), &board, None, None, None)
238 .apply()
239 .await
240 .unwrap();
241 println!("{sprints:#?}");
242 }
243 SprintCommands::Get { key } => {
244 let sprint = agile::sprint::get(bot.clone(), &key).apply().await.unwrap();
245 println!("{sprint:#?}");
246 }
247 SprintCommands::Issue { key, task } => {
248 let payload = json!([task]);
249 let sprint = agile::sprint::issue(bot.clone(), &key, payload)
250 .apply()
251 .await
252 .unwrap();
253 println!("{sprint:#?}");
254 }
255 },
256 }
257}