Add output formatters

This commit is contained in:
Daan Boerlage 2025-01-21 22:03:11 +01:00
parent 476fa90200
commit f05461f1f7
Signed by: daan
GPG key ID: FCE070E1E4956606
5 changed files with 62 additions and 47 deletions

View file

@ -78,7 +78,7 @@ Find issues currently assigned to you
Usage: jirac list [OPTIONS] Usage: jirac list [OPTIONS]
Options: Options:
--json Print json rather than pretty print -o, --output <OUTPUT> Pick an output formatter [default: pretty] [possible values: pretty, json]
-h, --help Print help -h, --help Print help
``` ```
@ -93,7 +93,7 @@ Arguments:
<JQL> A JQL string <JQL> A JQL string
Options: Options:
--json Print JSON rather than pretty print -o, --output <OUTPUT> Pick an output formatter [default: pretty] [possible values: pretty, json]
-h, --help Print help -h, --help Print help
``` ```
@ -116,7 +116,7 @@ Arguments:
<ISSUE> An issue key, for example, KEY-123 <ISSUE> An issue key, for example, KEY-123
Options: Options:
--json Print JSON rather than pretty print -o, --output <OUTPUT> Pick an output formatter [default: pretty] [possible values: pretty, json]
-h, --help Print help -h, --help Print help
``` ```

View file

@ -1,4 +1,4 @@
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Parser)] #[derive(Parser)]
@ -8,12 +8,27 @@ pub struct Cli {
pub command: Commands, pub command: Commands,
} }
#[derive(ValueEnum, Debug, Copy, Clone, Eq, PartialEq)]
pub enum FormatMode {
Pretty,
Json,
}
impl std::fmt::Display for FormatMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_possible_value()
.expect("no values are skipped")
.get_name()
.fmt(f)
}
}
#[derive(Subcommand)] #[derive(Subcommand)]
pub enum Commands { pub enum Commands {
/// Create an issue /// Create an issue
Create { Create {
/// The project key in which to create the issue /// The project key in which to create the issue
#[arg(long)] #[arg(short, long)]
project: Option<String>, project: Option<String>,
/// Open the new issue in a browser /// Open the new issue in a browser
@ -26,15 +41,15 @@ pub enum Commands {
}, },
/// Find issues currently assigned to you /// Find issues currently assigned to you
List { List {
/// Print JSON rather than pretty print /// Pick an output formatter
#[arg(long)] #[arg(short, long, default_value_t = FormatMode::Pretty)]
json: bool, output: FormatMode,
}, },
/// Search for issues /// Search for issues
Search { Search {
/// Print JSON rather than pretty print /// Pick an output formatter
#[arg(long)] #[arg(short, long, default_value_t = FormatMode::Pretty)]
json: bool, output: FormatMode,
/// A JQL string /// A JQL string
#[arg(value_name = "JQL")] #[arg(value_name = "JQL")]
@ -42,9 +57,9 @@ pub enum Commands {
}, },
/// View an issue /// View an issue
View { View {
/// Print JSON rather than pretty print /// Pick an output formatter
#[arg(long)] #[arg(short, long, default_value_t = FormatMode::Pretty)]
json: bool, output: FormatMode,
/// An issue key, for example, KEY-123 /// An issue key, for example, KEY-123
#[arg(value_name = "ISSUE")] #[arg(value_name = "ISSUE")]

View file

@ -1,31 +1,31 @@
use crate::cli::FormatMode;
use crate::jira_config::JiraConfig; use crate::jira_config::JiraConfig;
use crate::types::issue::{display_issues_json, display_issues_pretty}; use crate::types::issue::{display_issues_json, display_issues_pretty};
pub async fn exec(json: bool, jql: &str) -> Result<(), Box<dyn std::error::Error>> { pub async fn exec(output: FormatMode, jql: &str) -> Result<(), Box<dyn std::error::Error>> {
let config = JiraConfig::load().map_err(|e| format!("Configuration error: {}", e))?; let config = JiraConfig::load().map_err(|e| format!("Configuration error: {}", e))?;
if !json { if output != FormatMode::Json {
println!("Searching for issues..."); println!("Searching for issues...");
} }
match crate::jql::run(&config, jql).await { let result = match crate::jql::run(&config, jql).await {
Ok(response) => { Ok(x) => x,
if json { Err(reason) => {
if response.issues.is_empty() { eprintln!("Error fetching issues: {}", reason);
println!("[]");
} else {
display_issues_json(&response.issues)?;
}
} else if response.issues.is_empty() {
println!("No results found for query.");
} else {
display_issues_pretty(&response.issues)?;
println!("Total issues: {}", response.total);
}
}
Err(e) => {
eprintln!("Error fetching issues: {}", e);
std::process::exit(1); std::process::exit(1);
} }
};
match (output, result.issues.is_empty()) {
(FormatMode::Pretty, false) => {
display_issues_pretty(&result.issues)?;
println!("Total issues: {}", result.total);
}
(FormatMode::Pretty, true) => {
println!("No results found for query.");
}
(FormatMode::Json, false) => display_issues_json(&result.issues)?,
(FormatMode::Json, true) => println!("[]"),
} }
Ok(()) Ok(())

View file

@ -1,3 +1,4 @@
use crate::cli::FormatMode;
use crate::jira_config::JiraConfig; use crate::jira_config::JiraConfig;
use crate::types::issue::JiraIssue; use crate::types::issue::JiraIssue;
use crossterm::style::{Color, Stylize}; use crossterm::style::{Color, Stylize};
@ -112,9 +113,9 @@ pub fn json_print(issues: &JiraIssue) -> Result<(), Box<dyn std::error::Error>>
Ok(()) Ok(())
} }
pub async fn exec(json: bool, issue_key: &str) -> Result<(), Box<dyn std::error::Error>> { pub async fn exec(output: FormatMode, issue_key: &str) -> Result<(), Box<dyn std::error::Error>> {
let config = JiraConfig::load().map_err(|e| format!("Configuration error: {}", e))?; let config = JiraConfig::load().map_err(|e| format!("Configuration error: {}", e))?;
if !json { if output != FormatMode::Json {
println!("Loading issue data"); println!("Loading issue data");
} }
@ -138,11 +139,10 @@ pub async fn exec(json: bool, issue_key: &str) -> Result<(), Box<dyn std::error:
let fetched_issue = fetch_issue(&config, &matched_issue.href).await?; let fetched_issue = fetch_issue(&config, &matched_issue.href).await?;
if json { match output {
json_print(&fetched_issue)?; FormatMode::Pretty => pretty_print(&fetched_issue)?,
} else { FormatMode::Json => json_print(&fetched_issue)?,
pretty_print(&fetched_issue)?; }
};
Ok(()) Ok(())
} }

View file

@ -18,12 +18,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
open, open,
markdown_file, markdown_file,
} => cmd::create::create(project, open, markdown_file).await?, } => cmd::create::create(project, open, markdown_file).await?,
Commands::List { json } => { Commands::List { output } => {
let jql = "assignee = currentUser() AND resolution = Unresolved order by updated DESC"; let jql = "assignee = currentUser() AND resolution = Unresolved order by updated DESC";
cmd::search::exec(json, jql).await? cmd::search::exec(output, jql).await?
} }
Commands::Search { json, jql } => cmd::search::exec(json, &jql).await?, Commands::Search { output, jql } => cmd::search::exec(output, &jql).await?,
Commands::View { json, issue } => cmd::view::exec(json, &issue).await?, Commands::View { output, issue } => cmd::view::exec(output, &issue).await?,
Commands::Init { url, email, token } => { Commands::Init { url, email, token } => {
JiraConfig::init(url, email, token).await?; JiraConfig::init(url, email, token).await?;
println!("Configuration initialized successfully!"); println!("Configuration initialized successfully!");